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,7 +16,13 @@ class CmsController < MyProfileController
16 16
17 before_filter :login_required, :except => [:suggest_an_article] 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 user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)) 26 user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))
21 end 27 end
22 28
@@ -92,7 +98,7 @@ class CmsController < MyProfileController @@ -92,7 +98,7 @@ class CmsController < MyProfileController
92 @article_types = [] 98 @article_types = []
93 available_article_types.each do |type| 99 available_article_types.each do |type|
94 @article_types.push({ 100 @article_types.push({
95 - :name => type.name, 101 + :class => type,
96 :short_description => type.short_description, 102 :short_description => type.short_description,
97 :description => type.description 103 :description => type.description
98 }) 104 })
@@ -154,7 +160,7 @@ class CmsController < MyProfileController @@ -154,7 +160,7 @@ class CmsController < MyProfileController
154 end 160 end
155 if request.post? && params[:uploaded_files] 161 if request.post? && params[:uploaded_files]
156 params[:uploaded_files].each do |file| 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 end 164 end
159 @errors = @uploaded_files.select { |f| f.errors.any? } 165 @errors = @uploaded_files.select { |f| f.errors.any? }
160 if @errors.any? 166 if @errors.any?
app/helpers/content_viewer_helper.rb
@@ -26,7 +26,7 @@ module ContentViewerHelper @@ -26,7 +26,7 @@ module ContentViewerHelper
26 end 26 end
27 title << content_tag('span', 27 title << content_tag('span',
28 content_tag('span', show_date(article.published_at), :class => 'date') + 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 content_tag('span', comments, :class => 'comments'), 30 content_tag('span', comments, :class => 'comments'),
31 :class => 'created-at' 31 :class => 'created-at'
32 ) 32 )
app/helpers/folder_helper.rb
@@ -52,8 +52,8 @@ module FolderHelper @@ -52,8 +52,8 @@ module FolderHelper
52 end 52 end
53 end 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 end 57 end
58 58
59 def custom_options_for_article(article) 59 def custom_options_for_article(article)
app/helpers/forms_helper.rb
@@ -142,6 +142,38 @@ module FormsHelper @@ -142,6 +142,38 @@ module FormsHelper
142 content_tag('table',rows.join("\n")) 142 content_tag('table',rows.join("\n"))
143 end 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 def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) 177 def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {})
146 datepicker_options[:disabled] ||= false 178 datepicker_options[:disabled] ||= false
147 datepicker_options[:alt_field] ||= '' 179 datepicker_options[:alt_field] ||= ''
app/models/approve_article.rb
@@ -48,7 +48,7 @@ class ApproveArticle &lt; Task @@ -48,7 +48,7 @@ class ApproveArticle &lt; Task
48 end 48 end
49 49
50 def perform 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 end 52 end
53 53
54 def title 54 def title
app/models/article.rb
@@ -13,6 +13,12 @@ class Article &lt; ActiveRecord::Base @@ -13,6 +13,12 @@ class Article &lt; ActiveRecord::Base
13 # xss_terminate plugin can't sanitize array fields 13 # xss_terminate plugin can't sanitize array fields
14 before_save :sanitize_tag_list 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 belongs_to :profile 22 belongs_to :profile
17 validates_presence_of :profile_id, :name 23 validates_presence_of :profile_id, :name
18 validates_presence_of :slug, :path, :if => lambda { |article| !article.name.blank? } 24 validates_presence_of :slug, :path, :if => lambda { |article| !article.name.blank? }
@@ -289,7 +295,7 @@ class Article &lt; ActiveRecord::Base @@ -289,7 +295,7 @@ class Article &lt; ActiveRecord::Base
289 if last_comment 295 if last_comment
290 {:date => last_comment.created_at, :author_name => last_comment.author_name, :author_url => last_comment.author_url} 296 {:date => last_comment.created_at, :author_name => last_comment.author_name, :author_url => last_comment.author_url}
291 else 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 end 299 end
294 end 300 end
295 301
@@ -441,7 +447,7 @@ class Article &lt; ActiveRecord::Base @@ -441,7 +447,7 @@ class Article &lt; ActiveRecord::Base
441 end 447 end
442 448
443 def allow_post_content?(user = nil) 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 end 451 end
446 452
447 def allow_publish_content?(user = nil) 453 def allow_publish_content?(user = nil)
@@ -496,7 +502,6 @@ class Article &lt; ActiveRecord::Base @@ -496,7 +502,6 @@ class Article &lt; ActiveRecord::Base
496 :slug, 502 :slug,
497 :updated_at, 503 :updated_at,
498 :created_at, 504 :created_at,
499 - :last_changed_by_id,  
500 :version, 505 :version,
501 :lock_version, 506 :lock_version,
502 :type, 507 :type,
@@ -539,15 +544,20 @@ class Article &lt; ActiveRecord::Base @@ -539,15 +544,20 @@ class Article &lt; ActiveRecord::Base
539 end 544 end
540 545
541 def author 546 def author
542 - if reference_article  
543 - reference_article.author 547 + if versions.empty?
  548 + last_changed_by
