Commit 45e5189b55d3effe6b73b68fee7a0f5400b02185

Authored by Rodrigo Souto
2 parents 56e1b119 7358e1d0

Merge branch 'work-assignment' into features

Conflicts:
	db/schema.rb
	test/functional/cms_controller_test.rb
	test/unit/article_test.rb
app/controllers/my_profile/cms_controller.rb
... ... @@ -16,7 +16,12 @@ 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 + profile.articles.find(article_id).allow_create?(user)
  22 + end
  23 +
  24 + protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :upload_files] do |c, user, profile|
20 25 user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))
21 26 end
22 27  
... ... @@ -92,7 +97,7 @@ class CmsController < MyProfileController
92 97 @article_types = []
93 98 available_article_types.each do |type|
94 99 @article_types.push({
95   - :name => type.name,
  100 + :class => type,
96 101 :short_description => type.short_description,
97 102 :description => type.description
98 103 })
... ... @@ -117,6 +122,7 @@ class CmsController < MyProfileController
117 122 end
118 123  
119 124 @article.profile = profile
  125 + @article.author = user
120 126 @article.last_changed_by = user
121 127  
122 128 translations if @article.translatable?
... ... @@ -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, :author => user) unless file == ''
158 164 end
159 165 @errors = @uploaded_files.select { |f| f.errors.any? }
160 166 if @errors.any?
... ...
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/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_save do |article|
  17 + if article.author_id
  18 + article.author_name = Person.find(article.author_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? }
... ... @@ -20,6 +26,7 @@ class Article &lt; ActiveRecord::Base
20 26 validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? }
21 27  
22 28 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
  29 + belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id'
23 30  
24 31 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
25 32  
... ... @@ -289,7 +296,7 @@ class Article &lt; ActiveRecord::Base
289 296 if last_comment
290 297 {:date => last_comment.created_at, :author_name => last_comment.author_name, :author_url => last_comment.author_url}
291 298 else
292   - {:date => updated_at, :author_name => author.name, :author_url => author.url}
  299 + {:date => updated_at, :author_name => author_name, :author_url => author ? author.url : nil}
293 300 end
294 301 end
295 302  
... ... @@ -441,7 +448,7 @@ class Article &lt; ActiveRecord::Base
441 448 end
442 449  
443 450 def allow_post_content?(user = nil)
444   - user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == self.creator))
  451 + user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == author))
445 452 end
446 453  
447 454 def allow_publish_content?(user = nil)
... ... @@ -538,16 +545,8 @@ class Article &lt; ActiveRecord::Base
538 545 false
539 546 end
540 547  
541   - def author
542   - if reference_article
543   - reference_article.author
544   - else
545   - last_changed_by || profile
546   - end
547   - end
548   -
549 548 def author_name
550   - setting[:author_name].blank? ? author.name : setting[:author_name]
  549 + author ? author.name : setting[:author_name]
551 550 end
552 551  
553 552 alias :active_record_cache_key :cache_key
... ... @@ -572,11 +571,6 @@ class Article &lt; ActiveRecord::Base
572 571 truncate sanitize_html(self.lead), :length => 170, :omission => '...'
573 572 end
574 573  
575   - def creator
576   - creator_id = versions[0][:last_changed_by_id]
577   - creator_id && Profile.find(creator_id)
578   - end
579   -
580 574 def notifiable?
581 575 false
582 576 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/person.rb
... ... @@ -54,6 +54,8 @@ class Person &lt; Profile
54 54  
55 55 has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy
56 56  
  57 + has_many :creations, :class_name => 'Article', :foreign_key => :author_id
  58 +
57 59 named_scope :more_popular,
58 60 :select => "#{Profile.qualified_column_names}, count(friend_id) as total",
59 61 :group => Profile.qualified_column_names,
... ...
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/migrate/20121024220349_add_author_id_to_article.rb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +class AddAuthorIdToArticle < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :articles, :author_id, :integer
  4 + add_column :article_versions, :author_id, :integer
  5 + end
  6 +
  7 + def self.down
  8 + remove_column :articles, :author_id
  9 + remove_column :article_versions, :author_id, :integer
  10 + end
  11 +end
... ...
db/migrate/20121024222938_set_authors_based_on_article_versions.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class SetAuthorsBasedOnArticleVersions < ActiveRecord::Migration
  2 + def self.up
  3 + update('UPDATE articles SET author_id = (SELECT profiles.id FROM articles as a INNER JOIN article_versions ON a.id = article_versions.article_id INNER JOIN profiles ON profiles.id = article_versions.last_changed_by_id WHERE article_versions.version = 1 AND articles.id = a.id)')
  4 + end
  5 +
  6 + def self.down
  7 + say "Can not be revesed!"
  8 + end
  9 +end
