Skip to content

Commit e6df7d2

Browse files
committed
Merge branch '3.2-compat'
Conflicts: app/controllers/articles_controller.rb app/controllers/categories_controller.rb app/models/kb_article.rb app/views/articles/show.html.erb config/routes.rb init.rb
2 parents 424c023 + f8b82cb commit e6df7d2

40 files changed

+609
-72
lines changed

AUTHORS

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ Contributors:
2121
* Daniel Felix
2222
* Messinger
2323
* xarlie
24+
* Rob Spearman
25+
* Eduard Kuleshov
26+
* Axel Kämpfe
2427

2528
Documentation:
2629
* Alan Bowman
@@ -56,7 +59,7 @@ French:
5659
* myorama
5760
* Xavier Calland
5861
* LabriePierre
59-
62+
6063
German:
6164
* eschsa
6265
* cforce
@@ -96,7 +99,7 @@ Spanish:
9699
* Carlos Solano
97100
* dtamajon
98101

99-
Swedish:
102+
Swedish:
100103
* Peter Brauner
101104

102105
Turkish:

app/controllers/articles_controller.rb

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ class ArticlesController < ApplicationController
99
include WatchersHelper
1010

1111
before_filter :find_project_by_project_id, :authorize
12-
before_filter :get_article, :except => [:index, :new, :create, :preview, :comment, :tagged, :rate]
12+
before_filter :get_article, :except => [:index, :new, :create, :preview, :comment, :tagged, :rate, :authored]
1313

1414
rescue_from ActionView::MissingTemplate, :with => :force_404
1515
rescue_from ActiveRecord::RecordNotFound, :with => :force_404
@@ -27,10 +27,25 @@ def index
2727

2828
@articles_newest = @project.articles.order("created_at DESC").first(summary_limit)
2929
@articles_latest = @project.articles.order("updated_at DESC").first(summary_limit)
30-
@articles_popular = @project.articles.includes(:viewings).limit(summary_limit).sort_by(&:view_count).reverse
31-
@articles_toprated = @project.articles.includes(:ratings).limit(summary_limit).sort_by(&:rated_count).reverse
30+
@articles_popular = @project.articles.includes(:viewings).sort_by(&:view_count).reverse.first(summary_limit)
31+
@articles_toprated = @project.articles.includes(:ratings).sort_by { |a| [a.rating_average, a.rated_count] }.reverse.first(summary_limit)
3232

33-
@tags = @project.articles.tag_counts
33+
@tags = @project.articles.tag_counts.sort { |a, b| a.name.downcase <=> b.name.downcase }
34+
end
35+
36+
def authored
37+
38+
@author_id = params[:author_id]
39+
@articles = @project.articles.where(:author_id => @author_id).order("#{KbArticle.table_name}.#{sort_column} #{sort_direction}")
40+
41+
if params[:tag]
42+
@tag = params[:tag]
43+
@articles = @articles.tagged_with(@tag)
44+
end
45+
46+
@categories = @project.categories.where(:parent_id => nil)
47+
48+
@tags = @articles.tag_counts.sort { |a, b| a.name.downcase <=> b.name.downcase }
3449
end
3550

3651
def new
@@ -71,7 +86,7 @@ def create
7186

7287
def show
7388
@article.view request.remote_ip, User.current
74-
@attachments = @article.attachments.sort_by(&:created_on)
89+
@attachments = @article.attachments.all.sort_by(&:created_on)
7590
@comments = @article.comments
7691
@versions = @article.versions.select("id, author_id, version_comments, updated_at, version").order('version DESC')
7792

@@ -83,16 +98,28 @@ def show
8398
end
8499

85100
def edit
86-
@categories=@project.categories
101+
if not @article.editable_by?(User.current)
102+
render_403
103+
return false
104+
end
105+
106+
@categories=@project.categories.all
107+
87108
# don't keep previous comment
88109
@article.version_comments = nil
89110
@article.version = params[:version]
90111
end
91112