544 else 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 end 552 end
547 end 553 end
548 554
549 def author_name 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 end 561 end
552 562
553 alias :active_record_cache_key :cache_key 563 alias :active_record_cache_key :cache_key
@@ -572,11 +582,6 @@ class Article &lt; ActiveRecord::Base @@ -572,11 +582,6 @@ class Article &lt; ActiveRecord::Base
572 truncate sanitize_html(self.lead), :length => 170, :omission => '...' 582 truncate sanitize_html(self.lead), :length => 170, :omission => '...'
573 end 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 def notifiable? 585 def notifiable?
581 false 586 false
582 end 587 end
app/models/event.rb
@@ -38,7 +38,7 @@ class Event &lt; Article @@ -38,7 +38,7 @@ class Event &lt; Article
38 filter_iframes :body, :link, :address, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe } 38 filter_iframes :body, :link, :address, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe }
39 39
40 def self.description 40 def self.description
41 - _('A calendar event') 41 + _('A calendar event.')
42 end 42 end
43 43
44 def self.short_description 44 def self.short_description
app/models/raw_html_article.rb
@@ -5,11 +5,11 @@ class RawHTMLArticle &lt; TextArticle @@ -5,11 +5,11 @@ class RawHTMLArticle &lt; TextArticle
5 end 5 end
6 6
7 def self.short_description 7 def self.short_description
8 - _('Raw HTML text article.') 8 + _('Raw HTML text article')
9 end 9 end
10 10
11 def self.description 11 def self.description
12 - _('Allows HTML without filter (only for admins)') 12 + _('Allows HTML without filter (only for admins).')
13 end 13 end
14 14
15 xss_terminate :only => [ ] 15 xss_terminate :only => [ ]
app/models/tiny_mce_article.rb
1 class TinyMceArticle < TextArticle 1 class TinyMceArticle < TextArticle
2 2
3 def self.short_description 3 def self.short_description
4 - _('Text article with visual editor.') 4 + _('Text article with visual editor')
5 end 5 end
6 6
7 def self.description 7 def self.description
app/views/cms/select_article_type.rhtml
@@ -2,9 +2,9 @@ @@ -2,9 +2,9 @@
2 2
3 <ul id="article_types"> 3 <ul id="article_types">
4 <% for type in @article_types %> 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 <% content_tag('a', :href => url_for(action.merge(:parent_id => @parent_id, :back_to => @back_to))) do %> 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 <strong><%= type[:short_description] %></strong> 8 <strong><%= type[:short_description] %></strong>
9 <div class='description'><%= type[:description] %></div> 9 <div class='description'><%= type[:description] %></div>
10 </li> 10 </li>
app/views/content_viewer/_article_toolbar.rhtml
@@ -34,11 +34,11 @@ @@ -34,11 +34,11 @@
34 <%= expirable_button @page, :locale, content, url %> 34 <%= expirable_button @page, :locale, content, url %>
35 <% end %> 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 <% end %> 38 <% end %>
39 39
40 <% if @page.accept_uploads? && @page.allow_create?(user) %> 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 <% end %> 42 <% end %>
43 43
44 <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest) %> 44 <% if !@page.allow_create?(user) && profile.community? && (@page.blog? || @page.parent && @page.parent.blog?) && !remove_content_button(:suggest) %>
@@ -9,7 +9,7 @@ @@ -9,7 +9,7 @@
9 # 9 #
10 # It's strongly recommended to check this file into your version control system. 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 create_table "abuse_reports", :force => true do |t| 14 create_table "abuse_reports", :force => true do |t|
15 t.integer "reporter_id" 15 t.integer "reporter_id"
lib/noosfero/plugin.rb
@@ -130,7 +130,7 @@ class Noosfero::Plugin @@ -130,7 +130,7 @@ class Noosfero::Plugin
130 end 130 end
131 131
132 # -> Adds plugin-specific content types to CMS 132 # -> Adds plugin-specific content types to CMS
133 - # returns = { content type class } 133 + # returns = [ContentClass1, ContentClass2, ...]
134 def content_types 134 def content_types
135 nil 135 nil
136 end 136 end
@@ -384,7 +384,9 @@ class Noosfero::Plugin @@ -384,7 +384,9 @@ class Noosfero::Plugin
384 private 384 private
385 385
386 def content_actions 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 end 390 end
389 391
390 end 392 end
plugins/work_assignment/lib/ext/uploaded_file.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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 @@ @@ -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,6 +1583,28 @@ class CmsControllerTest &lt; ActionController::TestCase
1583 assert_equal f2, article.parent 1583 assert_equal f2, article.parent
1584 end 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 protected 1608 protected
1587 1609
1588 # FIXME this is to avoid adding an extra dependency for a proper JSON parser. 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,22 +210,21 @@ class ApproveArticleTest &lt; ActiveSupport::TestCase
210 end 210 end
211 211
212 should 'use author from original article on published' do 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 a = ApproveArticle.create!(:name => 'test name', :article => article, :target => community, :requestor => profile) 214 a = ApproveArticle.create!(:name => 'test name', :article => article, :target => community, :requestor => profile)
216 a.finish 215 a.finish
217 216
218 assert_equal profile, article.class.last.author 217 assert_equal profile, article.class.last.author
219 end 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 a = ApproveArticle.create!(:article => article, :target => community, :requestor => profile) 222 a = ApproveArticle.create!(:article => article, :target => community, :requestor => profile)
224 a.finish 223 a.finish
225 224
226 article.destroy 225 article.destroy
227 226
228 - assert_equal community, article.class.last.author 227 + assert_equal profile, article.class.last.author
229 end 228 end
230 229
231 should 'the published article have parent if defined' do 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,14 +708,6 @@ class ArticleTest &lt; ActiveSupport::TestCase
708 assert_equal a.url, a.view_url 708 assert_equal a.url, a.view_url
709 end 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 should 'have published_at' do 711 should 'have published_at' do
720 assert_respond_to Article.new, :published_at 712 assert_respond_to Article.new, :published_at
721 end 713 end
@@ -791,15 +783,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -791,15 +783,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
791 assert_match(/-owner/, a.cache_key({}, c)) 783 assert_match(/-owner/, a.cache_key({}, c))
792 end 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 c = fast_create(Community) 787 c = fast_create(Community)
804 p = create_user_with_permission('test_user', 'publish_content', c) 788 p = create_user_with_permission('test_user', 'publish_content', c)
805 a = c.articles.create!(:name => 'a test article', :last_changed_by => p) 789 a = c.articles.create!(:name => 'a test article', :last_changed_by => p)
@@ -1372,19 +1356,18 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1372,19 +1356,18 @@ class ArticleTest &lt; ActiveSupport::TestCase
1372 assert Article.method_defined?('author_name') 1356 assert Article.method_defined?('author_name')
1373 end 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 a.author_name = 'some name' 1364 a.author_name = 'some name'
1382 assert_equal 'some name', a.author_name 1365 assert_equal 'some name', a.author_name
1383 end 1366 end
1384 1367
1385 should 'retrieve latest info from topic when has no comments' do 1368 should 'retrieve latest info from topic when has no comments' do
1386 forum = fast_create(Forum, :name => 'Forum test', :profile_id => profile.id) 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 assert_equal post.updated_at, post.info_from_last_update[:date] 1371 assert_equal post.updated_at, post.info_from_last_update[:date]
1389 assert_equal profile.name, post.info_from_last_update[:author_name] 1372 assert_equal profile.name, post.info_from_last_update[:author_name]
1390 assert_equal profile.url, post.info_from_last_update[:author_url] 1373 assert_equal profile.url, post.info_from_last_update[:author_url]
@@ -1818,4 +1801,15 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1818,4 +1801,15 @@ class ArticleTest &lt; ActiveSupport::TestCase
1818 assert a1.errors.invalid?(:parent_id) 1801 assert a1.errors.invalid?(:parent_id)
1819 end 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 end 1815 end
test/unit/folder_helper_test.rb
@@ -33,7 +33,7 @@ class FolderHelperTest &lt; ActiveSupport::TestCase @@ -33,7 +33,7 @@ class FolderHelperTest &lt; ActiveSupport::TestCase
33 33
34 should 'display icon for type of article' do 34 should 'display icon for type of article' do
35 Article.expects(:icon_name).returns('article') 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 end 37 end
38 38
39 should 'list all the folder\'s children to the owner' do 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,17 +29,16 @@ class ForumHelperTest &lt; ActiveSupport::TestCase
29 end 29 end
30 30
31 should 'list posts with different classes' do 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 one_month_later = Time.now + 1.month 33 one_month_later = Time.now + 1.month
34 Time.stubs(:now).returns(one_month_later) 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 assert_match /forum-post position-1 first odd-post.*forum-post position-2 last not-published even-post/, list_forum_posts(forum.posts) 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 end 37 end
38 38
39 should 'return post update if it has no comments' do 39 should 'return post update if it has no comments' do
40 author = create_user('forum test author').person 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 assert some_post.comments.empty? 42 assert some_post.comments.empty?
44 out = last_topic_update(some_post) 43 out = last_topic_update(some_post)
45 assert_match some_post.updated_at.to_s, out 44 assert_match some_post.updated_at.to_s, out