... ...
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 => 20121024222938) do
13 13  
14 14 create_table "abuse_reports", :force => true do |t|
15 15 t.integer "reporter_id"
... ... @@ -86,6 +86,7 @@ ActiveRecord::Schema.define(:version =&gt; 20121008185303) do
86 86 t.string "language"
87 87 t.string "source_name"
88 88 t.integer "license_id"
  89 + t.integer "author_id"
89 90 end
90 91  
91 92 create_table "articles", :force => true do |t|
... ... @@ -127,6 +128,7 @@ ActiveRecord::Schema.define(:version =&gt; 20121008185303) do
127 128 t.string "language"
128 129 t.string "source_name"
129 130 t.integer "license_id"
  131 + t.integer "author_id"
130 132 end
131 133  
132 134 add_index "articles", ["translation_of_id"], :name => "index_articles_on_translation_of_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/work_assignment_plugin.rb 0 → 100644
... ... @@ -0,0 +1,52 @@
  1 +class WorkAssignmentPlugin < Noosfero::Plugin
  2 +
  3 + def self.plugin_name
  4 + "Work Assignment"
  5 + end
  6 +
  7 + def self.plugin_description
  8 + _("New kind of content for organizations.")
  9 + end
  10 +
  11 + def self.can_download_submission?(user, submission)
  12 + work_assignment = submission.parent.parent
  13 + work_assignment.publish_submissions || (user && (submission.author == user || user.has_permission?('view_private_content', work_assignment.profile)))
  14 + end
  15 +
  16 + def self.is_submission?(content)
  17 + content && content.parent && content.parent.parent && content.parent.parent.kind_of?(WorkAssignmentPlugin::WorkAssignment)
  18 + end
  19 +
  20 + def content_types
  21 + [WorkAssignmentPlugin::WorkAssignment] if context.profile.organization?
  22 + end
  23 +
  24 + def stylesheet?
  25 + true
  26 + end
  27 +
  28 + def content_remove_new(content)
  29 + content.kind_of?(WorkAssignmentPlugin::WorkAssignment)
  30 + end
  31 +
  32 + def content_remove_upload(content)
  33 + !content.profile.members.include?(context.send(:user))
  34 + end
  35 +
  36 + def content_viewer_controller_filters
  37 + block = lambda do
  38 + path = params[:page].join('/')
  39 + content = profile.articles.find_by_path(path)
  40 +
  41 + if WorkAssignmentPlugin.is_submission?(content) && !WorkAssignmentPlugin.can_download_submission?(user, content)
  42 + render_access_denied
  43 + end
  44 + end
  45 +
  46 + { :type => 'before_filter',
  47 + :method_name => 'work_assingment_only_admin_or_owner_download',
  48 + :options => {:only => 'view_page'},
  49 + :block => block }
  50 + end
  51 +
  52 +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,52 @@
  1 +class WorkAssignmentPlugin::WorkAssignment < Folder
  2 +
  3 + after_save do |work_assignment|
  4 + work_assignment.children.select {|child| child.kind_of?(UploadedFile)}.each do |submission|
  5 + author_folder = work_assignment.find_or_create_author_folder(submission.author)
  6 + submission.name = versioned_name(submission, author_folder) if !(submission.name =~ /\(V[0-9]*\)/)
  7 + submission.parent = author_folder
  8 + submission.save!
  9 + end
  10 + end
  11 +
  12 + settings_items :publish_submissions, :type => :boolean, :default => false
  13 +
  14 + def self.icon_name(article = nil)
  15 + 'work-assignment'
  16 + end
  17 +
  18 + def self.short_description
  19 + _('Work Assignment')
  20 + end
  21 +
  22 + def self.description
  23 + _('Defines a work to be done by the members and receives their submissions about this work.')
  24 + end
  25 +
  26 + def self.versioned_name(submission, folder)
  27 + "(V#{folder.children.count + 1}) #{submission.name}"
  28 + end
  29 +
  30 + def accept_comments?
  31 + true
  32 + end
  33 +
  34 + def allow_create?(user)
  35 + profile.members.include?(user)
  36 + end
  37 +
  38 + def to_html(options = {})
  39 + lambda do
  40 + render :file => 'content_viewer/work_assignment.html.erb'
  41 + end
  42 + end
  43 +
  44 + def find_or_create_author_folder(author)
  45 + children.find_by_slug(author.identifier) || Folder.create!(:name => author.name, :slug => author.identifier, :parent => self, :profile => profile)
  46 + end
  47 +
  48 + def submissions
  49 + children.map(&:children).flatten.compact
  50 + end
  51 +
  52 +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,34 @@
  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 +end
  34 +