92113
def update
114+
115+
if not @article.editable_by?(User.current)
116+
render_403
117+
return false
118+
end
119+
93120
@article.updater_id = User.current.id
94121
params[:article][:category_id] = params[:category_id]
95-
@categories = @project.categories
122+
@categories = @project.categories.all
96123
# don't keep previous comment
97124
@article.version_comments = nil
98125
@article.version_comments = params[:article][:version_comments]
@@ -129,13 +156,24 @@ def destroy_comment
129156
end
130157

131158
def destroy
159+
160+
if not @article.editable_by?(User.current)
161+
render_403
162+
return false
163+
end
164+
132165
KbMailer.article_destroy(@article).deliver
133166
@article.destroy
134167
flash[:notice] = l(:label_article_removed)
135168
redirect_to({ :controller => 'articles', :action => 'index', :project_id => @project})
136169
end
137170

138171
def add_attachment
172+
if not @article.editable_by?(User.current)
173+
render_403
174+
return false
175+
end
176+
139177
attachments = attach(@article, params[:attachments])
140178
redirect_to({ :action => 'show', :id => @article.id, :project_id => @project })
141179
end

app/controllers/categories_controller.rb

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,23 @@ class CategoriesController < ApplicationController
1414
rescue_from ActiveRecord::RecordNotFound, :with => :force_404
1515

1616
def show
17+
1718
@articles = @category.articles.order("#{sort_column} #{sort_direction}")
19+
20+
if params[:tag]
21+
@tag = params[:tag]
22+
@articles = @articles.tagged_with(@tag)
23+
end
24+
1825
@categories = @project.categories.where(:parent_id => nil)
1926

27+
@tags = @articles.tag_counts.sort { |a, b| a.name.downcase <=> b.name.downcase }
28+
2029
respond_to do |format|
2130
format.html { render :template => 'categories/show', :layout => !request.xhr? }
2231
format.atom { render_feed(@articles, :title => "#{l(:knowledgebase_title)}: #{l(:label_category)}: #{@category.title}") }
2332
end
33+
2434
end
2535

2636
def new
@@ -53,15 +63,23 @@ def edit
5363
end
5464

5565
def destroy
56-
@categories=@project.categories
57-
if @category.articles.size == 0
58-
@category.destroy
59-
flash[:notice] = l(:label_category_deleted)
60-
redirect_to({ :controller => :articles, :action => 'index', :project_id => @project})
61-
else
66+
@categories = @project.categories.all
67+
68+
# Do not allow deletion of categories with existing subcategories
69+
@subcategories = @project.categories.where(:parent_id => @category.id)
70+
71+
if @subcategories.size != 0
72+
@articles = @category.articles.all
73+
flash[:error] = l(:label_category_has_subcategory_cannot_delete)
74+
render(:action => 'show')
75+
elsif @category.articles.size != 0
6276
@articles = @category.articles.all
6377
flash[:error] = l(:label_category_not_empty_cannot_delete)
6478
render(:action => 'show')
79+
else
80+
@category.destroy
81+
flash[:notice] = l(:label_category_deleted)
82+
redirect_to({ :controller => :articles, :action => 'index', :project_id => @project})
6583
end
6684
end
6785

app/helpers/knowledgebase_helper.rb

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
module KnowledgebaseHelper
22
include Redmine::Export::PDF
33
include KnowledgebaseSettingsHelper
4+
include ActionView::Helpers::NumberHelper
45

56
def format_article_summary(article, format, options = {})
67
output = case format
78
when "normal"
8-
truncate article.summary, :length => options[:truncate]
9+
""
10+
#truncate article.summary, :length => options[:truncate]
911
when "newest"
1012
l(:label_summary_newest_articles,
1113
:ago => time_ago_in_words(article.created_at),
@@ -19,15 +21,24 @@ def format_article_summary(article, format, options = {})
1921
:count => article.view_count,
2022
:created => article.created_at.to_date.to_formatted_s(:rfc822))
2123
when "toprated"
22-
l(:label_summary_toprated_articles,
23-
:rating_avg => article.rating_average.to_s,
24-
:rating_max => "5",
25-
:count => article.rated_count)
24+
if article.rating_average.to_i == 0
25+
l(:label_unrated_article)
26+
else
27+
l(:label_summary_toprated_articles,
28+
:rating_avg => article.rating_average.to_s,
29+
:rating_max => "5",
30+
:count => article.rated_count)
31+
end
2632
else
2733
nil
2834
end
2935

