Commit 483f5d55ae046c308ea951ddb50d9c77715b759d

Authored by Daniela Feitosa
2 parents 43e837c4 fe47b515

Merge remote branch 'diguliu/features' into work-assignment

Conflicts:
	test/functional/cms_controller_test.rb
	test/unit/article_test.rb
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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
1 1 class TinyMceArticle < TextArticle
2 2  
3 3 def self.short_description
4   - _('Text article with visual editor.')
  4 + _('Text article with visual editor')
5 5 end
6 6  
7 7 def self.description
... ...
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
... ...
plugins/work_assignment/lib/ext/uploaded_file.rb 0 → 100644
... ... @@ -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
... ...
plugins/work_assignment/lib/work_assignment_plugin.rb 0 → 100644
... ... @@ -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
... ...
plugins/work_assignment/public/show_versions.js 0 → 100644
... ... @@ -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/public/style.css 0 → 100644
... ... @@ -0,0 +1,2 @@
  1 +.icon-newwork-assignment { background-image: url(../../designs/icons/tango/Tango/16x16/categories/applications-office.png) }
  2 +.icon-work-assignment { background-image: url(../../designs/icons/tango/Tango/16x16/categories/applications-office.png) }
... ...
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
... ... @@ -0,0 +1,3 @@
  1 +<%= render :partial => 'folder', :locals => {:f => f} %>
  2 +
  3 +<%= f.check_box(:publish_submissions) %>
... ...
plugins/work_assignment/views/content_viewer/work_assignment.html.erb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<% extend WorkAssignmentPlugin::Helper %>
  2 +
  3 +<% unless @page.body.blank? %>
  4 + <div><%= @page.body %></div>
  5 + <hr/>
  6 +<% end %>
  7 +
  8 +<%= display_submissions(@page, user) %>
  9 +
  10 +<%= javascript_include_tag '../plugins/work_assignment/show_versions' %>
... ...
test/functional/cms_controller_test.rb
... ... @@ -1583,6 +1583,28 @@ class CmsControllerTest &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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 &lt; 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
... ...