... ...
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,43 @@
  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 + folder = fast_create(Folder)
  17 + profile = fast_create(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, :author => author)
  39 +
  40 + author_folder = work_assignment.find_or_create_author_folder(author)
  41 + assert author_folder, submission.parent
  42 + end
  43 +end
... ...
plugins/work_assignment/test/unit/work_assingment_plugin_test.rb 0 → 100644
... ... @@ -0,0 +1,57 @@
  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)
  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(fast_create(Person))
  15 + content.parent = author_folder
  16 + content.save!
  17 + assert WorkAssignmentPlugin.is_submission?(content)
  18 + end
  19 +
  20 + should 'be able to download submission if work_assignment published submissions' do
  21 + submission = create_submission
  22 + assert !WorkAssignmentPlugin.can_download_submission?(nil, submission)
  23 +
  24 + work_assignment = submission.parent.parent
  25 + work_assignment.publish_submissions = true
  26 + work_assignment.save!
  27 + assert WorkAssignmentPlugin.can_download_submission?(nil, submission)
  28 + end
  29 +
  30 + should 'be able to download submission if the user is author of it' do
  31 + person = fast_create(Person)
  32 + submission = create_submission
  33 + assert !WorkAssignmentPlugin.can_download_submission?(person, submission)
  34 +
  35 + submission.author = person
  36 + submission.save!
  37 + assert WorkAssignmentPlugin.can_download_submission?(person, submission)
  38 + end
  39 +
  40 + should 'be able to download submission if the user has the view_private_content permission on the profile' do
  41 + person = fast_create(Person)
  42 + submission = create_submission
  43 + assert !WorkAssignmentPlugin.can_download_submission?(person, submission)
  44 +
  45 + moderator = create_user_with_permission('moderator', 'view_private_content', submission.profile)
  46 + assert WorkAssignmentPlugin.can_download_submission?(moderator, submission)
  47 + end
  48 +
  49 + private
  50 +
  51 + def create_submission
  52 + organization = fast_create(Organization)
  53 + work_assignment = WorkAssignmentPlugin::WorkAssignment.create!(:name => 'Work Assignment', :profile => organization)
  54 + author_folder = work_assignment.find_or_create_author_folder(fast_create(Person))
  55 + UploadedFile.create!(:uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => organization, :parent => author_folder)
  56 + end
  57 +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/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
... ... @@ -1372,7 +1364,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1372 1364 assert Article.method_defined?('author_name')
1373 1365 end
1374 1366  
1375   - should "the author_name returns the name od the article's author" do
  1367 + should "the author_name returns the name of the article's author" do
1376 1368 author = mock()
1377 1369 author.expects(:name).returns('author name')
1378 1370 a = Article.new
... ... @@ -1818,4 +1810,25 @@ class ArticleTest &lt; ActiveSupport::TestCase
1818 1810 assert a1.errors.invalid?(:parent_id)
1819 1811 end
1820 1812  
  1813 + should 'be able to have an author' do
  1814 + author = fast_create(Person)
  1815 + article = Article.new
  1816 + assert_nothing_raised do
  1817 + article.author = author
  1818 + end
  1819 + end
  1820 +
  1821 + should 'set author_name before saving article if there is an author' do
  1822 + author = fast_create(Person)
  1823 + article = fast_create(Article, :profile_id => fast_create(Profile).id)
  1824 + article.author = author
  1825 + article.save!
  1826 + assert_equal author.name, article.author_name
  1827 +
  1828 + author_name = author.name
  1829 + author.destroy
  1830 + article.reload
  1831 + assert_equal author_name, article.author_name
  1832 + end
  1833 +
1821 1834 end
... ...
test/unit/person_test.rb
... ... @@ -1262,4 +1262,15 @@ class PersonTest &lt; ActiveSupport::TestCase
1262 1262  
1263 1263 assert person.has_permission?('bli', Profile.new)
1264 1264 end
  1265 +
  1266 + should 'have creations' do
  1267 + person = create_user('some-user').person
  1268 + a1 = fast_create(Article, :author_id => person.id)
  1269 + a2 = fast_create(Article, :author_id => person.id)
  1270 + a3 = fast_create(Article)
  1271 +
  1272 + assert_includes person.creations, a1
  1273 + assert_includes person.creations, a2
  1274 + assert_not_includes person.creations, a3
  1275 + end
1265 1276 end
... ...