30-
content_tag(:div, raw(output), :class => "summary")
36+
sum = ""
37+
unless redmine_knowledgebase_settings_value(:disable_article_summaries)
38+
sum = "<p>" + (truncate article.summary, :length => options[:truncate]) + "</p>"
39+
end
40+
41+
content_tag(:div, raw(sum + output), :class => "summary")
3142
end
3243

3344
def sort_categories?
@@ -54,7 +65,7 @@ def sortable(column, title = nil)
5465
title ||= column.titleize
5566
css_class = column == sort_column ? "current #{sort_direction}" : nil
5667
direction = column == sort_column && sort_direction == "asc" ? "desc" : "asc"
57-
link_to title, {:id => params[:id], :sort => column, :direction => direction }, {:class => css_class}
68+
link_to title, {:id => params[:id], :tag => params[:tag], :author_id => params[:author_id], :sort => column, :direction => direction }, {:class => css_class}
5869
end
5970

6071
def article_to_pdf(article, project)
@@ -94,13 +105,29 @@ def write_article(pdf, article)
94105
end
95106

96107
def article_tabs
97-
tabs = [{:name => 'content', :action => :content, :partial => 'articles/sections/content', :label => :label_content},
98-
{:name => 'comments', :action => :comments, :partial => 'articles/sections/comments', :label => :label_comment_plural},
99-
{:name => 'attachments', :action => :attachments, :partial => 'articles/sections/attachments', :label => :label_attachment_plural},
100-
{:name => 'history', :action => :history, :partial => 'articles/sections/history', :label => :label_history}
101-
]
108+
109+
content = {:name => 'content', :action => :content, :partial => 'articles/sections/content', :label => :label_content}
110+
comments = {:name => 'comments', :action => :comments, :partial => 'articles/sections/comments', :label => :label_comment_plural}
111+
attachments = {:name => 'attachments', :action => :attachments, :partial => 'articles/sections/attachments', :label => :label_attachment_plural}
112+
history = {:name => 'history', :action => :history, :partial => 'articles/sections/history', :label => :label_history}
113+
114+
unless redmine_knowledgebase_settings_value(:show_attachments_first)
115+
116+
tabs = [content, comments, attachments, history]
117+
else
118+
119+
tabs = [attachments, content, comments, history]
120+
end
121+
122+
# Do not show History if no permission
123+
unless User.current.allowed_to?(:view_article_history, @project)
124+
tabs.pop(1)
125+
end
126+
102127
# TODO permissions?
103128
# tabs.select {|tab| User.current.allowed_to?(tab[:action], @project)}
129+
130+
return tabs
104131
end
105132

106133
def create_preview_link

app/models/kb_article.rb

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,39 @@ class KbArticle < ActiveRecord::Base
2525
acts_as_versioned :if_changed => [:title, :content, :summary]
2626
self.non_versioned_columns << 'comments_count'
2727

28-
acts_as_searchable :columns => [ "#{table_name}.title", "#{table_name}.content"],
29-
:scope => preload(:project),
30-
:date_column => "created_at"
31-
3228
acts_as_event :title => Proc.new {|o| status = (o.new_status ? "(#{l(:label_new_article)})" : nil ); "#{status} #{l(:label_title_articles)} ##{o.id} - #{o.title}" },
3329
:description => :content,
3430
:datetime => :updated_at,
3531
:type => Proc.new { |o| 'article-' + (o.new_status ? 'add' : 'edit') },
3632
:url => Proc.new { |o| {:controller => 'articles', :action => 'show', :id => o.id, :project_id => o.project} }
3733

