Commit 483f5d55ae046c308ea951ddb50d9c77715b759d
Exists in
master
and in
29 other branches
Merge remote branch 'diguliu/features' into work-assignment
Conflicts: test/functional/cms_controller_test.rb test/unit/article_test.rb
Showing
30 changed files
with
523 additions
and
64 deletions
Show diff stats
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -16,7 +16,13 @@ class CmsController < MyProfileController |
16 | 16 | |
17 | 17 | before_filter :login_required, :except => [:suggest_an_article] |
18 | 18 | |
19 | - protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish] do |c, user, profile| | |
19 | + protect_if :only => :upload_files do |c, user, profile| | |
20 | + article_id = c.params[:parent_id] | |
21 | + (article_id && profile.articles.find(article_id).allow_create?(user)) || | |
22 | + (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))) | |
23 | + end | |
24 | + | |
25 | + protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :upload_files] do |c, user, profile| | |
20 | 26 | user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)) |
21 | 27 | end |
22 | 28 | |
... | ... | @@ -92,7 +98,7 @@ class CmsController < MyProfileController |
92 | 98 | @article_types = [] |
93 | 99 | available_article_types.each do |type| |
94 | 100 | @article_types.push({ |
95 | - :name => type.name, | |
101 | + :class => type, | |
96 | 102 | :short_description => type.short_description, |
97 | 103 | :description => type.description |
98 | 104 | }) |
... | ... | @@ -154,7 +160,7 @@ class CmsController < MyProfileController |
154 | 160 | end |
155 | 161 | if request.post? && params[:uploaded_files] |
156 | 162 | params[:uploaded_files].each do |file| |
157 | - @uploaded_files << UploadedFile.create(:uploaded_data => file, :profile => profile, :parent => @parent) unless file == '' | |
163 | + @uploaded_files << UploadedFile.create(:uploaded_data => file, :profile => profile, :parent => @parent, :last_changed_by => user) unless file == '' | |
158 | 164 | end |
159 | 165 | @errors = @uploaded_files.select { |f| f.errors.any? } |
160 | 166 | if @errors.any? | ... | ... |
app/helpers/content_viewer_helper.rb
... | ... | @@ -26,7 +26,7 @@ module ContentViewerHelper |
26 | 26 | end |
27 | 27 | title << content_tag('span', |
28 | 28 | content_tag('span', show_date(article.published_at), :class => 'date') + |
29 | - content_tag('span', [_(", by %s") % link_to(article.author_name, article.author.url)], :class => 'author') + | |
29 | + content_tag('span', [_(", by %s") % link_to(article.author_name, article.author_url)], :class => 'author') + | |
30 | 30 | content_tag('span', comments, :class => 'comments'), |
31 | 31 | :class => 'created-at' |
32 | 32 | ) | ... | ... |
app/helpers/folder_helper.rb
... | ... | @@ -52,8 +52,8 @@ module FolderHelper |
52 | 52 | end |
53 | 53 | end |
54 | 54 | |
55 | - def icon_for_new_article(type) | |
56 | - "icon-new icon-new%s" % type.constantize.icon_name | |
55 | + def icon_for_new_article(klass) | |
56 | + "icon-new icon-new%s" % klass.icon_name | |
57 | 57 | end |
58 | 58 | |
59 | 59 | def custom_options_for_article(article) | ... | ... |
app/helpers/forms_helper.rb
... | ... | @@ -142,6 +142,38 @@ module FormsHelper |
142 | 142 | content_tag('table',rows.join("\n")) |
143 | 143 | end |
144 | 144 | |
145 | + def select_folder(label_text, field_id, collection, default_value=nil, html_options = {}, js_options = {}) | |
146 | + root = profile ? profile.identifier : _("root") | |
147 | + labelled_form_field( | |
148 | + label_text, | |
149 | + select_tag( | |
150 | + field_id, | |
151 | + options_for_select( | |
152 | + [[root, '']] + | |
153 | + collection.collect {|f| [ root + '/' + f.full_name, f.id ] }, | |
154 | + default_value | |
155 | + ), | |
156 | + html_options.merge(js_options) | |
157 | + ) | |
158 | + ) | |
159 | + end | |
160 | + | |
161 | + def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {}) | |
162 | + result = labelled_form_field( | |
163 | + label_text, | |
164 | + select_tag( | |
165 | + field_id, | |
166 | + options_for_select( | |
167 | + [[profile.identifier, '']] + | |
168 | + profile.folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] }, | |
169 | + default_value | |
170 | + ), | |
171 | + html_options.merge(js_options) | |
172 | + ) | |
173 | + ) | |
174 | + return result | |
175 | + end | |
176 | + | |
145 | 177 | def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) |
146 | 178 | datepicker_options[:disabled] ||= false |
147 | 179 | datepicker_options[:alt_field] ||= '' | ... | ... |
app/models/approve_article.rb
... | ... | @@ -48,7 +48,7 @@ class ApproveArticle < Task |
48 | 48 | end |
49 | 49 | |
50 | 50 | def perform |
51 | - article.copy!(:name => name, :abstract => abstract, :body => body, :profile => target, :reference_article => article, :parent => article_parent, :highlighted => highlighted, :source => article.source) | |
51 | + article.copy!(:name => name, :abstract => abstract, :body => body, :profile => target, :reference_article => article, :parent => article_parent, :highlighted => highlighted, :source => article.source, :last_changed_by_id => article.author) | |
52 | 52 | end |
53 | 53 | |
54 | 54 | def title | ... | ... |
app/models/article.rb
... | ... | @@ -13,6 +13,12 @@ class Article < ActiveRecord::Base |
13 | 13 | # xss_terminate plugin can't sanitize array fields |
14 | 14 | before_save :sanitize_tag_list |
15 | 15 | |
16 | + before_create do |article| | |
17 | + if article.last_changed_by_id | |
18 | + article.author_name = Person.find(article.last_changed_by_id).name | |
19 | + end | |
20 | + end | |
21 | + | |
16 | 22 | belongs_to :profile |
17 | 23 | validates_presence_of :profile_id, :name |
18 | 24 | validates_presence_of :slug, :path, :if => lambda { |article| !article.name.blank? } |
... | ... | @@ -289,7 +295,7 @@ class Article < ActiveRecord::Base |
289 | 295 | if last_comment |
290 | 296 | {:date => last_comment.created_at, :author_name => last_comment.author_name, :author_url => last_comment.author_url} |
291 | 297 | else |
292 | - {:date => updated_at, :author_name => author.name, :author_url => author.url} | |
298 | + {:date => updated_at, :author_name => author_name, :author_url => author_url} | |
293 | 299 | end |
294 | 300 | end |
295 | 301 | |
... | ... | @@ -441,7 +447,7 @@ class Article < ActiveRecord::Base |
441 | 447 | end |
442 | 448 | |
443 | 449 | def allow_post_content?(user = nil) |
444 | - user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == self.creator)) | |
450 | + user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == author)) | |
445 | 451 | end |
446 | 452 | |
447 | 453 | def allow_publish_content?(user = nil) |
... | ... | @@ -496,7 +502,6 @@ class Article < ActiveRecord::Base |
496 | 502 | :slug, |
497 | 503 | :updated_at, |
498 | 504 | :created_at, |
499 | - :last_changed_by_id, | |
500 | 505 | :version, |
501 | 506 | :lock_version, |
502 | 507 | :type, |
... | ... | @@ -539,15 +544,20 @@ class Article < ActiveRecord::Base |
539 | 544 | end |
540 | 545 | |
541 | 546 | def author |
542 | - if reference_article | |
543 | - reference_article.author | |
547 | + if versions.empty? | |
548 | + last_changed_by | |
544 | 549 | else |
545 | - last_changed_by || profile | |
550 | + author_id = versions.first.last_changed_by_id | |
551 | + Person.exists?(author_id) ? Person.find(author_id) : nil | |
546 | 552 | end |
547 | 553 | end |
548 | 554 | |
549 | 555 | def author_name |
550 | - setting[:author_name].blank? ? author.name : setting[:author_name] | |
556 | + author ? author.name : (setting[:author_name] || _('Unknown')) | |
557 | + end | |
558 | + | |
559 | + def author_url | |
560 | + author ? author.url : nil | |
551 | 561 | end |
552 | 562 | |
553 | 563 | alias :active_record_cache_key :cache_key |
... | ... | @@ -572,11 +582,6 @@ class Article < ActiveRecord::Base |
572 | 582 | truncate sanitize_html(self.lead), :length => 170, :omission => '...' |
573 | 583 | end |
574 | 584 | |
575 | - def creator | |
576 | - creator_id = versions[0][:last_changed_by_id] | |
577 | - creator_id && Profile.find(creator_id) | |
578 | - end | |
579 | - | |
580 | 585 | def notifiable? |
581 | 586 | false |
582 | 587 | end | ... | ... |
app/models/event.rb
... | ... | @@ -38,7 +38,7 @@ class Event < Article |
38 | 38 | filter_iframes :body, :link, :address, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe } |
39 | 39 | |
40 | 40 | def self.description |
41 | - _('A calendar event') | |
41 | + _('A calendar event.') | |
42 | 42 | end |
43 | 43 | |
44 | 44 | def self.short_description | ... | ... |
app/models/raw_html_article.rb
... | ... | @@ -5,11 +5,11 @@ class RawHTMLArticle < TextArticle |
5 | 5 | end |
6 | 6 | |
7 | 7 | def self.short_description |
8 | - _('Raw HTML text article.') | |
8 | + _('Raw HTML text article') | |
9 | 9 | end |
10 | 10 | |
11 | 11 | def self.description |
12 | - _('Allows HTML without filter (only for admins)') | |
12 | + _('Allows HTML without filter (only for admins).') | |
13 | 13 | end |
14 | 14 | |
15 | 15 | xss_terminate :only => [ ] | ... | ... |
app/models/tiny_mce_article.rb
app/views/cms/select_article_type.rhtml
... | ... | @@ -2,9 +2,9 @@ |
2 | 2 | |
3 | 3 | <ul id="article_types"> |
4 | 4 | <% for type in @article_types %> |
5 | - <% action = type[:name] == 'UploadedFile' ? {:action => 'upload_files'} : {:action => 'new', :type => type[:name]} %> | |
5 | + <% action = type[:class].name == 'UploadedFile' ? {:action => 'upload_files'} : {:action => 'new', :type => type[:class].name} %> | |
6 | 6 | <% content_tag('a', :href => url_for(action.merge(:parent_id => @parent_id, :back_to => @back_to))) do %> |
7 | - <li class="<%= icon_for_new_article(type[:name]) %>" onmouseover="javascript: jQuery(this).addClass('mouseover')" onmouseout="jQuery(this).removeClass('mouseover')"> | |
7 | + <li class="<%= icon_for_new_article(type[:class]) %>" onmouseover="javascript: jQuery(this).addClass('mouseover')" onmouseout="jQuery(this).removeClass('mouseover')"> | |
8 | 8 | <strong><%= type[:short_description] %></strong> |
9 | 9 | <div class='description'><%= type[:description] %></div> |
10 | 10 | </li> | ... | ... |
app/views/content_viewer/_article_toolbar.rhtml
... | ... | @@ -34,11 +34,11 @@ |
34 | 34 | <%= expirable_button @page, :locale, content, url %> |
35 | 35 | <% end %> |
36 | 36 | |
37 | - <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) %> | |
37 | + <%= colorbox_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) if !remove_content_button(:new) %> | |
38 | 38 | <% end %> |
39 | 39 | |
40 | 40 | <% if @page.accept_uploads? && @page.allow_create?(user) %> |
41 | - <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) %> | |
41 | + <%= button('upload-file', _('Upload files'), profile.admin_url.merge(:controller => 'cms', :action => 'upload_files', :parent_id => (@page.folder? ? @page : @page.parent))) if !remove_content_button(:upload)%> | |
42 | 42 | <% end %> |
43 | 43 | |
44 | 44 | <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest) %> | ... | ... |
db/schema.rb
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | # |
10 | 10 | # It's strongly recommended to check this file into your version control system. |
11 | 11 | |
12 | -ActiveRecord::Schema.define(:version => 20121008185303) do | |
12 | +ActiveRecord::Schema.define(:version => 20121022190819) do | |
13 | 13 | |
14 | 14 | create_table "abuse_reports", :force => true do |t| |
15 | 15 | t.integer "reporter_id" | ... | ... |
lib/noosfero/plugin.rb
... | ... | @@ -130,7 +130,7 @@ class Noosfero::Plugin |
130 | 130 | end |
131 | 131 | |
132 | 132 | # -> Adds plugin-specific content types to CMS |
133 | - # returns = { content type class } | |
133 | + # returns = [ContentClass1, ContentClass2, ...] | |
134 | 134 | def content_types |
135 | 135 | nil |
136 | 136 | end |
... | ... | @@ -384,7 +384,9 @@ class Noosfero::Plugin |
384 | 384 | private |
385 | 385 | |
386 | 386 | def content_actions |
387 | - %w[edit delete spread locale suggest home] | |
387 | + #FIXME 'new' and 'upload' only works for content_remove. It should work for | |
388 | + #content_expire too. | |
389 | + %w[edit delete spread locale suggest home new upload] | |
388 | 390 | end |
389 | 391 | |
390 | 392 | end | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +require_dependency 'article' | |
2 | +require_dependency 'uploaded_file' | |
3 | + | |
4 | +class UploadedFile < Article | |
5 | + after_save do |uploaded_file| | |
6 | + if uploaded_file.parent.kind_of?(WorkAssignmentPlugin::WorkAssignment) | |
7 | + author_folder = uploaded_file.parent.find_or_create_author_folder(uploaded_file.author) | |
8 | + uploaded_file.name = WorkAssignmentPlugin::WorkAssignment.versioned_name(uploaded_file, author_folder) | |
9 | + uploaded_file.parent = author_folder | |
10 | + logger.info("\n\n==> #{uploaded_file.name}\n\n") | |
11 | + uploaded_file.save! | |
12 | + end | |
13 | + end | |
14 | +end | ... | ... |
... | ... | @@ -0,0 +1,54 @@ |
1 | +require_dependency 'ext/uploaded_file' | |
2 | + | |
3 | +class WorkAssignmentPlugin < Noosfero::Plugin | |
4 | + | |
5 | + def self.plugin_name | |
6 | + "Work Assignment" | |
7 | + end | |
8 | + | |
9 | + def self.plugin_description | |
10 | + _("New kind of content for organizations.") | |
11 | + end | |
12 | + | |
13 | + def self.can_download_submission?(user, submission) | |
14 | + work_assignment = submission.parent.parent | |
15 | + work_assignment.publish_submissions || (user && (submission.author == user || user.has_permission?('view_private_content', work_assignment.profile))) | |
16 | + end | |
17 | + | |
18 | + def self.is_submission?(content) | |
19 | + content && content.parent && content.parent.parent && content.parent.parent.kind_of?(WorkAssignmentPlugin::WorkAssignment) | |
20 | + end | |
21 | + | |
22 | + def content_types | |
23 | + [WorkAssignmentPlugin::WorkAssignment] if context.profile.organization? | |
24 | + end | |
25 | + | |
26 | + def stylesheet? | |
27 | + true | |
28 | + end | |
29 | + | |
30 | + def content_remove_new(content) | |
31 | + content.kind_of?(WorkAssignmentPlugin::WorkAssignment) | |
32 | + end | |
33 | + | |
34 | + def content_remove_upload(content) | |
35 | + !content.profile.members.include?(context.send(:user)) | |
36 | + end | |
37 | + | |
38 | + def content_viewer_controller_filters | |
39 | + block = lambda do | |
40 | + path = params[:page].join('/') | |
41 | + content = profile.articles.find_by_path(path) | |
42 | + | |
43 | + if WorkAssignmentPlugin.is_submission?(content) && !WorkAssignmentPlugin.can_download_submission?(user, content) | |
44 | + render_access_denied | |
45 | + end | |
46 | + end | |
47 | + | |
48 | + { :type => 'before_filter', | |
49 | + :method_name => 'work_assingment_only_admin_or_owner_download', | |
50 | + :options => {:only => 'view_page'}, | |
51 | + :block => block } | |
52 | + end | |
53 | + | |
54 | +end | ... | ... |
plugins/work_assignment/lib/work_assignment_plugin/helper.rb
0 → 100644
... | ... | @@ -0,0 +1,59 @@ |
1 | +module WorkAssignmentPlugin::Helper | |
2 | + def display_submissions(work_assignment, user) | |
3 | + return if work_assignment.submissions.empty? | |
4 | + content_tag('table', | |
5 | + content_tag('tr', | |
6 | + content_tag('th', _('Author'), :style => 'width: 50%') + | |
7 | + content_tag('th', _('Submission date')) + | |
8 | + content_tag('th', _('Versions'), :style => 'text-align: center') + | |
9 | + content_tag('th', '') | |
10 | + ) + | |
11 | + work_assignment.children.map {|author_folder| display_author_folder(author_folder, user)}.join("\n") | |
12 | + ) | |
13 | + end | |
14 | + | |
15 | + def display_author_folder(author_folder, user) | |
16 | + return if author_folder.children.empty? | |
17 | + content_tag('tr', | |
18 | + content_tag('td', link_to_last_submission(author_folder, user)) + | |
19 | + content_tag('td', time_format(author_folder.children.last.created_at)) + | |
20 | + content_tag('td', author_folder.children.count, :style => 'text-align: center') + | |
21 | + content_tag('td', content_tag('button', _('View all versions'), :class => 'view-author-versions', 'data-folder-id' => author_folder.id)) | |
22 | + ) + | |
23 | + author_folder.children.map {|submission| display_submission(submission, user)}.join("\n") | |
24 | + end | |
25 | + | |
26 | + def display_submission(submission, user) | |
27 | + content_tag('tr', | |
28 | + content_tag('td', link_to_submission(submission, user)) + | |
29 | + content_tag('td', time_format(submission.created_at), :colspan => 3), | |
30 | + :class => "submission-from-#{submission.parent.id}", | |
31 | + :style => 'display: none' | |
32 | + ) | |
33 | + end | |
34 | + | |
35 | + def link_to_submission(submission, user) | |
36 | + if WorkAssignmentPlugin.can_download_submission?(user, submission) | |
37 | + link_to(submission.name, submission.url) | |
38 | + else | |
39 | + submission.name | |
40 | + end | |
41 | + end | |
42 | + | |
43 | + | |
44 | + def link_to_last_submission(author_folder, user) | |
45 | + if WorkAssignmentPlugin.can_download_submission?(user, author_folder.children.last) | |
46 | + link_to(author_folder.name, author_folder.children.last.url) | |
47 | + else | |
48 | + author_folder.name | |
49 | + end | |
50 | + end | |
51 | + # FIXME Copied from custom-froms. Consider passing it to core... | |
52 | + def time_format(time) | |
53 | + minutes = (time.min == 0) ? '' : ':%M' | |
54 | + hour = (time.hour == 0 && minutes.blank?) ? '' : ' %H' | |
55 | + h = hour.blank? ? '' : 'h' | |
56 | + time.strftime("%Y-%m-%d#{hour+minutes+h}") | |
57 | + end | |
58 | + | |
59 | +end | ... | ... |
plugins/work_assignment/lib/work_assignment_plugin/work_assignment.rb
0 → 100644
... | ... | @@ -0,0 +1,48 @@ |
1 | +class WorkAssignmentPlugin::WorkAssignment < Folder | |
2 | + | |
3 | + settings_items :publish_submissions, :type => :boolean, :default => false | |
4 | + | |
5 | + def self.icon_name(article = nil) | |
6 | + 'work-assignment' | |
7 | + end | |
8 | + | |
9 | + def self.short_description | |
10 | + _('Work Assignment') | |
11 | + end | |
12 | + | |
13 | + def self.description | |
14 | + _('Defines a work to be done by the members and receives their submissions about this work.') | |
15 | + end | |
16 | + | |
17 | + def self.versioned_name(submission, folder) | |
18 | + "(V#{folder.children.count + 1}) #{submission.name}" | |
19 | + end | |
20 | + | |
21 | + def accept_comments? | |
22 | + true | |
23 | + end | |
24 | + | |
25 | + def allow_create?(user) | |
26 | + profile.members.include?(user) | |
27 | + end | |
28 | + | |
29 | + def to_html(options = {}) | |
30 | + lambda do | |
31 | + render :file => 'content_viewer/work_assignment.html.erb' | |
32 | + end | |
33 | + end | |
34 | + | |
35 | + def find_or_create_author_folder(author) | |
36 | + children.find_by_slug(author.identifier.to_slug) || Folder.create!(:name => author.name, :slug => author.identifier.to_slug, :parent => self, :profile => profile) | |
37 | + end | |
38 | + | |
39 | + def submissions | |
40 | + children.map(&:children).flatten.compact | |
41 | + end | |
42 | + | |
43 | + def cache_key_with_person(params = {}, user = nil, language = 'en') | |
44 | + cache_key_without_person + (user && profile.members.include?(user) ? "-#{user.identifier}" : '') | |
45 | + end | |
46 | + alias_method_chain :cache_key, :person | |
47 | + | |
48 | +end | ... | ... |
... | ... | @@ -0,0 +1,16 @@ |
1 | +jQuery(".view-author-versions").each(function(index, bt){ | |
2 | + jQuery(bt).button({ | |
3 | + icons: { | |
4 | + primary: "ui-icon-info" | |
5 | + }, | |
6 | + text: false | |
7 | + }); | |
8 | + bt.onclick = function(){ | |
9 | + var folderId = this.getAttribute("data-folder-id"); | |
10 | + var tr = jQuery(".submission-from-"+folderId); | |
11 | + if ( tr[0].style.display == "none" ) | |
12 | + tr.show(); | |
13 | + else | |
14 | + tr.hide(); | |
15 | + } | |
16 | +}); | ... | ... |
plugins/work_assignment/test/functional/cms_controller_test.rb
0 → 100644
... | ... | @@ -0,0 +1,44 @@ |
1 | +require 'test_helper' | |
2 | +require 'cms_controller' | |
3 | + | |
4 | +# Re-raise errors caught by the controller. | |
5 | +class CmsController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class CmsControllerTest < ActionController::TestCase | |
8 | + | |
9 | + def setup | |
10 | + @controller = CmsController.new | |
11 | + @request = ActionController::TestRequest.new | |
12 | + @response = ActionController::TestResponse.new | |
13 | + @person = create_user('test_user').person | |
14 | + login_as :test_user | |
15 | + end | |
16 | + | |
17 | + attr_accessor :person | |
18 | + | |
19 | + should 'not allow non-members to upload submissions on work_assignment' do | |
20 | + organization = fast_create(Organization) | |
21 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Work Assignment', :profile => organization) | |
22 | + | |
23 | + get :upload_files, :profile => organization.identifier, :parent_id => work_assignment.id | |
24 | + assert_response :forbidden | |
25 | + assert_template 'access_denied.rhtml' | |
26 | + | |
27 | + organization.add_member(person) | |
28 | + | |
29 | + get :upload_files, :profile => organization.identifier, :parent_id => work_assignment.id | |
30 | + assert_response :success | |
31 | + end | |
32 | + | |
33 | + should 'upload submission and automatically move it to the author folder' do | |
34 | + organization = fast_create(Organization) | |
35 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Work Assignment', :profile => organization) | |
36 | + organization.add_member(person) | |
37 | + post :upload_files, :profile => organization.identifier, :parent_id => work_assignment.id, :uploaded_files => [fixture_file_upload('/files/test.txt', 'text/plain')] | |
38 | + | |
39 | + submission = UploadedFile.last | |
40 | + assert_equal work_assignment.find_or_create_author_folder(person), submission.parent | |
41 | + end | |
42 | + | |
43 | +end | |
44 | + | ... | ... |
plugins/work_assignment/test/functional/content_viewer_controller_test.rb
0 → 100644
... | ... | @@ -0,0 +1,41 @@ |
1 | +require 'test_helper' | |
2 | +require 'content_viewer_controller' | |
3 | + | |
4 | +# Re-raise errors caught by the controller. | |
5 | +class ContentViewerController; def rescue_action(e) raise e end; end | |
6 | + | |
7 | +class ContentViewerControllerTest < ActionController::TestCase | |
8 | + | |
9 | + def setup | |
10 | + @controller = ContentViewerController.new | |
11 | + @request = ActionController::TestRequest.new | |
12 | + @response = ActionController::TestResponse.new | |
13 | + | |
14 | + @organization = fast_create(Organization) | |
15 | + @work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Work Assignment', :profile => @organization) | |
16 | + @person = create_user('test_user').person | |
17 | + @environment = @organization.environment | |
18 | + @environment.enable_plugin(WorkAssignmentPlugin) | |
19 | + @environment.save! | |
20 | + login_as(:test_user) | |
21 | + end | |
22 | + attr_reader :organization, :person, :work_assignment | |
23 | + | |
24 | + should 'can download work_assignment' do | |
25 | + random_member = fast_create(Person) | |
26 | + organization.add_member(random_member) | |
27 | + folder = work_assignment.find_or_create_author_folder(random_member) | |
28 | + submission = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => organization, :parent => folder) | |
29 | + WorkAssignmentPlugin.stubs(:can_download_submission?).returns(false) | |
30 | + | |
31 | + get :view_page, :profile => organization.identifier, :page => submission.explode_path | |
32 | + assert_response :forbidden | |
33 | + assert_template 'access_denied.rhtml' | |
34 | + | |
35 | + WorkAssignmentPlugin.stubs(:can_download_submission?).returns(true) | |
36 | + | |
37 | + get :view_page, :profile => organization.identifier, :page => submission.explode_path | |
38 | + assert_response :success | |
39 | + end | |
40 | + | |
41 | +end | ... | ... |
plugins/work_assignment/test/unit/work_assingment_plugin/work_assignment_test.rb
0 → 100644
... | ... | @@ -0,0 +1,55 @@ |
1 | +require "test_helper" | |
2 | + | |
3 | +class WorkAssignmentTest < ActiveSupport::TestCase | |
4 | + should 'find or create sub-folder based on author identifier' do | |
5 | + profile = fast_create(Profile) | |
6 | + author = fast_create(Person) | |
7 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Sample Work Assignment', :profile => profile) | |
8 | + assert_nil work_assignment.children.find_by_slug(author.identifier) | |
9 | + | |
10 | + folder = work_assignment.find_or_create_author_folder(author) | |
11 | + assert_not_nil work_assignment.children.find_by_slug(author.identifier) | |
12 | + assert_equal folder, work_assignment.find_or_create_author_folder(author) | |
13 | + end | |
14 | + | |
15 | + should 'return versioned name' do | |
16 | + profile = fast_create(Profile) | |
17 | + folder = fast_create(Folder, :profile_id => profile) | |
18 | + a1 = Article.create!(:name => "Article 1", :profile => profile) | |
19 | + a2 = Article.create!(:name => "Article 2", :profile => profile) | |
20 | + a3 = Article.create!(:name => "Article 3", :profile => profile) | |
21 | + klass = WorkAssignmentPlugin::WorkAssignment | |
22 | + | |
23 | + assert_equal "(V1) #{a1.name}", klass.versioned_name(a1, folder) | |
24 | + | |
25 | + a1.parent = folder | |
26 | + a1.save! | |
27 | + assert_equal "(V2) #{a2.name}", klass.versioned_name(a2, folder) | |
28 | + | |
29 | + a2.parent = folder | |
30 | + a2.save! | |
31 | + assert_equal "(V3) #{a3.name}", klass.versioned_name(a3, folder) | |
32 | + end | |
33 | + | |
34 | + should 'move submission to its correct author folder' do | |
35 | + organization = fast_create(Organization) | |
36 | + author = fast_create(Person) | |
37 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Sample Work Assignment', :profile => organization) | |
38 | + submission = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => organization, :parent => work_assignment, :last_changed_by => author) | |
39 | + | |
40 | + author_folder = work_assignment.find_or_create_author_folder(author) | |
41 | + assert author_folder, submission.parent | |
42 | + end | |
43 | + | |
44 | + should 'add logged user on cache_key if is a member' do | |
45 | + organization = fast_create(Organization) | |
46 | + not_member = fast_create(Person) | |
47 | + member = fast_create(Person) | |
48 | + organization.add_member(member) | |
49 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Sample Work Assignment', :profile => organization) | |
50 | + | |
51 | + assert_no_match(/-#{not_member.identifier}/, work_assignment.cache_key({}, not_member)) | |
52 | + assert_match(/-#{member.identifier}/, work_assignment.cache_key({}, member)) | |
53 | + end | |
54 | + | |
55 | +end | ... | ... |
plugins/work_assignment/test/unit/work_assingment_plugin_test.rb
0 → 100644
... | ... | @@ -0,0 +1,54 @@ |
1 | +require 'test_helper' | |
2 | + | |
3 | +class WorkAssignmentPluginTest < ActiveSupport::TestCase | |
4 | + should 'verify if a content is a work_assignment submission' do | |
5 | + organization = fast_create(Organization) | |
6 | + content = UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => organization, :last_changed_by => fast_create(Person)) | |
7 | + assert !WorkAssignmentPlugin.is_submission?(content) | |
8 | + | |
9 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Work Assignment', :profile => organization) | |
10 | + content.parent = work_assignment | |
11 | + content.save! | |
12 | + assert WorkAssignmentPlugin.is_submission?(content) | |
13 | + | |
14 | + author_folder = work_assignment.find_or_create_author_folder(content.author) | |
15 | + assert_equal author_folder, content.parent | |
16 | + end | |
17 | + | |
18 | + should 'be able to download submission if work_assignment published submissions' do | |
19 | + submission = create_submission | |
20 | + assert !WorkAssignmentPlugin.can_download_submission?(nil, submission) | |
21 | + | |
22 | + work_assignment = submission.parent.parent | |
23 | + work_assignment.publish_submissions = true | |
24 | + work_assignment.save! | |
25 | + assert WorkAssignmentPlugin.can_download_submission?(nil, submission) | |
26 | + end | |
27 | + | |
28 | + should 'be able to download submission if the user is author of it' do | |
29 | + person = fast_create(Person) | |
30 | + submission = create_submission | |
31 | + assert !WorkAssignmentPlugin.can_download_submission?(person, submission) | |
32 | + | |
33 | + submission = create_submission(person) | |
34 | + assert WorkAssignmentPlugin.can_download_submission?(person, submission) | |
35 | + end | |
36 | + | |
37 | + should 'be able to download submission if the user has the view_private_content permission on the profile' do | |
38 | + person = fast_create(Person) | |
39 | + submission = create_submission | |
40 | + assert !WorkAssignmentPlugin.can_download_submission?(person, submission) | |
41 | + | |
42 | + moderator = create_user_with_permission('moderator', 'view_private_content', submission.profile) | |
43 | + assert WorkAssignmentPlugin.can_download_submission?(moderator, submission) | |
44 | + end | |
45 | + | |
46 | + private | |
47 | + | |
48 | + def create_submission(author=nil) | |
49 | + organization = fast_create(Organization) | |
50 | + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Work Assignment', :profile => organization) | |
51 | + author_folder = work_assignment.find_or_create_author_folder(fast_create(Person)) | |
52 | + UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => organization, :parent => author_folder, :last_changed_by => author) | |
53 | + end | |
54 | +end | ... | ... |
plugins/work_assignment/views/cms/work_assignment_plugin/_work_assignment.html.erb
0 → 100644
plugins/work_assignment/views/content_viewer/work_assignment.html.erb
0 → 100644
test/functional/cms_controller_test.rb
... | ... | @@ -1583,6 +1583,28 @@ class CmsControllerTest < ActionController::TestCase |
1583 | 1583 | assert_equal f2, article.parent |
1584 | 1584 | end |
1585 | 1585 | |
1586 | + should 'set author when creating article' do | |
1587 | + login_as(profile.identifier) | |
1588 | + | |
1589 | + post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :article => { :name => 'Sample Article', :body => 'content ...' } | |
1590 | + | |
1591 | + a = profile.articles.find_by_path('sample-article') | |
1592 | + assert_not_nil a | |
1593 | + assert_equal profile, a.author | |
1594 | + end | |
1595 | + | |
1596 | + should 'not allow user upload files if he can not create on the parent folder' do | |
1597 | + c = Community.create!(:name => 'test_comm', :identifier => 'test_comm') | |
1598 | + u = create_user('test_user') | |
1599 | + a = c.articles.create!(:name => 'test_article') | |
1600 | + a.stubs(:allow_create?).with(u).returns(true) | |
1601 | + login_as :test_user | |
1602 | + | |
1603 | + get :upload_files, :profile => c.identifier, :parent_id => a.id | |
1604 | + assert_response :forbidden | |
1605 | + assert_template 'access_denied.rhtml' | |
1606 | + end | |
1607 | + | |
1586 | 1608 | protected |
1587 | 1609 | |
1588 | 1610 | # FIXME this is to avoid adding an extra dependency for a proper JSON parser. | ... | ... |
test/unit/approve_article_test.rb
... | ... | @@ -210,22 +210,21 @@ class ApproveArticleTest < ActiveSupport::TestCase |
210 | 210 | end |
211 | 211 | |
212 | 212 | should 'use author from original article on published' do |
213 | - article.stubs(:last_changed_by_id).returns(profile) | |
214 | - | |
213 | + article.class.any_instance.stubs(:author).returns(profile) | |
215 | 214 | a = ApproveArticle.create!(:name => 'test name', :article => article, :target => community, :requestor => profile) |
216 | 215 | a.finish |
217 | 216 | |
218 | 217 | assert_equal profile, article.class.last.author |
219 | 218 | end |
220 | 219 | |
221 | - | |
222 | - should 'use owning profile as author when there is no referenced article' do | |
220 | + should 'use original article author even if article is destroyed' do | |
221 | + article.class.any_instance.stubs(:author).returns(profile) | |
223 | 222 | a = ApproveArticle.create!(:article => article, :target => community, :requestor => profile) |
224 | 223 | a.finish |
225 | 224 | |
226 | 225 | article.destroy |
227 | 226 | |
228 | - assert_equal community, article.class.last.author | |
227 | + assert_equal profile, article.class.last.author | |
229 | 228 | end |
230 | 229 | |
231 | 230 | should 'the published article have parent if defined' do | ... | ... |
test/unit/article_test.rb
... | ... | @@ -708,14 +708,6 @@ class ArticleTest < ActiveSupport::TestCase |
708 | 708 | assert_equal a.url, a.view_url |
709 | 709 | end |
710 | 710 | |
711 | - should 'know its author' do | |
712 | - assert_equal profile, Article.new(:last_changed_by => profile).author | |
713 | - end | |
714 | - | |
715 | - should 'use owning profile as author when we dont know who did the last change' do | |
716 | - assert_equal profile, Article.new(:last_changed_by => nil, :profile => profile).author | |
717 | - end | |
718 | - | |
719 | 711 | should 'have published_at' do |
720 | 712 | assert_respond_to Article.new, :published_at |
721 | 713 | end |
... | ... | @@ -791,15 +783,7 @@ class ArticleTest < ActiveSupport::TestCase |
791 | 783 | assert_match(/-owner/, a.cache_key({}, c)) |
792 | 784 | end |
793 | 785 | |
794 | - should 'have a creator method' do | |
795 | - c = fast_create(Community) | |
796 | - a = c.articles.create!(:name => 'a test article', :last_changed_by => profile) | |
797 | - p = create_user('other_user').person | |
798 | - a.update_attributes(:body => 'some content', :last_changed_by => p); a.save! | |
799 | - assert_equal profile, a.creator | |
800 | - end | |
801 | - | |
802 | - should 'allow creator to edit if is publisher' do | |
786 | + should 'allow author to edit if is publisher' do | |
803 | 787 | c = fast_create(Community) |
804 | 788 | p = create_user_with_permission('test_user', 'publish_content', c) |
805 | 789 | a = c.articles.create!(:name => 'a test article', :last_changed_by => p) |
... | ... | @@ -1372,19 +1356,18 @@ class ArticleTest < ActiveSupport::TestCase |
1372 | 1356 | assert Article.method_defined?('author_name') |
1373 | 1357 | end |
1374 | 1358 | |
1375 | - should "the author_name returns the name od the article's author" do | |
1376 | - author = mock() | |
1377 | - author.expects(:name).returns('author name') | |
1378 | - a = Article.new | |
1379 | - a.expects(:author).returns(author) | |
1380 | - assert_equal 'author name', a.author_name | |
1359 | + should "the author_name returns the name of the article's author" do | |
1360 | + author = fast_create(Person) | |
1361 | + a = profile.articles.create!(:name => 'a test article', :last_changed_by => author) | |
1362 | + assert_equal author.name, a.author_name | |
1363 | + author.destroy | |
1381 | 1364 | a.author_name = 'some name' |
1382 | 1365 | assert_equal 'some name', a.author_name |
1383 | 1366 | end |
1384 | 1367 | |
1385 | 1368 | should 'retrieve latest info from topic when has no comments' do |
1386 | 1369 | forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id) |
1387 | - post = fast_create(TextileArticle, :name => 'First post', :profile_id => profile.id, :parent_id => forum.id, :updated_at => Time.now) | |
1370 | + post = fast_create(TextileArticle, :name => 'First post', :profile_id => profile.id, :parent_id => forum.id, :updated_at => Time.now, :last_changed_by_id => profile.id) | |
1388 | 1371 | assert_equal post.updated_at, post.info_from_last_update[:date] |
1389 | 1372 | assert_equal profile.name, post.info_from_last_update[:author_name] |
1390 | 1373 | assert_equal profile.url, post.info_from_last_update[:author_url] |
... | ... | @@ -1818,4 +1801,15 @@ class ArticleTest < ActiveSupport::TestCase |
1818 | 1801 | assert a1.errors.invalid?(:parent_id) |
1819 | 1802 | end |
1820 | 1803 | |
1804 | + should 'set author_name before creating article if there is an author' do | |
1805 | + author = fast_create(Person) | |
1806 | + article = Article.create!(:name => 'Test', :profile => profile, :last_changed_by => author) | |
1807 | + assert_equal author.name, article.author_name | |
1808 | + | |
1809 | + author_name = author.name | |
1810 | + author.destroy | |
1811 | + article.reload | |
1812 | + assert_equal author_name, article.author_name | |
1813 | + end | |
1814 | + | |
1821 | 1815 | end | ... | ... |
test/unit/folder_helper_test.rb
... | ... | @@ -33,7 +33,7 @@ class FolderHelperTest < ActiveSupport::TestCase |
33 | 33 | |
34 | 34 | should 'display icon for type of article' do |
35 | 35 | Article.expects(:icon_name).returns('article') |
36 | - assert_match /icon-newarticle/, icon_for_new_article('Article') | |
36 | + assert_match /icon-newarticle/, icon_for_new_article(Article) | |
37 | 37 | end |
38 | 38 | |
39 | 39 | should 'list all the folder\'s children to the owner' do | ... | ... |
test/unit/forum_helper_test.rb
... | ... | @@ -29,17 +29,16 @@ class ForumHelperTest < ActiveSupport::TestCase |
29 | 29 | end |
30 | 30 | |
31 | 31 | should 'list posts with different classes' do |
32 | - forum.children << older_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => false) | |
32 | + forum.children << older_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => false, :last_changed_by => profile) | |
33 | 33 | one_month_later = Time.now + 1.month |
34 | 34 | Time.stubs(:now).returns(one_month_later) |
35 | - forum.children << newer_post = TextileArticle.create!(:name => 'Second post', :profile => profile, :parent => forum, :published => true) | |
35 | + forum.children << newer_post = TextileArticle.create!(:name => 'Second post', :profile => profile, :parent => forum, :published => true, :last_changed_by => profile) | |
36 | 36 | assert_match /forum-post position-1 first odd-post.*forum-post position-2 last not-published even-post/, list_forum_posts(forum.posts) |
37 | 37 | end |
38 | 38 | |
39 | 39 | should 'return post update if it has no comments' do |
40 | 40 | author = create_user('forum test author').person |
41 | - some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true) | |
42 | - some_post.expects(:author).returns(author).times(2) | |
41 | + some_post = TextileArticle.create!(:name => 'First post', :profile => profile, :parent => forum, :published => true, :last_changed_by => author) | |
43 | 42 | assert some_post.comments.empty? |
44 | 43 | out = last_topic_update(some_post) |
45 | 44 | assert_match some_post.updated_at.to_s, out | ... | ... |