38-
acts_as_activity_provider :scope => preload(:project),
39-
:author_key => :author_id,
40-
:type => 'kb_articles',
41-
:timestamp => :updated_at
34+
# Redmine 3.1.X
35+
if ActiveRecord::VERSION::MAJOR >= 4
36+
acts_as_activity_provider :scope => joins(:project),
37+
:permission => :view_kb_articles,
38+
:author_key => :author_id,
39+
:type => 'kb_articles',
40+
:timestamp => :updated_at
41+
42+
acts_as_searchable :columns => [ "#{table_name}.title", "#{table_name}.summary", "#{table_name}.content"],
43+
:preload => [ :project ],
44+
:date_column => "#{table_name}.created_at"
45+
else
46+
acts_as_activity_provider :find_options => {:include => :project},
47+
:author_key => :author_id,
48+
:type => 'kb_articles',
49+
:timestamp => :updated_at
50+
51+
acts_as_searchable :columns => [ "#{table_name}.title", "#{table_name}.summary", "#{table_name}.content"],
52+
:include => [ :project ],
53+
:order_column => "#{table_name}.id",
54+
:date_column => "#{table_name}.created_at"
55+
end
4256

43-
has_many :comments, -> { order 'created_on DESC' }, :as => :commented, :dependent => :delete_all
57+
has_many :comments, -> { order 'created_on DESC' }, :as => :commented, :dependent => :destroy
4458

45-
scope :visible, ->(*args) { joins(:project).where(Project.allowed_to_condition(args.shift || User.current, :view_kb_articles, *args)) }
59+
scope :visible, lambda {|*args| { :include => :project,
60+
:conditions => Project.allowed_to_condition(args.shift || User.current, :view_kb_articles, *args) } }
4661

4762
def recipients
4863
notified = []
@@ -54,8 +69,10 @@ def recipients
5469
notified.collect(&:mail)
5570
end
5671

57-
def editable_by?(user)
58-
user.allowed_to?(:edit_articles, self.project)
72+
def editable_by?(user = User.current)
73+
return user.allowed_to?(:edit_articles, self.project) ||
74+
user.allowed_to?(:manage_articles, self.project) ||
75+
(user.allowed_to?(:manage_own_articles, self.project) && self.author_id == user.id)
5976
end
6077

6178
def attachments_deletable?(user = User.current)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
3+
<p class="breadcrumb list-breadcrumb">
4+
<% article.category.ancestors.each do |ancestor| %>
5+
&nbsp;&raquo;&nbsp;
6+
<%= link_to ancestor.title, { :controller => 'categories', :action => 'show', :id => ancestor.id, :project_id => @project} %>
7+
<% end %>
8+
&nbsp;&raquo;&nbsp;
9+
<%= link_to article.category.title, { :controller => 'categories', :action => 'show', :id => article.category.id, :project_id => @project} %>
10+
</p>
11+

app/views/articles/_form.html.erb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,17 @@
1414
<p><%= f.text_field :tag_list, :size => 80, :value => "#{@article.tag_list.join(",")}" %></p>
1515
<p><%= f.text_field :version_comments, :size => 120, :label => l(:field_version_comments) %></p>
1616
</div>
17+
18+
<% if @article.attachments.exists? %>
19+
<div class="box">
20+
<p><label><%= l(:label_attachment_plural) %></label>
21+
<%= render :partial => "articles/sections/attachments" %>
22+
</p>
23+
</div>
24+
<% end %>
25+
1726
<div class="box">
18-
<p><label><%=l(:label_attachment_plural)%></label><%= render :partial => 'attachments/form' %></p>
27+
<p><label><%=l(:label_attachment_add)%></label><%= render :partial => 'attachments/form' %></p>
1928
</div>
2029

2130
<%= wikitoolbar_for 'article_content' %>

0 commit comments

Comments
 (0)