Commit eafa036da33d503072710eae3e214f05b1bdee33

Authored by Rodrigo Souto
2 parents a752c502 9a1c00d4

Merge branch 'master' into api

Conflicts:
	lib/noosfero/plugin.rb
	test/unit/article_test.rb
	test/unit/person_test.rb
Showing 120 changed files with 1360 additions and 799 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 120 files displayed.

app/controllers/my_profile/cms_controller.rb
... ... @@ -105,6 +105,11 @@ class CmsController < MyProfileController
105 105 end
106 106 end
107 107 end
  108 +
  109 + unless @article.kind_of?(RssFeed)
  110 + @escaped_body = CGI::escapeHTML(@article.body || '')
  111 + @escaped_abstract = CGI::escapeHTML(@article.abstract || '')
  112 + end
108 113 end
109 114  
110 115 def new
... ...
app/controllers/my_profile/friends_controller.rb
1 1 class FriendsController < MyProfileController
2   -
  2 +
3 3 protect 'manage_friends', :profile
4   -
  4 +
5 5 def index
6   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  6 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
7 7 if is_cache_expired?(profile.manage_friends_cache_key(params))
8 8 @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage])
9 9 end
... ... @@ -18,7 +18,7 @@ class FriendsController &lt; MyProfileController
18 18 end
19 19  
20 20 def suggest
21   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  21 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
22 22 end
23 23  
24 24 def remove_suggestion
... ... @@ -26,13 +26,13 @@ class FriendsController &lt; MyProfileController
26 26 redirect_to :action => 'suggest' unless @person
27 27 if @person && request.post?
28 28 profile.remove_suggestion(@person)
29   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  29 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
30 30 render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :friends_suggestions, :per_page => params[:per_page] || per_page }
31 31 end
32 32 end
33 33  
34 34 def connections
35   - @suggestion = profile.profile_suggestions.of_person.enabled.find_by_suggestion_id(params[:id])
  35 + @suggestion = profile.suggested_profiles.of_person.enabled.find_by_suggestion_id(params[:id])
36 36 if @suggestion
37 37 @tags = @suggestion.tag_connections
38 38 @profiles = @suggestion.profile_connections
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -40,7 +40,7 @@ class MembershipsController &lt; MyProfileController
40 40 end
41 41  
42 42 def suggest
43   - @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(per_page)
  43 + @suggestions = profile.suggested_profiles.of_community.enabled.includes(:suggestion).limit(per_page)
44 44 end
45 45  
46 46 def remove_suggestion
... ... @@ -49,13 +49,13 @@ class MembershipsController &lt; MyProfileController
49 49 redirect_to :action => 'suggest' unless @community
50 50 if @community && request.post?
51 51 profile.remove_suggestion(@community)
52   - @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(custom_per_page)
  52 + @suggestions = profile.suggested_profiles.of_community.enabled.includes(:suggestion).limit(custom_per_page)
53 53 render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :communities_suggestions, :per_page => custom_per_page}
54 54 end
55 55 end
56 56  
57 57 def connections
58   - @suggestion = profile.profile_suggestions.of_community.enabled.find_by_suggestion_id(params[:id])
  58 + @suggestion = profile.suggested_profiles.of_community.enabled.find_by_suggestion_id(params[:id])
59 59 if @suggestion
60 60 @tags = @suggestion.tag_connections
61 61 @profiles = @suggestion.profile_connections
... ...
app/controllers/my_profile/tasks_controller.rb
1 1 class TasksController < MyProfileController
2 2  
3   - protect 'perform_task', :profile
  3 + protect [:perform_task, :view_tasks], :profile, :only => [:index]
  4 + protect :perform_task, :profile, :except => [:index]
4 5  
5 6 def index
6 7 @filter_type = params[:filter_type].presence
... ... @@ -15,6 +16,8 @@ class TasksController &lt; MyProfileController
15 16 @failed = params ? params[:failed] : {}
16 17  
17 18 @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization?
  19 +
  20 + @view_only = !current_person.has_permission?(:perform_task, profile)
18 21 end
19 22  
20 23 def processed
... ... @@ -46,7 +49,7 @@ class TasksController &lt; MyProfileController
46 49 task = profile.find_in_all_tasks(id)
47 50 begin
48 51 task.update_attributes(value[:task])
49   - task.send(decision)
  52 + task.send(decision, current_person)
50 53 rescue Exception => ex
51 54 message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
52 55 failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -11,6 +11,7 @@ class ContentViewerController &lt; ApplicationController
11 11 path = get_path(params[:page], params[:format])
12 12  
13 13 @version = params[:version].to_i
  14 + @npage = params[:npage] || '1'
14 15  
15 16 if path.blank?
16 17 @page = profile.home_page
... ... @@ -127,7 +128,7 @@ class ContentViewerController &lt; ApplicationController
127 128 end
128 129  
129 130 unless @page.display_to?(user)
130   - if !profile.visible? || profile.secret? || (user && user.follows?(profile))
  131 + if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank?
131 132 render_access_denied
132 133 else #!profile.public?
133 134 private_profile_partial_parameters
... ...
app/helpers/application_helper.rb
... ... @@ -1215,35 +1215,6 @@ module ApplicationHelper
1215 1215 list.sort.inject(Hash.new(0)){|h,i| h[i] += 1; h }.collect{ |x, n| [n, connector, x].join(" ") }.sort
1216 1216 end
1217 1217  
1218   - #FIXME Use time_ago_in_words instead of this method if you're using Rails 2.2+
1219   - def time_ago_as_sentence(from_time, include_seconds = false)
1220   - to_time = Time.now
1221   - from_time = Time.parse(from_time.to_s)
1222   - from_time = from_time.to_time if from_time.respond_to?(:to_time)
1223   - to_time = to_time.to_time if to_time.respond_to?(:to_time)
1224   - distance_in_minutes = (((to_time - from_time).abs)/60).round
1225   - distance_in_seconds = ((to_time - from_time).abs).round
1226   - case distance_in_minutes
1227   - when 0..1
1228   - return (distance_in_minutes == 0) ? _('less than a minute') : _('1 minute') unless include_seconds
1229   - case distance_in_seconds
1230   - when 0..4 then _('less than 5 seconds')
1231   - when 5..9 then _('less than 10 seconds')
1232   - when 10..19 then _('less than 20 seconds')
1233   - when 20..39 then _('half a minute')
1234   - when 40..59 then _('less than a minute')
1235   - else _('1 minute')
1236   - end
1237   -
1238   - when 2..44 then _('%{distance} minutes ago') % { :distance => distance_in_minutes }
1239   - when 45..89 then _('about 1 hour ago')
1240   - when 90..1439 then _('about %{distance} hours ago') % { :distance => (distance_in_minutes.to_f / 60.0).round }
1241   - when 1440..2879 then _('1 day ago')
1242   - when 2880..10079 then _('%{distance} days ago') % { :distance => (distance_in_minutes / 1440).round }
1243   - else show_time(from_time)
1244   - end
1245   - end
1246   -
1247 1218 def comment_balloon(options = {}, &block)
1248 1219 wrapper = content_tag(:div, capture(&block), :class => 'comment-balloon-content')
1249 1220 (1..8).to_a.reverse.each { |i| wrapper = content_tag(:div, wrapper, :class => "comment-wrapper-#{i}") }
... ...
app/helpers/blog_helper.rb
... ... @@ -22,7 +22,9 @@ module BlogHelper
22 22 :param_name => 'npage',
23 23 :previous_label => _('&laquo; Newer posts'),
24 24 :next_label => _('Older posts &raquo;'),
25   - :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
  25 + :params => {:action=>"view_page",
  26 + :page=>articles.first.parent.path.split('/'),
  27 + :controller=>"content_viewer"}
26 28 }) if articles.present? && conf[:paginate]
27 29 content = []
28 30 artic_len = articles.length
... ... @@ -44,7 +46,7 @@ module BlogHelper
44 46 end
45 47  
46 48 def display_post(article, format = 'full')
47   - no_comments = (format == 'full') ? false : true
  49 + no_comments = (format == 'full' || format == 'compact' ) ? false : true
48 50 title = article_title(article, :no_comments => no_comments)
49 51 method = "display_#{format.split('+')[0]}_format"
50 52 html = send(method, FilePresenter.for(article)).html_safe
... ... @@ -55,8 +57,12 @@ module BlogHelper
55 57 else
56 58 '<div class="post-pic" style="background-image:url('+img+')"></div>'
57 59 end
58   - end.to_s +
59   - title + html
  60 + end.to_s + title + html
  61 + end
  62 +
  63 + def display_compact_format(article)
  64 + render :file => 'content_viewer/_display_compact_format',
  65 + :locals => { :article => article, :format => "compact" }
60 66 end
61 67  
62 68 def display_full_format(article)
... ...
app/helpers/comment_helper.rb
1 1 module CommentHelper
  2 + include DatesHelper
2 3  
3 4 def article_title(article, args = {})
4 5 title = article.title
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -2,6 +2,7 @@ module ContentViewerHelper
2 2  
3 3 include BlogHelper
4 4 include ForumHelper
  5 + include DatesHelper
5 6  
6 7 def display_number_of_comments(n)
7 8 base_str = "<span class='comment-count hide'>#{n}</span>"
... ... @@ -24,8 +25,9 @@ module ContentViewerHelper
24 25 unless args[:no_comments] || !article.accept_comments
25 26 comments = (" - %s") % link_to_comments(article)
26 27 end
  28 + date_format = show_with_right_format_date article
27 29 title << content_tag('span',
28   - content_tag('span', show_date(article.published_at), :class => 'date') +
  30 + date_format +
29 31 content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') +
30 32 content_tag('span', comments, :class => 'comments'),
31 33 :class => 'created-at'
... ... @@ -34,6 +36,24 @@ module ContentViewerHelper
34 36 title
35 37 end
36 38  
  39 + def show_with_right_format_date article
  40 + date_format = article.environment.date_format
  41 + use_numbers = false
  42 + year = true
  43 + left_time = false
  44 + if date_format == 'numbers_with_year'
  45 + use_numbers = true
  46 + elsif date_format == 'numbers'
  47 + use_numbers = true
  48 + year = false
  49 + elsif date_format == 'month_name'
  50 + year = false
  51 + elsif date_format == 'past_time'
  52 + left_time = true
  53 + end
  54 + content_tag('span', show_date(article.published_at, use_numbers , year, left_time), :class => 'date')
  55 + end
  56 +
37 57 def link_to_comments(article, args = {})
38 58 return '' unless article.accept_comments?
39 59 reference_to_article number_of_comments(article), article, 'comments_list'
... ...
app/helpers/dates_helper.rb
... ... @@ -2,6 +2,7 @@ require &#39;noosfero/i18n&#39;
2 2  
3 3 module DatesHelper
4 4  
  5 + include ActionView::Helpers::DateHelper
5 6 def months
6 7 I18n.t('date.month_names')
7 8 end
... ... @@ -15,10 +16,12 @@ module DatesHelper
15 16 end
16 17  
17 18 # formats a date for displaying.
18   - def show_date(date, use_numbers = false, year=true)
  19 + def show_date(date, use_numbers = false, year = true, left_time = false)
19 20 if date && use_numbers
20 21 date_format = year ? _('%{month}/%{day}/%{year}') : _('%{month}/%{day}')
21 22 date_format % { :day => date.day, :month => date.month, :year => date.year }
  23 + elsif date && left_time
  24 + date_format = time_ago_in_words(date)
22 25 elsif date
23 26 date_format = year ? _('%{month_name} %{day}, %{year}') : _('%{month_name} %{day}')
24 27 date_format % { :day => date.day, :month_name => month_name(date.month), :year => date.year }
... ...
app/helpers/events_helper.rb
1 1 module EventsHelper
2 2  
  3 + include DatesHelper
3 4 def list_events(date, events)
4 5 title = _('Events for %s') % show_date_month(date)
5 6 content_tag('h2', title) +
... ...
app/helpers/folder_helper.rb
... ... @@ -25,49 +25,32 @@ module FolderHelper
25 25 articles.select {|article| article.display_to?(user)}
26 26 end
27 27  
28   - def display_content_in_listing(configure={})
29   - recursive = configure[:recursive] || false
30   - list_type = configure[:list_type] || :folder
31   - level = configure[:level] || 0
32   - content = FilePresenter.for configure[:content]
  28 + def display_content_icon(content_item)
  29 + content = FilePresenter.for content_item
33 30 content_link = if content.image?
34   - link_to('&nbsp;' * (level * 4) +
35   - image_tag(icon_for_article(content)) + short_filename(content.name),
  31 + link_to(
  32 + image_tag(icon_for_article(content, :bigicon)),
36 33 content.url.merge(:view => true)
37 34 )
38 35 else
39   - link_to('&nbsp;' * (level * 4) +
40   - short_filename(content.name),
41   - content.url.merge(:view => true), :class => icon_for_article(content)
  36 + link_to('',
  37 + content.url.merge(:view => true),
  38 + :class => icon_for_article(content, :bigicon)
42 39 )
43 40 end
44   - result = content_tag(
45   - 'tr',
46   - content_tag('td', content_link ) +
47   - content_tag('td', show_date(content.updated_at), :class => 'last-update'),
48   - :class => "#{list_type}-item"
49   - )
50   - if recursive
51   - result + content.children.map {|item|
52   - display_content_in_listing :content=>item, :recursive=>recursive,
53   - :list_type=>list_type, :level=>level+1
54   - }.join("\n")
55   - else
56   - result
57   - end
58 41 end
59 42  
60   - def icon_for_article(article)
  43 + def icon_for_article(article, size = 'icon')
61 44 article = FilePresenter.for article
62   - icon = article.respond_to?(:icon_name) ?
63   - article.icon_name :
64   - article.class.icon_name(article)
65   - if (icon =~ /\//)
66   - icon
  45 + if article.respond_to?(:sized_icon)
  46 + article.sized_icon(size)
67 47 else
68   - klasses = 'icon ' + [icon].flatten.map{|name| 'icon-'+name}.join(' ')
  48 + icon = article.respond_to?(:icon_name) ?
  49 + article.icon_name :
  50 + article.class.icon_name(article)
  51 + klasses = "#{size} " + [icon].flatten.map{|name| "#{size}-"+name}.join(' ')
69 52 if article.kind_of?(UploadedFile) || article.kind_of?(FilePresenter)
70   - klasses += ' icon-upload-file'
  53 + klasses += " #{size}-upload-file"
71 54 end
72 55 klasses
73 56 end
... ...
app/helpers/forum_helper.rb
1 1 module ForumHelper
  2 + include ActionView::Helpers::DateHelper
2 3  
3 4 def cms_label_for_new_children
4 5 _('New discussion topic')
... ... @@ -42,9 +43,9 @@ module ForumHelper
42 43 def last_topic_update(article)
43 44 info = article.info_from_last_update
44 45 if info[:author_url]
45   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
  46 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
46 47 else
47   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
  48 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
48 49 end
49 50 end
50 51  
... ...
app/models/add_friend.rb
... ... @@ -54,7 +54,7 @@ class AddFriend &lt; Task
54 54 end
55 55  
56 56 def remove_from_suggestion_list(task)
57   - suggestion = task.requestor.profile_suggestions.find_by_suggestion_id task.target.id
  57 + suggestion = task.requestor.suggested_profiles.find_by_suggestion_id task.target.id
58 58 suggestion.disable if suggestion
59 59 end
60 60 end
... ...
app/models/article.rb
... ... @@ -28,7 +28,7 @@ class Article &lt; ActiveRecord::Base
28 28 def initialize(*params)
29 29 super
30 30  
31   - if !params.blank? && params.first.has_key?(:profile)
  31 + if !params.blank? && params.first.has_key?(:profile) && !params.first[:profile].blank?
32 32 profile = params.first[:profile]
33 33 self.published = false unless profile.public?
34 34 end
... ... @@ -96,6 +96,8 @@ class Article &lt; ActiveRecord::Base
96 96 belongs_to :translation_of, :class_name => 'Article', :foreign_key => :translation_of_id
97 97 before_destroy :rotate_translations
98 98  
  99 + acts_as_voteable
  100 +
99 101 before_create do |article|
100 102 article.published_at ||= Time.now
101 103 if article.reference_article && !article.parent
... ...
app/models/blog.rb
... ... @@ -76,9 +76,12 @@ class Blog &lt; Folder
76 76 end
77 77  
78 78 settings_items :visualization_format, :type => :string, :default => 'full'
79   - validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format
  79 + validates_inclusion_of :visualization_format,
  80 + :in => [ 'full', 'short', 'short+pic', 'compact'],
  81 + :if => :visualization_format
80 82  
81   - settings_items :display_posts_in_current_language, :type => :boolean, :default => false
  83 + settings_items :display_posts_in_current_language,
  84 + :type => :boolean, :default => false
82 85  
83 86 alias :display_posts_in_current_language? :display_posts_in_current_language
84 87  
... ...
app/models/comment.rb
... ... @@ -39,6 +39,8 @@ class Comment &lt; ActiveRecord::Base
39 39  
40 40 xss_terminate :only => [ :body, :title, :name ], :on => 'validation'
41 41  
  42 + acts_as_voteable
  43 +
42 44 def comment_root
43 45 (reply_of && reply_of.comment_root) || self
44 46 end
... ...
app/models/environment.rb
... ... @@ -3,7 +3,17 @@
3 3 # domains.
4 4 class Environment < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body, :members_whitelist_enabled, :members_whitelist, :highlighted_news_amount, :portal_news_amount
  6 + attr_accessible :name, :is_default, :signup_welcome_text_subject,
  7 + :signup_welcome_text_body, :terms_of_use,
  8 + :message_for_disabled_enterprise, :news_amount_by_folder,
  9 + :default_language, :languages, :description,
  10 + :organization_approval_method, :enabled_plugins,
  11 + :enabled_features, :redirection_after_login,
  12 + :redirection_after_signup, :contact_email, :theme,
  13 + :reports_lower_bound, :noreply_email,
  14 + :signup_welcome_screen_body, :members_whitelist_enabled,
  15 + :members_whitelist, :highlighted_news_amount,
  16 + :portal_news_amount, :date_format
7 17  
8 18 has_many :users
9 19  
... ... @@ -14,6 +24,12 @@ class Environment &lt; ActiveRecord::Base
14 24  
15 25 IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
16 26  
  27 + validates_inclusion_of :date_format,
  28 + :in => [ 'numbers_with_year', 'numbers',
  29 + 'month_name_with_year', 'month_name',
  30 + 'past_time'],
  31 + :if => :date_format
  32 +
17 33 def self.verify_filename(filename)
18 34 filename += '.txt' if File.extname(filename) =~ IDENTIFY_SCRIPTS
19 35 filename
... ... @@ -75,7 +91,8 @@ class Environment &lt; ActiveRecord::Base
75 91 'edit_profile_design',
76 92 'manage_products',
77 93 'manage_friends',
78   - 'perform_task'
  94 + 'perform_task',
  95 + 'view_tasks'
79 96 ]
80 97 )
81 98 end
... ...
app/models/person.rb
... ... @@ -92,9 +92,9 @@ roles] }
92 92 has_and_belongs_to_many :acepted_forums, :class_name => 'Forum', :join_table => 'terms_forum_people'
93 93 has_and_belongs_to_many :articles_with_access, :class_name => 'Article', :join_table => 'article_privacy_exceptions'
94 94  
95   - has_many :profile_suggestions, :foreign_key => :person_id, :order => 'score DESC', :dependent => :destroy
96   - has_many :suggested_people, :through => :profile_suggestions, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Person', true]
97   - has_many :suggested_communities, :through => :profile_suggestions, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Community', true]
  95 + has_many :suggested_profiles, :class_name => 'ProfileSuggestion', :foreign_key => :person_id, :order => 'score DESC', :dependent => :destroy
  96 + has_many :suggested_people, :through => :suggested_profiles, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Person', true]
  97 + has_many :suggested_communities, :through => :suggested_profiles, :source => :suggestion, :conditions => ['profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Community', true]
98 98  
99 99 scope :more_popular, :order => 'friends_count DESC'
100 100  
... ... @@ -111,6 +111,8 @@ roles] }
111 111  
112 112 belongs_to :user, :dependent => :delete
113 113  
  114 + acts_as_voter
  115 +
114 116 def can_change_homepage?
115 117 !environment.enabled?('cant_change_homepage') || is_admin?
116 118 end
... ... @@ -535,7 +537,7 @@ roles] }
535 537 end
536 538  
537 539 def remove_suggestion(profile)
538   - suggestion = profile_suggestions.find_by_suggestion_id profile.id
  540 + suggestion = suggested_profiles.find_by_suggestion_id profile.id
539 541 suggestion.disable if suggestion
540 542 end
541 543  
... ...
app/models/profile.rb
... ... @@ -71,6 +71,7 @@ class Profile &lt; ActiveRecord::Base
71 71 'manage_friends' => N_('Manage friends'),
72 72 'validate_enterprise' => N_('Validate enterprise'),
73 73 'perform_task' => N_('Perform task'),
  74 + 'view_tasks' => N_('View tasks'),
74 75 'moderate_comments' => N_('Moderate comments'),
75 76 'edit_appearance' => N_('Edit appearance'),
76 77 'view_private_content' => N_('View private content'),
... ... @@ -969,19 +970,11 @@ private :generate_url, :url_options
969 970 self.save
970 971 end
971 972  
972   - def disabled?
973   - !visible
974   - end
975   -
976 973 def enable
977 974 self.visible = true
978 975 self.save
979 976 end
980 977  
981   - def enabled?
982   - visible
983   - end
984   -
985 978 def control_panel_settings_button
986 979 {:title => _('Edit Profile'), :icon => 'edit-profile'}
987 980 end
... ... @@ -1041,7 +1034,7 @@ private :generate_url, :url_options
1041 1034 end
1042 1035  
1043 1036 def remove_from_suggestion_list(person)
1044   - suggestion = person.profile_suggestions.find_by_suggestion_id self.id
  1037 + suggestion = person.suggested_profiles.find_by_suggestion_id self.id
1045 1038 suggestion.disable if suggestion
1046 1039 end
1047 1040  
... ...
app/models/profile_suggestion.rb
... ... @@ -113,14 +113,14 @@ class ProfileSuggestion &lt; ActiveRecord::Base
113 113 suggested_profiles = all_suggestions(person)
114 114 return if suggested_profiles.nil?
115 115  
116   - already_suggested_profiles = person.profile_suggestions.map(&:suggestion_id).join(',')
  116 + already_suggested_profiles = person.suggested_profiles.map(&:suggestion_id).join(',')
117 117 suggested_profiles = suggested_profiles.where("profiles.id NOT IN (#{already_suggested_profiles})") if already_suggested_profiles.present?
118 118 #TODO suggested_profiles = suggested_profiles.order('score DESC')
119 119 suggested_profiles = suggested_profiles.limit(N_SUGGESTIONS)
120 120 return if suggested_profiles.blank?
121 121  
122 122 suggested_profiles.each do |suggested_profile|
123   - suggestion = person.profile_suggestions.find_or_initialize_by_suggestion_id(suggested_profile.id)
  123 + suggestion = person.suggested_profiles.find_or_initialize_by_suggestion_id(suggested_profile.id)
124 124 RULES.each do |rule, options|
125 125 begin
126 126 value = suggested_profile.send("#{rule}_count").to_i
... ... @@ -273,7 +273,7 @@ class ProfileSuggestion &lt; ActiveRecord::Base
273 273 end
274 274  
275 275 def self.generate_profile_suggestions(person, force = false)
276   - return if person.profile_suggestions.enabled.count >= MIN_LIMIT && !force
  276 + return if person.suggested_profiles.enabled.count >= MIN_LIMIT && !force
277 277 Delayed::Job.enqueue ProfileSuggestionsJob.new(person.id) unless ProfileSuggestionsJob.exists?(person.id)
278 278 end
279 279  
... ...
app/models/task.rb
... ... @@ -34,6 +34,7 @@ class Task &lt; ActiveRecord::Base
34 34 belongs_to :requestor, :class_name => 'Profile', :foreign_key => :requestor_id
35 35 belongs_to :target, :foreign_key => :target_id, :polymorphic => true
36 36 belongs_to :responsible, :class_name => 'Person', :foreign_key => :responsible_id
  37 + belongs_to :closed_by, :class_name => 'Person', :foreign_key => :closed_by_id
37 38  
38 39 validates_uniqueness_of :code, :on => :create
39 40 validates_presence_of :code
... ... @@ -77,11 +78,9 @@ class Task &lt; ActiveRecord::Base
77 78 # this method finished the task. It calls #perform, which must be overriden
78 79 # by subclasses. At the end a message (as returned by #finish_message) is
79 80 # sent to the requestor with #notify_requestor.
80   - def finish
  81 + def finish(closed_by=nil)
81 82 transaction do
82   - self.status = Task::Status::FINISHED
83   - self.end_date = Time.now
84   - self.save!
  83 + close(Task::Status::FINISHED, closed_by)
85 84 self.perform
86 85 begin
87 86 send_notification(:finished)
... ... @@ -106,11 +105,9 @@ class Task &lt; ActiveRecord::Base
106 105  
107 106 # this method cancels the task. At the end a message (as returned by
108 107 # #cancel_message) is sent to the requestor with #notify_requestor.
109   - def cancel
  108 + def cancel(closed_by=nil)
110 109 transaction do
111   - self.status = Task::Status::CANCELLED
112   - self.end_date = Time.now
113   - self.save!
  110 + close(Task::Status::CANCELLED, closed_by)
114 111 begin
115 112 send_notification(:cancelled)
116 113 rescue NotImplementedError => ex
... ... @@ -119,6 +116,13 @@ class Task &lt; ActiveRecord::Base
119 116 end
120 117 end
121 118  
  119 + def close(status, closed_by)
  120 + self.status = status
  121 + self.end_date = Time.now
  122 + self.closed_by = closed_by
  123 + self.save!
  124 + end
  125 +
122 126 # Here are the tasks customizable options.
123 127  
124 128 def title
... ...
app/models/uploaded_file.rb
... ... @@ -65,7 +65,7 @@ class UploadedFile &lt; Article
65 65 # :min_size => 2.megabytes
66 66 # :max_size => 5.megabytes
67 67 has_attachment :storage => :file_system,
68   - :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
  68 + :thumbnails => { :icon => [24,24], :bigicon => [50,50], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
69 69 :thumbnail_class => Thumbnail,
70 70 :max_size => self.max_size
71 71  
... ...
app/presenters/image.rb
... ... @@ -4,6 +4,10 @@ class FilePresenter::Image &lt; FilePresenter
4 4 f.image? ? 10 : nil
5 5 end
6 6  
  7 + def sized_icon(size)
  8 + public_filename size
  9 + end
  10 +
7 11 def icon_name
8 12 public_filename :icon
9 13 end
... ...
app/views/admin_panel/_site_info.html.erb
... ... @@ -3,6 +3,21 @@
3 3 <%= labelled_form_field(_('No reply email'), text_field(:environment, :noreply_email)) %>
4 4 <% themes_options = Theme.system_themes.map {|theme| [theme.name, theme.id] }.sort %>
5 5 <%= labelled_form_field(_('Theme'), select(:environment, :theme, options_for_select(themes_options, environment.theme))) %>
  6 +
  7 +<%= labelled_form_field(
  8 + _("Article's date format"),
  9 + select(:environment, :date_format,
  10 + options_for_select([
  11 + [ _('mm/dd/yyyy'), 'numbers_with_year'],
  12 + [ _('mm/dd'), 'numbers'],
  13 + [ _('Month dd, yyyy'), 'month_name_with_year'],
  14 + [ _('Month dd'), 'month_name'],
  15 + [ _('X minutes/hours/days/months/years ago'), 'past_time']
  16 + ], environment.date_format
  17 + )
  18 + )
  19 +) %>
  20 +
6 21 <%= required f.text_field(:reports_lower_bound, :size => 3) %>
7 22 <%= labelled_form_field(_('Default language'), select(:environment, :default_language, environment.locales.invert, { :selected => environment.default_locale, :include_blank => true })) %>
8 23 <%= label_tag :languages, _('Available languages') %>
... ...
app/views/blocks/profile_info_actions/_common.html.erb
1 1 <li><%= report_abuse(profile, :button) %></li>
2   -<%= render_environment_features(:profile_actions) %></li>
  2 +<%= render_environment_features(:profile_actions) %>
... ...
app/views/box_organizer/edit.html.erb
... ... @@ -25,6 +25,7 @@
25 25 </div>
26 26 <div class="move-modes">
27 27 <%= labelled_form_field _('Move options:'), select_tag('block[move_modes]', options_from_collection_for_select(@block.move_block_options, :first, :last, @block.move_modes)) %>
  28 + </div>
28 29 <% end %>
29 30  
30 31 <% if @block.owner.kind_of?(Profile) && @block.owner.is_template? %>
... ...
app/views/cms/_blog.html.erb
... ... @@ -67,7 +67,8 @@
67 67 <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [
68 68 [ _('Full post'), 'full'],
69 69 [ _('First paragraph'), 'short'],
70   - [ _('First paragraph, with post picture'), 'short+pic']
  70 + [ _('First paragraph, with post picture'), 'short+pic'],
  71 + [ _("Title, Image, Lead"), 'compact']
71 72 ])) %>
72 73  
73 74 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %>
... ...
app/views/content_viewer/_article_toolbar.html.erb
... ... @@ -62,7 +62,7 @@
62 62 <% if @page.blog? and !@page.image.nil? %>
63 63 <div class="blog-cover"><%= image_tag(@page.image.public_filename())%></div>
64 64 <% end %>
65   - <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
  65 + <%= link_to(image_tag('/images/icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
66 66 <%= @plugins.dispatch(:article_header_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %>
67 67 <%= article_title(@page, :no_link => true) %>
68 68 <%= article_translations(@page) %>
... ...
app/views/content_viewer/_display_compact_format.html.erb 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<% if article.image %>
  2 + <% className = "article-compact-abstract-with-image" %>
  3 + <% if article.image.thumbnails_processed? %>
  4 + <% image_file = article.image.public_filename(:big) %>
  5 + <% else %>
  6 + <% image_file = "/images/icons-app/image-loading-thumb.png" %>
  7 + <% end %>
  8 +<% else %>
  9 + <% className = "article-compact-abstract" %>
  10 +<% end %>
  11 +
  12 +<div>
  13 + <% if article.image %>
  14 + <div class = "article-compact-image">
  15 + <%= image_tag(image_file) %>
  16 + </div>
  17 + <% end %>
  18 + <div class = <%= className %> >
  19 + <%= article.abstract.truncate(400) %>
  20 + </div>
  21 +</div>
... ...
app/views/content_viewer/blog_page.html.erb
... ... @@ -8,7 +8,7 @@
8 8 </div>
9 9 </div>
10 10 <hr class="pre-posts"/>
11   -<div class="blog-posts">
  11 +<div class="blog-posts page-<%= @npage %>">
12 12 <% paginate = true %>
13 13 <%=
14 14 posts = @posts
... ...
app/views/content_viewer/folder.html.erb
1 1 <% unless folder.body.blank? %>
2   - <div>
  2 + <div class="folder-description">
3 3 <%= folder.body %>
4 4 </div>
5   - <hr/>
6 5 <% end %>
7 6  
8 7 <% if folder.children.empty? %>
... ...
app/views/person_notifier/mailer/_comment.html.erb
... ... @@ -19,7 +19,7 @@
19 19 <span style="font-size: 12px;"><%= comment.title %></span><br/>
20 20 <% end %>
21 21 <span style="font-size: 10px;"><%= txt2html comment.body %></span><br/>
22   - <span style="font-size: 8px; color: #929292"><%= time_ago_as_sentence(comment.created_at) %></span>
  22 + <span style="font-size: 8px; color: #929292"><%= time_ago_in_words(comment.created_at) %></span>
23 23 <br style="clear: both;" />
24 24  
25 25 <% unless comment.replies.blank? %>
... ...
app/views/person_notifier/mailer/_create_article.html.erb
... ... @@ -6,7 +6,7 @@
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span>
8 8 <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span>
9   - <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  9 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span>
10 10 </p>
11 11 <p>
12 12 <span style="font-size: 14px;"><%= link_to(activity.params['name'], activity.params['url'], :style => "color: #333; font-weight: bold; text-decoration: none;") %></span>
... ...
app/views/person_notifier/mailer/_default_activity.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <td>
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
8   - <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_in_words(activity.created_at) %></span>
9 9 </p>
10 10 </td>
11 11 </tr>
... ...
app/views/person_notifier/mailer/_task.html.erb
... ... @@ -12,7 +12,7 @@
12 12 <span style="font-size: 14px">
13 13 <%= task_information(task) %>
14 14 </span>
15   - <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_as_sentence(task.created_at) %></span>
  15 + <span style="font-size: 10px; color: #929292; float: right;"><%= time_ago_in_words(task.created_at) %></span>
16 16 </div>
17 17 </td>
18 18 </tr>
... ...
app/views/person_notifier/mailer/_upload_image.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <td>
6 6 <p>
7 7 <span style="font-size: 14px;"><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></span>
8   - <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_as_sentence(activity.created_at) %></span>
  8 + <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span>
9 9 </p>
10 10 </td>
11 11 </tr>
... ...
app/views/profile/_comment.html.erb
... ... @@ -40,7 +40,7 @@
40 40 <%= txt2html comment.body %>
41 41 </div>
42 42 <div class="profile-activity-time">
43   - <%= time_ago_as_sentence(comment.created_at) %>
  43 + <%= time_ago_in_words(comment.created_at) %>
44 44 </div>
45 45 </div>
46 46  
... ...
app/views/profile/_create_article.html.erb
... ... @@ -12,7 +12,7 @@
12 12 <%= image_tag(activity.params['first_image']) unless activity.params['first_image'].blank? %><%= strip_tags(truncate(activity.params['lead'], :length => 1000, :ommision => '...')).gsub(/(\xC2\xA0|\s)+/, ' ').gsub(/^\s+/, '') unless activity.params['lead'].blank? %> <small><%= link_to(_('See more'), activity.params['url']) unless activity.get_lead.blank? %></small>
13 13 </div>
14 14 <%= content_tag(:p, link_to(_('See complete forum'), activity.get_url), :class => 'see-forum') if activity.target.is_a?(Forum) %>
15   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  15 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
16 16 <div class='profile-wall-actions'>
17 17 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
18 18 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :only_hide => true, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
... ...
app/views/profile/_default_activity.html.erb
... ... @@ -3,7 +3,7 @@
3 3 </div>
4 4 <div class='profile-activity-description'>
5 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  6 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
7 7 <div class='profile-wall-actions'>
8 8 <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %>
9 9 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
... ...
app/views/profile/_leave_scrap.html.erb
... ... @@ -3,7 +3,7 @@
3 3 </div>
4 4 <div class='profile-activity-description'>
5 5 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
6   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  6 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
7 7 <div class='profile-wall-actions'>
8 8 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
9 9 </div>
... ...
app/views/profile/_profile_scrap.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
7 7 <p class='profile-activity-text'><%= txt2html scrap.content %></p>
8   - <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  8 + <p class='profile-activity-time'><%= time_ago_in_words(scrap.created_at) %></p>
9 9 <div class='profile-wall-actions'>
10 10 <% if logged_in? && current_person.follows?(scrap.sender) %>
11 11 <span class='profile-activity-send-reply'>
... ... @@ -22,5 +22,5 @@
22 22 <% end %>
23 23 </ul>
24 24 <%= render :partial => 'profile_scrap_reply_form', :locals => { :scrap => scrap } %>
25   - <hr />
  25 + <hr />
26 26 </li>
... ...
app/views/profile/_profile_scraps.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-sender'><%= link_to scrap.sender.name, scrap.sender.url %></p>
7 7 <p class='profile-activity-text'><%= txt2html scrap.content %></p>
8   - <p class='profile-activity-time'><%= time_ago_as_sentence(scrap.created_at) %></p>
  8 + <p class='profile-activity-time'><%= time_ago_in_words(scrap.created_at) %></p>
9 9 <div class='profile-wall-actions'>
10 10 <% if logged_in? && current_person.follows?(scrap.sender) %>
11 11 <span class='profile-activity-send-reply'>
... ...
app/views/profile/_upload_image.html.erb
... ... @@ -4,7 +4,7 @@
4 4 </div>
5 5 <div class='profile-activity-description'>
6 6 <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p>
7   - <p class='profile-activity-time'><%= time_ago_as_sentence(activity.created_at) %></p>
  7 + <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p>
8 8 <div class='profile-wall-actions'>
9 9 <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %>
10 10 </div>
... ...
app/views/profile/content_tagged.html.erb
... ... @@ -5,7 +5,7 @@
5 5 <h1><%= _('Content tagged with "%s"') % escaped_tag %></h1>
6 6  
7 7 <p>
8   -<%= link_to image_tag('icons-mime/rss-feed.png', :alt => _('Feed for this tag'), :title => _('Feed for this tag')), tag_feed_path, :class => 'blog-feed-link'%>
  8 +<%= link_to image_tag('/images/icons-mime/rss-feed.png', :alt => _('Feed for this tag'), :title => _('Feed for this tag')), tag_feed_path, :class => 'blog-feed-link'%>
9 9 </p>
10 10  
11 11 <% cache_timeout(@tag_cache_key, 4.hour) do %>
... ...
app/views/shared/_content_item.html.erb 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +<div id="list-item">
  2 + <div class="item-info">
  3 + <div class="item-icon" >
  4 + <%= display_content_icon(content) %>
  5 + </div>
  6 + <span class="item-description">
  7 + <%= link_to(short_filename_upper_ext(content.name), content.url) %>
  8 + </span>
  9 + <span class="item-date"><%= _("Published at: #{show_date(content.updated_at)}") %></span>
  10 + </div>
  11 +</div>
0 12 \ No newline at end of file
... ...
app/views/shared/_lead_and_body.html.erb
... ... @@ -19,17 +19,27 @@
19 19  
20 20 <div class='article-lead' id="article-lead-<%=lead_id.to_s%>">
21 21  
  22 + <% abstract_options = {:style => 'width: 100%; height: 200px;', :class => editor_type} %>
22 23 <% if f %>
23   - <%= labelled_form_field(_(abstract_label), f.text_area(abstract_method, :style => 'width: 100%; height: 200px;', :class => editor_type)) %>
  24 + <%= labelled_form_field(_(abstract_label), f.text_area(abstract_method, abstract_options)) %>
24 25 <% else %>
25   - <%= labelled_form_field(_(abstract_label), text_area(object, abstract_method, :style => 'width: 100%; height: 200px;', :class => editor_type)) %>
  26 + <% if @article.kind_of?(Article) %>
  27 + <%= labelled_form_field(_(abstract_label), text_area_tag("article[abstract]", @escaped_abstract, abstract_options)) %>
  28 + <% else %>
  29 + <%= labelled_form_field(_(abstract_label), text_area(object, abstract_method, abstract_options)) %>
  30 + <% end %>
26 31 <% end %>
27 32 </div>
28 33 <div style="margin-top: 10px;">
  34 + <% body_options = {:style => 'width: 100%; height: 400px;', :class => editor_type} %>
29 35 <% if f %>
30   - <%= labelled_form_field(_(body_label), f.text_area(body_method, :style => 'width: 100%; height: 400px;', :class => editor_type)) %>
  36 + <%= labelled_form_field(_(body_label), f.text_area(body_method, body_options)) %>
31 37 <% else %>
32   - <%= labelled_form_field(_(body_label), text_area(object, body_method, :style => 'width: 100%; height: 400px;', :class => editor_type)) %>
  38 + <% if @article.kind_of?(Article) %>
  39 + <%= labelled_form_field(_(body_label), text_area_tag("article[body]", @escaped_body, body_options)) %>
  40 + <% else %>
  41 + <%= labelled_form_field(_(body_label), text_area(object, body_method, body_options)) %>
  42 + <% end %>
33 43 <% end %>
34 44 </div>
35 45  
... ...
app/views/shared/content_list.html.erb
1   -<table class="<%= list_type %>-content">
2   - <tr>
3   - <th><%= _('Title') %></th>
4   - <th><%= _('Last update') %></th>
5   - </tr>
  1 +<ul class="<%= list_type %>-content">
6 2 <% contents.each do |content| %>
7   - <% if content.display_to?(user) %>
8   - <%= display_content_in_listing :content=>content, :list_type=>list_type, :recursive=>recursive %>
9   - <% end %>
  3 + <li class="<%= list_type %>-item">
  4 + <% if content.display_to?(user) %>
  5 + <%= render :partial => 'shared/content_item', :locals => { :content => content } %>
  6 + <% end %>
  7 + </li>
10 8 <% end %>
11   -</table>
  9 +</ul>
12 10  
13 11 <p><%= pagination_links contents, :param_name => 'npage', :page_links => true %></p>
... ...
app/views/tasks/_abuse_complaint_accept_details.html.erb
... ... @@ -2,7 +2,7 @@
2 2 <% task.abuse_reports.each do |abuse_report| %>
3 3 <div>
4 4 <strong style="word-wrap: break-word; display: block; padding-right: 40px">"<%= abuse_report.reason %>"</strong> <br />
5   - <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_as_sentence(abuse_report.created_at) }%></i> <br />
  5 + <i><%= _('Reported by %{reporter} %{time}.') % {:reporter => abuse_report.reporter.name, :time => time_ago_in_words(abuse_report.created_at) }%></i> <br />
6 6 <% if !abuse_report.content.blank? %>
7 7 <button class="display-abuse-report-details" data-report="<%=abuse_report.id%>"><%=_('View details')%></button>
8 8 <div style='display: none' id=<%= 'abuse-report-details-'+abuse_report.id.to_s %> class="abuse-report-details">
... ...
app/views/tasks/_task.html.erb
... ... @@ -2,7 +2,7 @@
2 2  
3 3 <%= render :partial => 'task_icon', :locals => {:task => task} %>
4 4  
5   - <% if profile.organization? && @responsible_candidates.present? %>
  5 + <% if !@view_only && profile.organization? && @responsible_candidates.present? %>
6 6 <div class="task_responsible">
7 7 <span class="label"><%= _('Assign to:') %></span>
8 8 <span>
... ... @@ -12,8 +12,16 @@
12 12 </div>
13 13 <% end %>
14 14  
  15 + <% if @view_only && task.responsible.present? %>
  16 + <div class="task_responsible">
  17 + <span class="label"><%= _('Assigned to:') %></span>
  18 + <span class="value"><%= task.responsible.name %></span>
  19 + </div>
  20 + <% end %>
  21 +
15 22 <div class="task_decisions">
16   - <%=
  23 + <% unless @view_only %>
  24 + <%=
17 25 labelled_radio_button(_("Accept"), "tasks[#{task.id}][decision]", 'finish', task.default_decision == 'accept',
18 26 :id => "decision-finish-#{task.id}",
19 27 :class => 'task_accept_radio',
... ... @@ -29,7 +37,8 @@
29 37 :class => 'task_skip_radio',
30 38 :disabled => task.skip_disabled?,
31 39 :task_id => "#{task.id}")
32   - %>
  40 + %>
  41 + <% end %>
33 42 </div><!-- class="task_decisions" -->
34 43  
35 44 <div class="task_date"><%= show_time(task.created_at) %></div>
... ...
app/views/tasks/index.html.erb
... ... @@ -46,36 +46,41 @@
46 46 </p>
47 47 <% else %>
48 48 <%= form_tag :action => 'close' do%>
49   - <% button_bar do %>
  49 + <% button_bar(:class => 'task-actions') do %>
50 50 <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
51 51 <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
52 52 <%= submit_button :save, _("Apply!") %>
53 53 <%= button(:edit, _('View processed tasks'), :action => 'processed') %>
54 54 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
55   - <% end %>
  55 + <% end unless @view_only %>
56 56  
57 57 <ul class='task-list'>
58   - <p>
59   - <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %>
60   - </p>
  58 + <% unless @view_only %>
  59 + <p>
  60 + <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "up-set-all-tasks-to") %>
  61 + </p>
  62 + <% end %>
61 63  
62 64 <div class="task_boxes">
63 65 <%= render :partial => 'task', :collection => @tasks %>
64 66 </div>
65   - <p>
66   - <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %>
67   - </p>
  67 +
  68 + <% unless @view_only %>
  69 + <p>
  70 + <%= labelled_select(_("Set all to: "), 'set-decisions', 'first', 'last', nil, [['',""],['accept',_("Accept")],['reject',_("Reject")],['skip',_("Skip")]], :id => "down-set-all-tasks-to") %>
  71 + </p>
  72 + <% end %>
68 73 </ul>
69 74  
70 75 <%= pagination_links(@tasks)%>
71 76  
72   - <% button_bar do %>
  77 + <% button_bar(:class => 'task-actions') do %>
73 78 <%# FiXME button(:edit, _('View my requests'), :action => 'list_requested') %>
74 79 <%# FIXME button('menu-mail', _('Send request'), :action => 'new') %>
75 80 <%= submit_button :save, _("Apply!") %>
76 81 <%= button(:edit, _('View processed tasks'), :action => 'processed') %>
77 82 <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %>
78   - <% end %>
  83 + <% end unless @view_only %>
79 84 <% end %>
80 85 <% end %>
81 86 </p>
... ...
config/initializers/delayed_job_config.rb
... ... @@ -23,3 +23,13 @@ end
23 23 # end
24 24 # alias_method_chain :handle_failed_job, :loggin
25 25 #end
  26 +
  27 +# Chain delayed job's handle_failed_job method to do exception notification
  28 +Delayed::Worker.class_eval do
  29 + def handle_failed_job_with_notification job, error
  30 + handle_failed_job_without_notification job, error
  31 + ExceptionNotifier.notify_exception error, exception_recipients: NOOSFERO_CONF['exception_recipients'],
  32 + data: {job: job, handler: job.handler} rescue nil
  33 + end
  34 + alias_method_chain :handle_failed_job, :notification
  35 +end
... ...
config/initializers/noosfero_extensions.rb
1 1 require 'noosfero/role_assignment_ext'
2 2 require 'noosfero/action_tracker_ext'
  3 +require 'noosfero/vote_ext'
... ...
db/migrate/20150423203352_fix_tags_case_differences.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class FixTagsCaseDifferences < ActiveRecord::Migration
  2 + def up
  3 + tags = ActsAsTaggableOn::Tag.joins('LEFT JOIN tags as b on LOWER(tags.name) = b.name').where('b.id is null')
  4 + tags.find_each do |tag|
  5 + unless ActsAsTaggableOn::Tag.exists?(:name => tag.name.mb_chars.downcase)
  6 + ActsAsTaggableOn::Tag.create(:name => tag.name.mb_chars.downcase)
  7 + end
  8 + end
  9 +
  10 + execute("UPDATE taggings SET tag_id = new.id FROM taggings AS t INNER JOIN tags AS old ON t.tag_id = old.id INNER JOIN tags AS new ON LOWER(old.name) = new.name WHERE old.id != new.id AND taggings.id = t.id")
  11 +
  12 + execute("UPDATE tags SET taggings_count = (SELECT COUNT(*) FROM taggings WHERE taggings.tag_id = tags.id)")
  13 + execute("DELETE FROM tags WHERE taggings_count = 0")
  14 + end
  15 +
  16 + def down
  17 + say 'This migration is irreversible.'
  18 + end
  19 +end
... ...
db/migrate/20150507204849_remove_broken_profile_suggestions.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class RemoveBrokenProfileSuggestions < ActiveRecord::Migration
  2 + def up
  3 + execute("DELETE FROM profile_suggestions WHERE suggestion_id NOT IN (SELECT id from profiles)")
  4 + end
  5 +
  6 + def down
  7 + say "this migration can't be reverted"
  8 + end
  9 +end
... ...
db/migrate/20150529180110_add_date_format_to_environment.rb 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +class AddDateFormatToEnvironment < ActiveRecord::Migration
  2 + def up
  3 + add_column :environments, :date_format, :string, :default => 'month_name_with_year'
  4 + end
  5 +
  6 + def down
  7 + remove_column :environments, :date_format
  8 + end
  9 +end
... ...
db/migrate/20150602142030_add_closed_by_to_task.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +class AddClosedByToTask < ActiveRecord::Migration
  2 +
  3 + def change
  4 + add_column :tasks, :closed_by_id, :integer
  5 + end
  6 +
  7 +end
... ...
db/schema.rb
... ... @@ -11,7 +11,7 @@
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13  
14   -ActiveRecord::Schema.define(:version => 20150525101430) do
  14 +ActiveRecord::Schema.define(:version => 20150602142030) do
15 15  
16 16 create_table "abuse_reports", :force => true do |t|
17 17 t.integer "reporter_id"
... ... @@ -320,17 +320,18 @@ ActiveRecord::Schema.define(:version =&gt; 20150525101430) do
320 320 t.text "design_data"
321 321 t.text "custom_header"
322 322 t.text "custom_footer"
323   - t.string "theme", :default => "default", :null => false
  323 + t.string "theme", :default => "default", :null => false
324 324 t.text "terms_of_use_acceptance_text"
325 325 t.datetime "created_at"
326 326 t.datetime "updated_at"
327   - t.integer "reports_lower_bound", :default => 0, :null => false
  327 + t.integer "reports_lower_bound", :default => 0, :null => false
328 328 t.string "redirection_after_login", :default => "keep_on_same_page"
329 329 t.text "signup_welcome_text"
330 330 t.string "languages"
331 331 t.string "default_language"
332 332 t.string "noreply_email"
333 333 t.string "redirection_after_signup", :default => "keep_on_same_page"
  334 + t.string "date_format", :default => "month_name_with_year"
334 335 end
335 336  
336 337 create_table "external_feeds", :force => true do |t|
... ... @@ -691,6 +692,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150525101430) do
691 692 t.integer "image_id"
692 693 t.boolean "spam", :default => false
693 694 t.integer "responsible_id"
  695 + t.integer "closed_by_id"
694 696 end
695 697  
696 698 add_index "tasks", ["requestor_id"], :name => "index_tasks_on_requestor_id"
... ...
features/approve_article.feature
... ... @@ -62,7 +62,8 @@ Feature: approve article
62 62 And I press "Spread this"
63 63 And I follow "Delete"
64 64 And I confirm the browser dialog
65   - When I am logged in as "joaosilva"
  65 + And I follow "Logout"
  66 + And I am logged in as "joaosilva"
66 67 And I go to sample-community's control panel
67 68 And I follow "Process requests"
68 69 And I choose "Reject"
... ...
features/balloon.feature
... ... @@ -41,19 +41,19 @@ Feature: balloon
41 41 @selenium
42 42 Scenario: I should not see trigger if not enabled on page
43 43 Given feature "show_balloon_with_profile_links_when_clicked" is disabled on environment
44   - When I go to /assets/people
  44 + When I go to /search/people
45 45 Then I should not see "Profile links"
46 46  
47 47 @selenium
48 48 Scenario: I should not see trigger by default on page
49 49 Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment
50   - When I go to /assets/communities
  50 + When I go to /search/communities
51 51 Then I should not see "Members"
52 52  
53 53 @selenium
54 54 Scenario: I should see balloon when clicked on page trigger
55 55 Given feature "show_balloon_with_profile_links_when_clicked" is enabled on environment
56   - And I go to /assets/communities
  56 + And I go to /search/communities
57 57 And display ".community-trigger"
58 58 When I follow "Profile links"
59 59 Then I should see "Members"
... ...
features/browse_enterprises.feature
... ... @@ -13,20 +13,20 @@ Scenario: show all enterprises
13 13 Given the following enterprises
14 14 | identifier | name |
15 15 | shop2 | Fruits Shop |
16   - Given I am on /assets/enterprises
  16 + Given I am on /search/enterprises
17 17 Then I should see "Enterprises"
18 18 And I should see "Shoes Shop"
19 19 And I should see "Fruits Shop"
20 20  
21 21 Scenario: show profile links button
22   - Given I am on /assets/enterprises
  22 + Given I am on /search/enterprises
23 23 Then I should see "Profile links" within "a.enterprise-trigger"
24 24 And I should not see "Members"
25 25 And I should not see "Agenda"
26 26  
27 27 @selenium-fixme
28 28 Scenario: show profile links when clicked
29   - Given I am on /assets/enterprises
  29 + Given I am on /search/enterprises
30 30 When I follow "Profile links"
31 31 Then I should see "Products" within "ul.menu-submenu-list"
32 32 And I should see "Members" within "ul.menu-submenu-list"
... ... @@ -34,7 +34,7 @@ Scenario: show profile links when clicked
34 34  
35 35 @selenium-fixme
36 36 Scenario: go to catalog when click on products link
37   - Given I am on /assets/enterprises
  37 + Given I am on /search/enterprises
38 38 When I follow "Profile links"
39 39 And I follow "Products" and wait
40 40 Then I should be exactly on /catalog/shop1
... ...
features/change_appearance.feature
... ... @@ -14,7 +14,7 @@ Feature: Change appearance
14 14 And I should not see an element ".box-4"
15 15 And I go to joaosilva's control panel
16 16 And I follow "Edit Appearance"
17   - And I follow "Left Top and Right"
  17 + And I follow "Top and Side Bars"
18 18 And I go to joaosilva's control panel
19 19 And I follow "Edit sideboxes"
20 20 And I should see an element ".box-4"
... ...
features/events.feature
... ... @@ -17,7 +17,7 @@ Feature: events
17 17 Then I should see "November 2009" within ".current-month"
18 18  
19 19 Scenario: go to next month in global agenda
20   - Given I am on /assets/events?year=2009&month=11
  20 + Given I am on /search/events?year=2009&month=11
21 21 When I follow "December"
22 22 Then I should see "December 2009" within ".current-month"
23 23  
... ... @@ -27,7 +27,7 @@ Feature: events
27 27 Then I should see "September 2009" within ".current-month"
28 28  
29 29 Scenario: go to previous month in global agenda
30   - Given I am on /assets/events?year=2009&month=11
  30 + Given I am on /search/events?year=2009&month=11
31 31 When I follow "October"
32 32 Then I should see "October 2009" within ".current-month"
33 33  
... ... @@ -43,7 +43,7 @@ Feature: events
43 43  
44 44 Scenario: go to specific day in global agenda
45 45 Given I am on the homepage
46   - When I am on /assets/events?year=2009&month=11&day=12
  46 + When I am on /search/events?year=2009&month=11&day=12
47 47 Then I should see "Events for November, 2009"
48 48  
49 49 Scenario: list events for specific day
... ... @@ -88,7 +88,7 @@ Feature: events
88 88 And the following events
89 89 | owner | name | start_date |
90 90 | josemanuel | Manuel Birthday | 2009-10-24 |
91   - When I am on /assets/events?year=2009&month=10&day=24
  91 + When I am on /search/events?year=2009&month=10&day=24
92 92 Then I should see "Another Conference"
93 93 And I should see "Manuel Birthday"
94 94  
... ... @@ -157,7 +157,7 @@ Feature: events
157 157 Then I should not see "New events" link
158 158  
159 159 Scenario: display environment name in global agenda
160   - When I am on /assets/events
  160 + When I am on /search/events
161 161 Then I should see "Colivre.net's Events"
162 162  
163 163 @selenium
... ...
features/profile_domain.feature
... ... @@ -21,9 +21,7 @@ Feature: domain for profile
21 21 Scenario: access profile control panel through profile blocks
22 22 Given I am logged in as "joaosilva"
23 23 When I go to joaosilva's homepage
24   - And I follow "Control panel" within ".profile-info-block"
25   - Then I should see "Joao Silva" within "span.control-panel-title"
26   - When I follow "Control panel" within ".profile-image-block"
  24 + And I follow "Control panel" within ".profile-image-block"
27 25 Then I should see "Joao Silva" within "span.control-panel-title"
28 26  
29 27 @selenium
... ...
features/profile_search.feature
... ... @@ -36,7 +36,7 @@ Feature: search inside a profile
36 36 | joaosilva | ProfileSearchBlock |
37 37 When I go to joaosilva's profile
38 38 And I fill in "q" with "bees" within ".profile-search-block"
39   - And I press "Search"
  39 + And I press "Search" within ".profile-search-block"
40 40 Then I should see "bees and butterflies" within ".main-block"
41 41  
42 42 Scenario: not display unpublished articles
... ...
features/register_enterprise.feature
... ... @@ -203,5 +203,5 @@ Feature: register enterprise
203 203  
204 204 Scenario: a user cant see button to register new enterprise if enterprise_registration disabled
205 205 Given feature "enterprise_registration" is disabled on environment
206   - When I am on /assets/enterprises
  206 + When I am on /search/enterprises
207 207 Then I should not see "New enterprise" link
... ...
features/search_enterprises.feature
... ... @@ -56,7 +56,7 @@ Feature: search enterprises
56 56 | owner | name | body | homepage |
57 57 | shop1 | Shoes home | This is the <i>homepage</i> of Shoes shop! It has a very long and pretty vague description, just so we can test wether the system will correctly create an excerpt of this text. We should probably talk about shoes. | true |
58 58 When I search enterprises for "shoes"
59   - And I choose the search filter "Full"
  59 + And I select "Full" from "display"
60 60 Then I should see "This is the homepage of" within ".search-enterprise-description"
61 61 And I should see "about sho..." within ".search-enterprise-description"
62 62  
... ... @@ -66,7 +66,7 @@ Feature: search enterprises
66 66 | identifier | name | description |
67 67 | shop4 | Clothes shop | This <b>clothes</b> shop also sells shoes! This too has a very long and pretty vague description, just so we can test wether the system will correctly create an excerpt of this text. Clothes are a really important part of our lives. |
68 68 When I search enterprises for "clothes"
69   - And I choose the search filter "Full"
  69 + And I select "Full" from "display"
70 70 And I should see "This clothes shop" within ".search-enterprise-description"
71 71 And I should see "really import..." within ".search-enterprise-description"
72 72  
... ...
features/step_definitions/noosfero_steps.rb
... ... @@ -94,7 +94,7 @@ Given /^the following blocks$/ do |table|
94 94 owner.boxes<< Box.new
95 95 owner.boxes.first.blocks << MainBlock.new
96 96 end
97   - box = owner.boxes.where(:position => 3).first
  97 + box = owner.boxes.first
98 98 klass.constantize.create!(item.merge(:box => box))
99 99 end
100 100 end
... ...
features/suggest_article.feature
... ... @@ -14,9 +14,12 @@ Feature: suggest article
14 14  
15 15 @selenium
16 16 Scenario: highlight an article before approval of a suggested article
17   - Given someone suggested the following article to be published
18   - | target | article_name | article_body | name | email |
19   - | sample-community | A suggested article | this is an article about whales | jose | jose@example.org |
  17 + Given I am on Sample Community's blog
  18 + And I follow "Suggest an article"
  19 + And I fill in "Title" with "Suggestion"
  20 + And I fill in "Your name" with "Some Guy"
  21 + And I fill in "Email" with "someguy@somewhere.com"
  22 + And I press "Save"
20 23 When I am logged in as "joaosilva"
21 24 And I go to sample-community's control panel
22 25 And I follow "Process requests"
... ...
lib/noosfero/plugin.rb
1 1 require_dependency 'noosfero'
  2 +require 'noosfero/plugin/parent_methods'
2 3  
3 4 class Noosfero::Plugin
4 5  
... ... @@ -14,13 +15,9 @@ class Noosfero::Plugin
14 15  
15 16 class << self
16 17  
17   - attr_writer :should_load
  18 + include Noosfero::Plugin::ParentMethods
18 19  
19   - # Called for each ActiveRecord class with parents
20   - # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix
21   - def table_name_prefix
22   - @table_name_prefix ||= "#{name.to_s.underscore}_"
23   - end
  20 + attr_writer :should_load
24 21  
25 22 def should_load
26 23 @should_load.nil? && true || @boot
... ... @@ -92,8 +89,14 @@ class Noosfero::Plugin
92 89 end
93 90 end
94 91  
95   - def load_plugin(plugin_name)
96   - (plugin_name.to_s.camelize + 'Plugin').constantize
  92 + def load_plugin_identifier identifier
  93 + klass = identifier.to_s.camelize.constantize
  94 + klass = klass.const_get :Base if klass.class == Module
  95 + klass
  96 + end
  97 +
  98 + def load_plugin public_name
  99 + load_plugin_identifier "#{public_name.to_s.camelize}Plugin"
97 100 end
98 101  
99 102 # This is a generic method that initialize any possible filter defined by a
... ... @@ -135,7 +138,7 @@ class Noosfero::Plugin
135 138 filters = [filters]
136 139 end
137 140 filters.each do |plugin_filter|
138   - filter_method = (plugin.name.underscore.gsub('/','_') + '_' + plugin_filter[:method_name]).to_sym
  141 + filter_method = "#{plugin.identifier}_#{plugin_filter[:method_name]}".to_sym
139 142 controller_class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {}))
140 143 controller_class.send(:define_method, filter_method) do
141 144 instance_exec(&plugin_filter[:block]) if environment.plugin_enabled?(plugin)
... ... @@ -167,44 +170,6 @@ class Noosfero::Plugin
167 170 def all
168 171 @all ||= available_plugins.map{ |dir| (File.basename(dir) + "_plugin").camelize }
169 172 end
170   -
171   - def public_name
172   - self.name.underscore.gsub('_plugin','')
173   - end
174   -
175   - def public_path file = '', relative=false
176   - File.join "#{if relative then '' else '/' end}plugins", public_name, file
177   - end
178   -
179   - def root_path
180   - Rails.root.join('plugins', public_name)
181   - end
182   -
183   - def view_path
184   - File.join(root_path,'views')
185   - end
186   -
187   - # Here the developer should specify the meta-informations that the plugin can
188   - # inform.
189   - def plugin_name
190   - self.name.underscore.humanize
191   - end
192   - def plugin_description
193   - _("No description informed.")
194   - end
195   -
196   - def admin_url
197   - {:controller => "#{name.underscore}_admin", :action => 'index'}
198   - end
199   -
200   - def has_admin_url?
201   - File.exists?(File.join(root_path, 'controllers', "#{name.underscore}_admin_controller.rb"))
202   - end
203   -
204   - # -> define grape class used to map resource api provided by the plugin
205   - def api_mount_points
206   - []
207   - end
208 173 end
209 174  
210 175 def expanded_template(file_path, locals = {})
... ...
lib/noosfero/plugin/manager.rb
... ... @@ -76,7 +76,7 @@ class Noosfero::Plugin::Manager
76 76  
77 77 def enabled_plugins
78 78 @enabled_plugins ||= (Noosfero::Plugin.all & environment.enabled_plugins).map do |plugin|
79   - plugin.constantize.new(context)
  79 + Noosfero::Plugin.load_plugin_identifier(plugin).new context
80 80 end
81 81 end
82 82  
... ...
lib/noosfero/plugin/parent_methods.rb 0 → 100644
... ... @@ -0,0 +1,67 @@
  1 +class Noosfero::Plugin
  2 +
  3 + # Plugins that are defined as modules should extend
  4 + # this module manually, for example:
  5 + # module MyPlugin
  6 + # extend Noosfero::Plugin::ParentMethods
  7 + # end
  8 + module ParentMethods
  9 +
  10 + def identifier
  11 + @identifier ||= (if self.parents.first.instance_of? Module then self.parents.first else self end).name.underscore
  12 + end
  13 +
  14 + def public_name
  15 + @public_name ||= self.identifier.gsub '_plugin', ''
  16 + end
  17 +
  18 + # Here the developer should specify the meta-informations that the plugin can
  19 + # inform.
  20 + def plugin_name
  21 + self.identifier.humanize
  22 + end
  23 + def plugin_description
  24 + _("No description informed.")
  25 + end
  26 +
  27 + # Called for each ActiveRecord model with parents
  28 + # See http://apidock.com/rails/ActiveRecord/ModelSchema/ClassMethods/full_table_name_prefix
  29 + def table_name_prefix
  30 + @table_name_prefix ||= "#{self.identifier}_"
  31 + end
  32 +
  33 + def public_path file = '', relative=false
  34 + File.join "#{if relative then '' else '/' end}plugins", public_name, file
  35 + end
  36 +
  37 + def root_path
  38 + Rails.root.join('plugins', public_name)
  39 + end
  40 +
  41 + def view_path
  42 + File.join(root_path,'views')
  43 + end
  44 +
  45 + def admin_url
  46 + {:controller => "#{self.identifier}_admin", :action => 'index'}
  47 + end
  48 +
  49 + def has_admin_url?
  50 + File.exists?(File.join(root_path, 'controllers', "#{self.identifier}_admin_controller.rb"))
  51 + end
  52 +
  53 + # -> define grape class used to map resource api provided by the plugin
  54 + def api_mount_points
  55 + []
  56 + end
  57 +
  58 + def controllers
  59 + @controllers ||= Dir.glob("#{self.root_path}/controllers/*/*").map do |controller_file|
  60 + next unless controller_file =~ /_controller.rb$/
  61 + controller = File.basename(controller_file).gsub(/.rb$/, '').camelize
  62 + end.compact
  63 + end
  64 +
  65 + end
  66 +
  67 +end
... ...
lib/noosfero/vote_ext.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +require_dependency 'models/vote'
  2 +
  3 +class Vote
  4 +
  5 + validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
  6 +
  7 +end
... ...
lib/short_filename.rb
1 1 module ShortFilename
2 2  
3 3 def short_filename(filename, limit_chars = 43)
4   - return filename if filename.size <= limit_chars
5 4 extname = File.extname(filename)
6 5 basename = File.basename(filename,extname)
  6 + return shrink(basename, extname, limit_chars) + extname
  7 + end
  8 +
  9 + def short_filename_upper_ext(filename, limit_chars = 43)
  10 + extname = File.extname(filename)
  11 + display_name = shrink(File.basename(filename, extname), extname, limit_chars)
  12 + return extname.present? ? (display_name + ' - ' + extname.upcase.delete(".")) : display_name
  13 + end
  14 +
  15 + def shrink(filename, extname, limit_chars)
  16 + return filename if filename.size <= limit_chars
7 17 str_complement = '(...)'
8   - return basename[0..(limit_chars - extname.size - str_complement.size - 1)] + str_complement + extname
  18 + return filename[0..(limit_chars - extname.size - str_complement.size - 1)] + str_complement
9 19 end
10 20  
11 21 end
... ...
plugins/comment_classification/views/comment_classification_plugin_myprofile/add_status.html.erb
... ... @@ -13,7 +13,7 @@
13 13 <ul>
14 14 <% @comment.comment_classification_plugin_comment_status_users.each do |relation| %>
15 15 <li>
16   - <%= _("<i>%{user}</i> added the status <i>%{status_name}</i> at <i>%{created_at}</i>.") % { :user => relation.profile.name, :status_name => relation.status.name, :created_at => time_ago_as_sentence(relation.created_at)} %>
  16 + <%= _("<i>%{user}</i> added the status <i>%{status_name}</i> at <i>%{created_at}</i>.") % { :user => relation.profile.name, :status_name => relation.status.name, :created_at => time_ago_in_words(relation.created_at)} %>
17 17 <% unless relation.reason.blank? %>
18 18 <p><%= _("<i>Reason:</i> %s") % relation.reason %></p>
19 19 <% end %>
... ...
plugins/custom_forms/views/custom_forms_plugin_profile/show.html.erb
... ... @@ -14,8 +14,8 @@
14 14  
15 15 <%= form_for :submission do |f| %>
16 16 <% if !user %>
17   - <%= required labelled_form_field _('Author name'), text_field_tag(:author_name, @submission.author_name) %>
18   - <%= required labelled_form_field _('Author email'), text_field_tag(:author_email, @submission.author_email) %>
  17 + <%= required labelled_form_field _('Name'), text_field_tag(:author_name, @submission.author_name) %>
  18 + <%= required labelled_form_field _('Email'), text_field_tag(:author_email, @submission.author_email) %>
19 19 <% end %>
20 20  
21 21 <%= render :partial => 'shared/form_submission', :locals => {:f => f} %>
... ...
plugins/metadata/lib/metadata_plugin.rb
... ... @@ -23,7 +23,7 @@ class MetadataPlugin &lt; Noosfero::Plugin
23 23 },
24 24 content_viewer: {
25 25 variable: proc do
26   - if profile and profile.home_page_id == @page.id
  26 + if profile and @page and profile.home_page_id == @page.id
27 27 @profile
28 28 elsif @page.respond_to? :encapsulated_file
29 29 @page.encapsulated_file
... ...
plugins/metadata/test/functional/content_viewer_controller_test.rb
... ... @@ -48,4 +48,13 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
48 48 assert_tag tag: 'meta', attributes: { property: 'og:image', content: /\/images\/x.png/ }
49 49 end
50 50  
  51 + should 'render not_found page properly' do
  52 + assert_equal false, Article.exists?(:slug => 'non-existing-page')
  53 + assert_nothing_raised do
  54 + get :view_page, profile: profile.identifier, page: [ 'non-existing-page' ]
  55 + assert_response 404 # not found
  56 + assert_template 'not_found'
  57 + end
  58 + end
  59 +
51 60 end
... ...
plugins/vote/lib/ext/article.rb
... ... @@ -1,7 +0,0 @@
1   -require_dependency 'article'
2   -
3   -class Article
4   -
5   - acts_as_voteable
6   -
7   -end
plugins/vote/lib/ext/comment.rb
... ... @@ -1,7 +0,0 @@
1   -require_dependency 'comment'
2   -
3   -class Comment
4   -
5   - acts_as_voteable
6   -
7   -end
plugins/vote/lib/ext/person.rb
... ... @@ -1,7 +0,0 @@
1   -require_dependency 'person'
2   -
3   -class Person
4   -
5   - acts_as_voter
6   -
7   -end
plugins/vote/lib/ext/vote.rb
... ... @@ -1,7 +0,0 @@
1   -require_dependency 'models/vote'
2   -
3   -class Vote
4   -
5   - validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id]
6   -
7   -end
plugins/vote/test/unit/article_test.rb
... ... @@ -1,24 +0,0 @@
1   -require 'test_helper'
2   -
3   -class ArticleTest < ActiveSupport::TestCase
4   -
5   - def setup
6   - @profile = create_user('testing').person
7   - end
8   -
9   - attr_reader :profile
10   -
11   - should 'vote in a article' do
12   - article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil)
13   - profile.vote(article, 5)
14   - assert_equal 1, article.voters_who_voted.length
15   - assert_equal 5, article.votes_total
16   - end
17   -
18   - should 'be able to remove a voted article' do
19   - article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil)
20   - profile.vote(article, 5)
21   - article.destroy
22   - end
23   -
24   -end
plugins/vote/test/unit/comment_test.rb
... ... @@ -1,59 +0,0 @@
1   -require 'test_helper'
2   -
3   -class CommentTest < ActiveSupport::TestCase
4   -
5   - should 'vote in a comment' do
6   - comment = create_comment
7   - person = create_user('voter').person
8   - person.vote(comment, 5)
9   - assert_equal 1, comment.voters_who_voted.length
10   - assert_equal 5, comment.votes_total
11   - end
12   -
13   - should 'like a comment' do
14   - comment = create_comment
15   - person = create_user('voter').person
16   - assert !comment.voted_by?(person, true)
17   - person.vote_for(comment)
18   - assert comment.voted_by?(person, true)
19   - assert !comment.voted_by?(person, false)
20   - end
21   -
22   - should 'count voters for' do
23   - comment = create_comment
24   - person = create_user('voter').person
25   - person2 = create_user('voter2').person
26   - person3 = create_user('voter3').person
27   - person.vote_for(comment)
28   - person2.vote_for(comment)
29   - person3.vote_against(comment)
30   - assert_equal 2, comment.votes_for
31   - end
32   -
33   - should 'count votes againts' do
34   - comment = create_comment
35   - person = create_user('voter').person
36   - person2 = create_user('voter2').person
37   - person3 = create_user('voter3').person
38   - person.vote_against(comment)
39   - person2.vote_against(comment)
40   - person3.vote_for(comment)
41   - assert_equal 2, comment.votes_against
42   - end
43   -
44   - should 'be able to remove a voted comment' do
45   - comment = create_comment
46   - person = create_user('voter').person
47   - person.vote(comment, 5)
48   - comment.destroy
49   - end
50   -
51   - private
52   -
53   - def create_comment(args = {})
54   - owner = create_user('testuser').person
55   - article = create(TextileArticle, :profile_id => owner.id)
56   - create(Comment, { :name => 'foo', :email => 'foo@example.com', :source => article }.merge(args))
57   - end
58   -
59   -end
plugins/vote/test/unit/person_test.rb
... ... @@ -1,134 +0,0 @@
1   -require 'test_helper'
2   -
3   -class PersonTest < ActiveSupport::TestCase
4   -
5   - should 'vote in a comment with value greater than 1' do
6   - comment = fast_create(Comment)
7   - person = fast_create(Person)
8   -
9   - person.vote(comment, 5)
10   - assert_equal 1, person.vote_count
11   - assert_equal 5, person.votes.first.vote
12   - assert person.voted_on?(comment)
13   - end
14   -
15   - should 'vote in a comment with value lesser than -1' do
16   - comment = fast_create(Comment)
17   - person = fast_create(Person)
18   -
19   - person.vote(comment, -5)
20   - assert_equal 1, person.vote_count
21   - assert_equal -5, person.votes.first.vote
22   - end
23   -
24   - should 'vote for a comment' do
25   - comment = fast_create(Comment)
26   - person = fast_create(Person)
27   -
28   - assert !person.voted_for?(comment)
29   - person.vote_for(comment)
30   - assert person.voted_for?(comment)
31   - assert !person.voted_against?(comment)
32   - end
33   -
34   - should 'vote against a comment' do
35   - comment = fast_create(Comment)
36   - person = fast_create(Person)
37   -
38   - assert !person.voted_against?(comment)
39   - person.vote_against(comment)
40   - assert !person.voted_for?(comment)
41   - assert person.voted_against?(comment)
42   - end
43   -
44   - should 'do not vote against a comment twice' do
45   - comment = fast_create(Comment)
46   - person = fast_create(Person)
47   -
48   - assert person.vote_against(comment)
49   - assert !person.vote_against(comment)
50   - end
51   -
52   - should 'do not vote for a comment twice' do
53   - comment = fast_create(Comment)
54   - person = fast_create(Person)
55   -
56   - assert person.vote_for(comment)
57   - assert !person.vote_for(comment)
58   - end
59   -
60   - should 'not vote against a voted for comment' do
61   - comment = fast_create(Comment)
62   - person = fast_create(Person)
63   -
64   - person.vote_for(comment)
65   - person.vote_against(comment)
66   - assert person.voted_for?(comment)
67   - assert !person.voted_against?(comment)
68   - end
69   -
70   - should 'not vote for a voted against comment' do
71   - comment = fast_create(Comment)
72   - person = fast_create(Person)
73   -
74   - person.vote_against(comment)
75   - person.vote_for(comment)
76   - assert !person.voted_for?(comment)
77   - assert person.voted_against?(comment)
78   - end
79   -
80   - should 'undo a vote for a comment' do
81   - comment = fast_create(Comment)
82   - person = fast_create(Person)
83   -
84   - person.vote_for(comment)
85   - assert person.voted_for?(comment)
86   - person.votes.for_voteable(comment).destroy_all
87   - assert !person.voted_for?(comment)
88   - end
89   -
90   - should 'count comments voted' do
91   - comment = fast_create(Comment)
92   - person = fast_create(Person)
93   -
94   - comment2 = fast_create(Comment)
95   - comment3 = fast_create(Comment)
96   - person.vote_for(comment)
97   - person.vote_for(comment2)
98   - person.vote_against(comment3)
99   - assert_equal 3, person.vote_count
100   - assert_equal 2, person.vote_count(true)
101   - assert_equal 1, person.vote_count(false)
102   - end
103   -
104   - should 'vote in a article with value greater than 1' do
105   - article = fast_create(Article)
106   - person = fast_create(Person)
107   -
108   - person.vote(article, 5)
109   - assert_equal 1, person.vote_count
110   - assert_equal 5, person.votes.first.vote
111   - assert person.voted_on?(article)
112   - end
113   -
114   - should 'vote for a article' do
115   - article = fast_create(Article)
116   - person = fast_create(Person)
117   -
118   - assert !person.voted_for?(article)
119   - person.vote_for(article)
120   - assert person.voted_for?(article)
121   - assert !person.voted_against?(article)
122   - end
123   -
124   - should 'vote against a article' do
125   - article = fast_create(Article)
126   - person = fast_create(Person)
127   -
128   - assert !person.voted_against?(article)
129   - person.vote_against(article)
130   - assert !person.voted_for?(article)
131   - assert person.voted_against?(article)
132   - end
133   -
134   -end
po/pt/noosfero.po
... ... @@ -13,10 +13,10 @@ msgid &quot;&quot;
13 13 msgstr ""
14 14 "Project-Id-Version: 1.1-166-gaf47713\n"
15 15 "POT-Creation-Date: 2015-06-01 17:26-0300\n"
16   -"PO-Revision-Date: 2015-03-29 01:47+0200\n"
17   -"Last-Translator: daniel <dtygel@eita.org.br>\n"
18   -"Language-Team: Portuguese <https://hosted.weblate.org/projects/noosfero/"
19   -"noosfero/pt/>\n"
  16 +"PO-Revision-Date: 2015-06-02 19:44+0200\n"
  17 +"Last-Translator: Arthur Del Esposte <arthurmde@gmail.com>\n"
  18 +"Language-Team: Portuguese "
  19 +"<https://hosted.weblate.org/projects/noosfero/noosfero/pt/>\n"
20 20 "Language: pt\n"
21 21 "MIME-Version: 1.0\n"
22 22 "Content-Type: text/plain; charset=UTF-8\n"
... ... @@ -378,9 +378,8 @@ msgid &quot;Manage environment users&quot;
378 378 msgstr "Gerenciar usuários do ambiente"
379 379  
380 380 #: app/models/environment.rb:32
381   -#, fuzzy
382 381 msgid "Manage environment organizations"
383   -msgstr "Gerenciar ambiente de validadores"
  382 +msgstr "Gerenciar organizações do ambiente"
384 383  
385 384 #: app/models/environment.rb:33
386 385 msgid "Manage environment templates"
... ... @@ -697,14 +696,12 @@ msgstr &quot;&quot;
697 696 "podem ser feitas."
698 697  
699 698 #: app/models/forum.rb:38
700   -#, fuzzy
701 699 msgid "Logged users"
702   -msgstr "Identificado(a) como %s"
  700 +msgstr "Usuários logados"
703 701  
704 702 #: app/models/forum.rb:41
705   -#, fuzzy
706 703 msgid "Me"
707   -msgstr "Masculino"
  704 +msgstr "Eu"
708 705  
709 706 #: app/models/forum.rb:42 app/models/block.rb:250
710 707 #: app/helpers/application_helper.rb:563
... ... @@ -712,9 +709,8 @@ msgid &quot;Friends&quot;
712 709 msgstr "Amigos"
713 710  
714 711 #: app/models/forum.rb:45
715   -#, fuzzy
716 712 msgid "Administrators"
717   -msgstr "Administração"
  713 +msgstr "Administradores"
718 714  
719 715 #: app/models/forum.rb:46 app/models/block.rb:250
720 716 #: app/helpers/profile_helper.rb:43 app/helpers/application_helper.rb:571
... ... @@ -1057,9 +1053,9 @@ msgid &quot;&quot;
1057 1053 "User \"%{user}\" just requested to register. You have to approve or reject "
1058 1054 "it through the \"Pending Validations\" section in your control panel.\n"
1059 1055 msgstr ""
1060   -"O usuário \"%{user}\" requisitou a criação da comunidade %{community}. Você "
1061   -"tem que aprová-lo ou rejeitá-lo através da seção \"Validações Pendentes\" no "
1062   -"seu painel de controle.\n"
  1056 +"O usuário \"%{user}\" pediu para cadastrar-se. Você tem que aprová-lo ou "
  1057 +"rejeitá-lo através da seção \"Validações Pendentes\" no seu painel de "
  1058 +"controle.\n"
1063 1059  
1064 1060 #: app/models/user.rb:10 app/models/change_password.rb:8
1065 1061 #: app/views/invite/_select_address_book.html.erb:34
... ... @@ -1831,14 +1827,12 @@ msgid &quot;Article suggestion&quot;
1831 1827 msgstr "Sugestão de artigo"
1832 1828  
1833 1829 #: app/models/suggest_article.rb:64
1834   -#, fuzzy
1835 1830 msgid "%{requestor} suggested the publication of the article: %{subject}."
1836   -msgstr "%{sender} sugeriu a publicação do artigo: %{subject}."
  1831 +msgstr "%{requestor} sugeriu a publicação do artigo: %{subject}."
1837 1832  
1838 1833 #: app/models/suggest_article.rb:77
1839   -#, fuzzy
1840 1834 msgid "%{requestor} suggested the publication of the article: %{article}."
1841   -msgstr "%{sender} sugeriu a publicação do artigo %{article}."
  1835 +msgstr "%{requestor} sugeriu a publicação do artigo %{article}."
1842 1836  
1843 1837 #: app/models/rss_feed.rb:6
1844 1838 msgid "RssFeed"
... ... @@ -2221,11 +2215,11 @@ msgstr &quot;Não logado&quot;
2221 2215  
2222 2216 #: app/models/block.rb:256
2223 2217 msgid "Can be modified"
2224   -msgstr ""
  2218 +msgstr "Pode ser modificada"
2225 2219  
2226 2220 #: app/models/block.rb:257
2227 2221 msgid "Cannot be modified"
2228   -msgstr ""
  2222 +msgstr "Não pode ser modificada"
2229 2223  
2230 2224 #: app/models/block.rb:263
2231 2225 msgid "Can be moved"
... ... @@ -2563,9 +2557,8 @@ msgid &quot;Public&quot;
2563 2557 msgstr "Público"
2564 2558  
2565 2559 #: app/helpers/application_helper.rb:944
2566   -#, fuzzy
2567 2560 msgid "Clone %s"
2568   -msgstr "Clonar"
  2561 +msgstr "Clonar %s"
2569 2562  
2570 2563 #: app/helpers/application_helper.rb:958
2571 2564 msgid "Online Manual"
... ... @@ -2842,21 +2835,20 @@ msgid &quot;See all connections&quot;
2842 2835 msgstr "Ver todas as conexões"
2843 2836  
2844 2837 #: app/helpers/application_helper.rb:1518
2845   -#, fuzzy
2846 2838 msgid "Full screen"
2847   -msgstr "Post completo"
  2839 +msgstr "Tela cheia"
2848 2840  
2849 2841 #: app/helpers/application_helper.rb:1523
2850 2842 msgid "Go to full screen mode"
2851   -msgstr ""
  2843 +msgstr "Ir para o modo tela cheia"
2852 2844  
2853 2845 #: app/helpers/application_helper.rb:1526
2854 2846 msgid "Exit full screen"
2855   -msgstr ""
  2847 +msgstr "Sair da tela cheia"
2856 2848  
2857 2849 #: app/helpers/application_helper.rb:1532
2858 2850 msgid "Exit full screen mode"
2859   -msgstr ""
  2851 +msgstr "Sair do modo tela cheia"
2860 2852  
2861 2853 #: app/helpers/manage_products_helper.rb:156
2862 2854 #: app/views/manage_products/_display_category.html.erb:3
... ... @@ -2988,9 +2980,8 @@ msgid &quot;search in all categories&quot;
2988 2980 msgstr "procurar em todas as categorias"
2989 2981  
2990 2982 #: app/helpers/search_helper.rb:158
2991   -#, fuzzy
2992 2983 msgid "Choose a template"
2993   -msgstr "O modelo \"%s\""
  2984 +msgstr "Escolha um template"
2994 2985  
2995 2986 #: app/helpers/boxes_helper.rb:106
2996 2987 msgid "This block is invisible. Your visitors will not see it."
... ... @@ -4081,9 +4072,8 @@ msgid &quot;Community fields not updated successfully.&quot;
4081 4072 msgstr "Campos de comunidade não atualizados com sucesso."
4082 4073  
4083 4074 #: app/controllers/admin/organizations_controller.rb:7
4084   -#, fuzzy
4085 4075 msgid "Organization profiles"
4086   -msgstr "Método de Aprovação de Organização"
  4076 +msgstr "Perfis de organizações"
4087 4077  
4088 4078 #: app/controllers/admin/organizations_controller.rb:9
4089 4079 #: app/views/tasks/index.html.erb:7 app/views/tasks/index.html.erb:34
... ... @@ -4093,9 +4083,8 @@ msgid &quot;All&quot;
4093 4083 msgstr "Todos"
4094 4084  
4095 4085 #: app/controllers/admin/organizations_controller.rb:33
4096   -#, fuzzy
4097 4086 msgid "%s enabled"
4098   -msgstr "%s não foi habilitado."
  4087 +msgstr "%s habilitado"
4099 4088  
4100 4089 #: app/controllers/admin/organizations_controller.rb:35
4101 4090 #, fuzzy
... ... @@ -4103,9 +4092,8 @@ msgid &quot;%s could not be enabled&quot;
4103 4092 msgstr "%s não pode ser enviado"
4104 4093  
4105 4094 #: app/controllers/admin/organizations_controller.rb:42
4106   -#, fuzzy
4107 4095 msgid "%s disabled"
4108   -msgstr "Desabilitado"
  4096 +msgstr "%s desabilitado"
4109 4097  
4110 4098 #: app/controllers/admin/organizations_controller.rb:44
4111 4099 #, fuzzy
... ... @@ -4568,9 +4556,8 @@ msgid &quot;Files&quot;
4568 4556 msgstr "Arquivos"
4569 4557  
4570 4558 #: app/controllers/my_profile/profile_roles_controller.rb:52
4571   -#, fuzzy
4572 4559 msgid "Role successfuly removed!"
4573   -msgstr "Produto removido com sucesso"
  4560 +msgstr "Papel removido com sucesso!"
4574 4561  
4575 4562 #: app/controllers/my_profile/profile_roles_controller.rb:54
4576 4563 #, fuzzy
... ... @@ -4579,7 +4566,7 @@ msgstr &quot;Falhou em criar papel&quot;
4579 4566  
4580 4567 #: app/controllers/my_profile/profile_roles_controller.rb:85
4581 4568 msgid "Error"
4582   -msgstr ""
  4569 +msgstr "Erro"
4583 4570  
4584 4571 #: app/controllers/my_profile/tasks_controller.rb:28
4585 4572 #, fuzzy
... ...
public/designs/icons/tango/style.css
... ... @@ -116,6 +116,107 @@
116 116 .icon-clock { background-image: url(Tango/16x16/actions/appointment.png) }
117 117 .icon-fullscreen { background-image: url(Tango/16x16/actions/view-fullscreen.png) }
118 118  
  119 +/******************BIG ICONS************************/
  120 +.bigicon-embed { background-image: url(Tango/scalable/apps/utilities-terminal.svg) }
  121 +.bigicon-edit { background-image: url(Tango/scalable/apps/text-editor.svg) }
  122 +.bigicon-undo { background-image: url(Tango/scalable/actions/edit-undo.svg) }
  123 +.bigicon-home { background-image: url(Tango/scalable/actions/go-home.svg) }
  124 +.bigicon-home-not { background-image: url(mod/scalable/actions/go-home-not.svg) }
  125 +.bigicon-new,
  126 +.bigicon-suggest { background-image: url(Tango/scalable/actions/filenew.svg) }
  127 +.bigicon-close { background-image: url(Tango/scalable/actions/gtk-cancel.svg) }
  128 +.bigicon-newfolder { background-image: url(Tango/scalable/actions/folder-new.svg) }
  129 +.bigicon-folder { background-image: url(Tango/scalable/places/folder.svg) }
  130 +.bigicon-parent-folder { background-image: url(Tango/scalable/places/folder_home.svg) }
  131 +.bigicon-newblog { background-image: url(mod/scalable/apps/text-editor.svg) }
  132 +.bigicon-blog { background-image: url(mod/scalable/apps/text-editor.svg) }
  133 +.bigicon-save { background-image: url(Tango/scalable/actions/filesave.svg) }
  134 +.bigicon-send { background-image: url(Tango/scalable/actions/stock_mail-forward.svg) }
  135 +.bigicon-cancel { background-image: url(Tango/scalable/actions/gtk-cancel.svg) }
  136 +.bigicon-person { background-image: url(Tango/scalable/apps/system-config-users.svg) }
  137 +.bigicon-product { background-image: url(Tango/scalable/mimetypes/package.svg) }
  138 +.bigicon-delete { background-image: url(Tango/scalable/places/user-trash.svg) }
  139 +.bigicon-back { background-image: url(Tango/scalable/actions/back.svg) }
  140 +.bigicon-next { background-image: url(Tango/scalable/actions/go-next.svg) }
  141 +.bigicon-add { background-image: url(Tango/scalable/actions/add.svg) }
  142 +.bigicon-remove { background-image: url(Tango/scalable/actions/gtk-remove.svg) }
  143 +.bigicon-more { background-image: url(Tango/scalable/actions/add.svg) }
  144 +.bigicon-up { background-image: url(Tango/scalable/actions/go-up.svg) }
  145 +.bigicon-down { background-image: url(Tango/scalable/actions/go-down.svg) }
  146 +.bigicon-left { background-image: url(Tango/scalable/actions/go-previous.svg) }
  147 +.bigicon-right { background-image: url(Tango/scalable/actions/go-next.svg) }
  148 +.bigicon-up-disabled { background-image: url(Tango/scalable/actions/go-up.svg); opacity: 0.25; filter:alpha(opacity=25); }
  149 +.bigicon-down-disabled { background-image: url(Tango/scalable/actions/go-down.svg); opacity: 0.25; filter:alpha(opacity=25); }
  150 +.bigicon-left-disabled { background-image: url(Tango/scalable/actions/go-previous.svg); opacity: 0.25; filter:alpha(opacity=25); }
  151 +.bigicon-right-disabled { background-image: url(Tango/scalable/actions/go-next.svg); opacity: 0.25; filter:alpha(opacity=25); }
  152 +.bigicon-up-red { background-image: url(mod/scalable/actions/go-up-red.svg) }
  153 +.bigicon-forward { background-image: url(Tango/scalable/actions/go-next.svg) }
  154 +.bigicon-search { background-image: url(Tango/scalable/actions/search.svg) }
  155 +.bigicon-ok { background-image: url(Tango/scalable/actions/media-playback-start.svg) }
  156 +.bigicon-login { background-image: url(mod/scalable/actions/log-in.svg) }
  157 +.bigicon-help { background-image: url(Tango/scalable/apps/gnome-help.svg) }
  158 +.bigicon-help32on { background-image: url(Tango/scalable/apps/gnome-help.svg) }
  159 +.bigicon-help32off { background-image: url(mod/scalable/apps/gnome-help-red.svg) }
  160 +.bigicon-spread { background-image: url(mod/scalable/actions/spread.svg) }
  161 +.bigicon-todo { background-image: url(Tango/scalable/actions/stock_paste.svg) }
  162 +.bigicon-eyes { background-image: url(Tango/scalable/actions/find.svg) }
  163 +.bigicon-menu-home { background-image: url(Tango/scalable/actions/go-home.svg) }
  164 +.bigicon-menu-product { background-image: url(Tango/scalable/mimetypes/package.svg) }
  165 +.bigicon-menu-enterprise { background-image: url(Tango/scalable/actions/go-home.svg) }
  166 +.bigicon-menu-community { background-image: url(Tango/scalable/apps/system-config-users.svg) }
  167 +.bigicon-menu-ctrl-panel { background-image: url(Tango/scalable/categories/preferences-desktop.svg) }
  168 +.bigicon-menu-admin { background-image: url(Tango/scalable/categories/preferences-system.svg) }
  169 +.bigicon-menu-my-groups { background-image: url(Tango/scalable/apps/system-config-users.svg) }
  170 +.bigicon-menu-login { background-image: url(mod/scalable/actions/log-in.svg) }
  171 +.bigicon-menu-logout { background-image: url(mod/scalable/actions/log-out.svg) }
  172 +.bigicon-menu-search { background-image: url(Tango/scalable/actions/search.svg) }
  173 +.bigicon-menu-events { background-image: url(Tango/scalable/mimetypes/stock_calendar.svg) }
  174 +.bigicon-event { background-image: url(Tango/scalable/mimetypes/stock_calendar.svg) }
  175 +.bigicon-newevent { background-image: url(Tango/scalable/mimetypes/stock_calendar.svg) }
  176 +.bigicon-menu-articles { background-image: url(Tango/scalable/apps/text-editor.svg) }
  177 +.bigicon-menu-people { background-image: url(mod/scalable/apps/user.svg) }
  178 +.bigicon-menu-mail { background-image: url(Tango/scalable/apps/email.svg) }
  179 +.bigicon-upload-file { background-image: url(Tango/scalable/actions/filesave.svg) }
  180 +.bigicon-newupload-file { background-image: url(Tango/scalable/actions/filesave.svg) }
  181 +.bigicon-slideshow { background-image: url(Tango/scalable/mimetypes/x-office-presentation.svg) }
  182 +.bigicon-photos { background-image: url(Tango/scalable/devices/camera-photo.svg) }
  183 +.bigicon-vertical-toggle { background-image: url(Tango/scalable/actions/mail-send-receive.svg) }
  184 +.bigicon-text-html { background-image: url(Tango/scalable/mimetypes/text-html.svg) }
  185 +.bigicon-text-plain { background-image: url(Tango/scalable/mimetypes/text-x-generic.svg) }
  186 +.bigicon-image-svg-xml { background-image: url(Tango/scalable/mimetypes/image-x-generic.svg) }
  187 +.bigicon-application-octet-stream { background-image: url(Tango/scalable/mimetypes/binary.svg) }
  188 +.bigicon-application-x-gzip { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-x-gzip.svg) }
  189 +.bigicon-application-postscript { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-postscript.svg) }
  190 +.bigicon-application-pdf { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-pdf.svg) }
  191 +.bigicon-application-ogg { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-ogg.svg) }
  192 +.bigicon-video, .icon-video-mpeg { background-image: url(Tango/scalable/mimetypes/video-x-generic.svg) }
  193 +.bigicon-application-vnd-oasis-opendocument-text { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-vnd.oasis.opendocument.text.svg) }
  194 +.bigicon-application-vnd-oasis-opendocument-spreadsheet { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-vnd.oasis.opendocument.spreadsheet.svg) }
  195 +.bigicon-application-vnd-oasis-opendocument-presentation { background-image: url(Tango/scalable/mimetypes/gnome-mime-application-vnd.oasis.opendocument.presentation.svg) }
  196 +.bigicon-welcome-page { background-image: url(mod/scalable/mimetypes/welcome-page.svg) }
  197 +.bigicon-blocks { background-image: url(mod/scalable/mimetypes/blocks.svg) }
  198 +.bigicon-header-footer { background-image: url(mod/scalable/mimetypes/header-footer.svg) }
  199 +.bigicon-appearance { background-image: url(Tango/scalable/apps/preferences-desktop-wallpaper.svg) }
  200 +.bigicon-media-pause { background-image: url(Tango/scalable/actions/media-playback-pause.svg) }
  201 +.bigicon-media-play { background-image: url(Tango/scalable/actions/media-playback-start.svg) }
  202 +.bigicon-media-prev { background-image: url(Tango/scalable/actions/media-skip-backward.svg) }
  203 +.bigicon-media-next { background-image: url(Tango/scalable/actions/media-skip-forward.svg) }
  204 +.bigicon-lock { background-image: url(Tango/scalable/actions/lock.svg) }
  205 +.bigicon-chat { background-image: url(Tango/scalable/apps/internet-group-chat.svg); background-repeat: no-repeat }
  206 +.bigicon-reply { background-image: url(Tango/scalable/actions/mail-reply-sender.svg) }
  207 +.bigicon-newforum { background-image: url(Tango/scalable/apps/internet-group-chat.svg) }
  208 +.bigicon-forum { background-image: url(Tango/scalable/apps/system-users.svg) }
  209 +.bigicon-gallery { background-image: url(Tango/scalable/mimetypes/image-x-generic.svg) }
  210 +.bigicon-newgallery { background-image: url(Tango/scalable/mimetypes/image-x-generic.svg) }
  211 +.bigicon-locale { background-image: url(Tango/scalable/apps/preferences-desktop-locale.svg) }
  212 +.bigicon-user-removed { background-image: url(Tango/scalable/actions/gtk-cancel.svg) }
  213 +.bigicon-user-unknown { background-image: url(Tango/scalable/status/dialog-error.svg) }
  214 +.bigicon-alert { background-image: url(Tango/scalable/status/dialog-warning.svg) }
  215 +.bigicon-clone { background-image: url(Tango/scalable/actions/edit-copy.svg) }
  216 +.bigicon-activate-user { background-image: url(Tango/scalable/emblems/emblem-system.svg) }
  217 +.bigicon-deactivate-user { background-image: url(Tango/scalable/emblems/emblem-unreadable.svg) }
  218 +.bigicon-clock { background-image: url(Tango/scalable/actions/appointment.svg) }
  219 +
119 220 /******************LARGE ICONS********************/
120 221 .image-gallery-item .folder { background-image: url(mod/96x96/places/folder.png) }
121 222 .image-gallery-item .gallery { background-image: url(mod/96x96/mimetypes/image-x-generic.png) }
... ...
public/images/icons-app/image-loading-bigicon.png 0 → 100644

3.24 KB

public/javascripts/media-panel.js
1   -var file_id = 1;
2   -
3   -jQuery('.view-all-media').on('click', '.pagination a', function(event) {
4   - jQuery.ajax({
5   - url: this.href,
6   - beforeSend: function(){jQuery('.view-all-media').addClass('fetching')},
7   - complete: function() {jQuery('.view-all-media').removeClass('fetching')},
8   - dataType: 'script'
  1 +(function($) {
  2 + "use strict";
  3 +
  4 + var file_id = 1;
  5 +
  6 + $('.view-all-media').on('click', '.pagination a', function(event) {
  7 + $.ajax({
  8 + url: this.href,
  9 + beforeSend: function(){$('.view-all-media').addClass('fetching')},
  10 + complete: function() {$('.view-all-media').removeClass('fetching')},
  11 + dataType: 'script'
  12 + });
  13 + return false;
9 14 });
10   - return false;
11   -});
12   -
13   -jQuery('#file').fileupload({
14   - add: function(e, data){
15   - data.files[0].id = file_id;
16   - file_id++;
17   - data.context = jQuery(tmpl("template-upload", data.files[0]));
18   - jQuery('#media-upload-form').append(data.context);
19   - data.submit();
20   - },
21   - progress: function (e, data) {
22   - if (jQuery('#hide-uploads').data('bootstraped') == false) {
23   - jQuery('#hide-uploads').show();
24   - jQuery('#hide-uploads').data('bootstraped', true);
25   - }
26   - if (data.context) {
27   - progress = parseInt(data.loaded / data.total * 100, 10);
28   - data.context.find('.bar').css('width', progress + '%');
29   - data.context.find('.percentage').text(progress + '%');
30   - }
31   - },
32   - fail: function(e, data){
33   - var file_id = '#file-'+data.files[0].id;
34   - jQuery(file_id).find('.progress .bar').addClass('error');
35   - jQuery(file_id).append("<div class='error-message'>" + data.jqXHR.responseText + "</div>")
36   - }
37   -});
38   -
39   -jQuery('#hide-uploads').click(function(){
40   - jQuery('#hide-uploads').hide();
41   - jQuery('#show-uploads').show();
42   - jQuery('.upload').slideUp();
43   - return false;
44   -});
45   -
46   -jQuery('#show-uploads').click(function(){
47   - jQuery('#hide-uploads').show();
48   - jQuery('#show-uploads').hide();
49   - jQuery('.upload').slideDown();
50   - return false;
51   -});
52   -
53   -function loadPublishedMedia() {
54   - var parent_id = jQuery('#published-media #parent_id').val();
55   - var q = jQuery('#published-media #q').val();
56   - var url = jQuery('#published-media').data('url');
57   -
58   - jQuery('#published-media .items').addClass('fetching');
59   - jQuery.ajax({
60   - url: url,
61   - data: {'parent_id': parent_id, 'q': q},
62   - dataType: 'html',
63   - success: function(response) {
64   - jQuery("#published-media .items").html(response);
65   - jQuery('#published-media .items').removeClass('fetching');
66   - updateViewAllLinks();
  15 +
  16 +
  17 + $('#file').fileupload({
  18 + add: function(e, data){
  19 + data.files[0].id = file_id;
  20 + file_id++;
  21 + data.context = $(tmpl("template-upload", data.files[0]));
  22 + $('#media-upload-form').append(data.context);
  23 + data.submit();
  24 + },
  25 + progress: function (e, data) {
  26 + if ($('#hide-uploads').data('bootstraped') == false) {
  27 + $('#hide-uploads').show();
  28 + $('#hide-uploads').data('bootstraped', true);
  29 + }
  30 + if (data.context) {
  31 + var progress = parseInt(data.loaded / data.total * 100, 10);
  32 + data.context.find('.bar').css('width', progress + '%');
  33 + data.context.find('.percentage').text(progress + '%');
  34 + }
67 35 },
68   - error: function(response, textStatus, xhr) {
69   - console.log(response);
70   - console.log(textStatus);
  36 + fail: function(e, data){
  37 + var file_id = '#file-'+data.files[0].id;
  38 + $(file_id).find('.progress .bar').addClass('error');
  39 + $(file_id).append("<div class='error-message'>" + data.jqXHR.responseText + "</div>")
71 40 }
72 41 });
73   -}
74   -
75   -function updateViewAllLinks() {
76   - var parent_id = jQuery('#published-media #parent_id').val();
77   - var q = jQuery('#published-media #q').val();
78   - jQuery('#published-media .view-all').each(function(){
79   - var key = jQuery(this).data('key');
80   - var params = {parent_id: parent_id, q: q, key: key}
81   - var href = jQuery(this).attr('href');
82   - href = href.replace(/\?.*/, '?'+jQuery.param(params));
83   - jQuery(this).attr('href', href);
  42 +
  43 +
  44 + $('#hide-uploads').click(function(){
  45 + $('#hide-uploads').hide();
  46 + $('#show-uploads').show();
  47 + $('.upload').slideUp();
  48 + return false;
  49 + });
  50 +
  51 +
  52 + $('#show-uploads').click(function(){
  53 + $('#hide-uploads').show();
  54 + $('#show-uploads').hide();
  55 + $('.upload').slideDown();
  56 + return false;
84 57 });
85   -}
86   -
87   -jQuery('#published-media #parent_id').change(function(){ loadPublishedMedia() });
88   -
89   -jQuery("#published-media #q").typeWatch({
90   - callback: function (value) { loadPublishedMedia() },
91   - wait: 750,
92   - highlight: true,
93   - captureLength: 2
94   -});
95   -
96   -jQuery("#published-media #q").bind('notext', function(){ loadPublishedMedia() });
97   -
98   -jQuery("#new-folder-dialog").submit(function( event ) {
99   - var name = jQuery('#new_folder').val();
100   - var parent_id = jQuery("#new-folder-dialog #parent_id").val();
101   - jQuery.ajax({
102   - url: this.action,
103   - type: 'POST',
104   - data: {
105   - 'parent_id': parent_id,
106   - 'article': {'name': name, 'published': true},
107   - 'type': jQuery('input[name=folder_type]:checked').val() },
108   - dataType: 'json',
109   - beforeSend: function(){jQuery("#new-folder-dialog").addClass('fetching')},
110   - success: function(response) {
111   - var option_selected = "<option value='"+ response.id +"' selected='selected'>"+ response.full_name +"</options>"
112   - var option = "<option value='"+ response.id +"'>"+ response.full_name +"</options>"
113   - jQuery('#media-upload-form #parent_id').append(option_selected);
114   - jQuery('#published-media #parent_id').append(option);
115   - jQuery('#new_folder').val('');
116   - },
117   - error: function(response, textStatus, xhr) {
118   - console.log(response);
119   - console.log(textStatus);
120   - },
121   - complete: function(response){
122   - jQuery("#new-folder-dialog").removeClass('fetching');
123   - jQuery("#new-folder-dialog").dialog('close');
124   - }
  58 +
  59 +
  60 + function loadPublishedMedia() {
  61 + var parent_id = $('#published-media #parent_id').val();
  62 + var q = $('#published-media #q').val();
  63 + var url = $('#published-media').data('url');
  64 +
  65 + $('#published-media .items').addClass('fetching');
  66 + $.ajax({
  67 + url: url,
  68 + data: {'parent_id': parent_id, 'q': q},
  69 + dataType: 'html',
  70 + success: function(response) {
  71 + $("#published-media .items").html(response);
  72 + $('#published-media .items').removeClass('fetching');
  73 + updateViewAllLinks();
  74 + },
  75 + error: function(response, textStatus, xhr) {
  76 + console.log(response);
  77 + console.log(textStatus);
  78 + }
  79 + });
  80 + }
  81 + // make it global for usage in media_upload.js.erb
  82 + window.loadPublishedMedia = loadPublishedMedia;
  83 +
  84 +
  85 + function updateViewAllLinks() {
  86 + var parent_id = $('#published-media #parent_id').val();
  87 + var q = $('#published-media #q').val();
  88 + $('#published-media .view-all').each(function(){
  89 + var key = $(this).data('key');
  90 + var params = {parent_id: parent_id, q: q, key: key}
  91 + var href = $(this).attr('href');
  92 + href = href.replace(/\?.*/, '?'+$.param(params));
  93 + $(this).attr('href', href);
  94 + });
  95 + }
  96 +
  97 +
  98 + $('#published-media #parent_id').change(function(){
  99 + loadPublishedMedia()
  100 + });
  101 +
  102 +
  103 + // Using a immediate function to make timer variable only visible for the keyup event
  104 + (function() {
  105 + var timer = null;
  106 +
  107 + $("#published-media #q").keyup(function() {
  108 + if(this.value.length > 2) {
  109 + timer = setTimeout(loadPublishedMedia, 750);
  110 + }
  111 + }).keydown(function() {
  112 + clearTimeout(timer);
  113 + });
  114 + }) ();
  115 +
  116 +
  117 + $("#published-media #q").bind('notext', function(){
  118 + loadPublishedMedia()
  119 + });
  120 +
  121 +
  122 + $("#new-folder-dialog").submit(function( event ) {
  123 + var name = $('#new_folder').val();
  124 + var parent_id = $("#new-folder-dialog #parent_id").val();
  125 + $.ajax({
  126 + url: this.action,
  127 + type: 'POST',
  128 + data: {
  129 + 'parent_id': parent_id,
  130 + 'article': {'name': name, 'published': true},
  131 + 'type': $('input[name=folder_type]:checked').val() },
  132 + dataType: 'json',
  133 + beforeSend: function(){$("#new-folder-dialog").addClass('fetching')},
  134 + success: function(response) {
  135 + var option_selected = "<option value='"+ response.id +"' selected='selected'>"+ response.full_name +"</options>"
  136 + var option = "<option value='"+ response.id +"'>"+ response.full_name +"</options>"
  137 + $('#media-upload-form #parent_id').append(option_selected);
  138 + $('#published-media #parent_id').append(option);
  139 + $('#new_folder').val('');
  140 + },
  141 + error: function(response, textStatus, xhr) {
  142 + console.log(response);
  143 + console.log(textStatus);
  144 + },
  145 + complete: function(response){
  146 + $("#new-folder-dialog").removeClass('fetching');
  147 + $("#new-folder-dialog").dialog('close');
  148 + }
  149 + });
  150 + return false;
  151 + });
  152 +
  153 + $('.icon-vertical-toggle').click(function(){
  154 + $('#content').toggleClass('show-media-panel');
  155 + return false;
125 156 });
126   - return false;
127   -});
128   -
129   -jQuery('.text-editor-sidebar .header .icon-vertical-toggle').click(function(){
130   - jQuery('#content').toggleClass('show-media-panel');
131   - return false;
132   -});
133   -
134   -jQuery('#new-folder-button').click(function(){
135   - jQuery('#new-folder-dialog').dialog({modal: true});
136   - return false;
137   -});
  157 +
  158 +
  159 + $('#new-folder-button').click(function(){
  160 + $('#new-folder-dialog').dialog({modal: true});
  161 + return false;
  162 + });
  163 +
  164 +}) (jQuery);
... ...
public/stylesheets/application.scss
... ... @@ -1561,6 +1561,32 @@ div.article-body p img {
1561 1561 #content .blog-post .read-more a {
1562 1562 margin: 0 10px;
1563 1563 }
  1564 +
  1565 +#content #article .blog-posts .blog-post .article-compact-abstract{
  1566 + position: relative;
  1567 + float:left;
  1568 + margin-left: 10px;
  1569 + width: 100%;
  1570 + word-wrap: break-word;
  1571 +}
  1572 +
  1573 +#content #article .blog-posts .blog-post .article-compact-image{
  1574 + position:relative;
  1575 + float:left;
  1576 + width: 27%;
  1577 + display: table-cell;
  1578 + vertical-align: middle;
  1579 + text-align: center;
  1580 + margin-top: 15px;
  1581 +}
  1582 +
  1583 +#content #article .blog-posts .blog-post .article-compact-abstract-with-image{
  1584 + position: relative;
  1585 + float:left;
  1586 + margin-left: 10px;
  1587 + width: 70%;
  1588 + word-wrap: break-word;
  1589 +}
1564 1590 /* NOT PUBLISHED BLOG POSTS */
1565 1591  
1566 1592 .blog-post.not-published {
... ... @@ -3832,6 +3858,11 @@ table.cms-articles .icon:hover {
3832 3858  
3833 3859 /* Folders */
3834 3860  
  3861 +.article-body ul.folder-content {
  3862 + list-style-type: none;
  3863 + padding: 0;
  3864 +}
  3865 +
3835 3866 .folder-content .folder-item img {
3836 3867 vertical-align: middle;
3837 3868 position: relative;
... ... @@ -3897,6 +3928,62 @@ table.cms-articles .icon:hover {
3897 3928 right: auto;
3898 3929 left: auto;
3899 3930 }
  3931 +
  3932 +/**************Folder Style**********************/
  3933 +
  3934 +.list-item{
  3935 + font-family: arial;
  3936 + color: #172738;
  3937 +}
  3938 +
  3939 +div.folder-description {
  3940 + padding-bottom: 15px;
  3941 +}
  3942 +
  3943 +.list-item h2{
  3944 + border-bottom:1px solid #ccc;
  3945 + margin:0px;
  3946 +}
  3947 +
  3948 +.item-info{
  3949 + border-top: 1px solid #ccc;
  3950 + line-height: 25px;
  3951 + padding:25px 20px;
  3952 +}
  3953 +
  3954 +.item-info a{
  3955 + text-decoration: none !important;
  3956 + font-size: 16px;
  3957 + font-weight: bold;
  3958 +}
  3959 +
  3960 +.item-icon a {
  3961 + float: left;
  3962 + width: 50px;
  3963 + height: 50px;
  3964 + background-repeat: no-repeat;
  3965 + background-position: center center;
  3966 +}
  3967 +
  3968 +span.item-type {
  3969 + font-size: 12px;
  3970 +}
  3971 +
  3972 +.item-description{
  3973 + display: block;
  3974 + position:relative;
  3975 + margin-left: 15%;
  3976 + padding-left: 10px;
  3977 +}
  3978 +
  3979 +.item-date{
  3980 + display:block;
  3981 + position:relative;
  3982 + font-size: 12px;
  3983 + margin-left: 15%;
  3984 + padding-left: 10px;
  3985 +}
  3986 +
3900 3987 /************* enterprise homepage style *****************/
3901 3988  
3902 3989 div.event-info {
... ...
test/functional/admin_panel_controller_test.rb
... ... @@ -130,6 +130,19 @@ class AdminPanelControllerTest &lt; ActionController::TestCase
130 130 assert_equal "This <strong>is</strong> my new environment", Environment.default.message_for_disabled_enterprise
131 131 end
132 132  
  133 + should 'save site article date format option' do
  134 + post :site_info, :environment => { :date_format => "numbers_with_year" }
  135 + assert_redirected_to :action => 'index'
  136 +
  137 + assert_equal "numbers_with_year", Environment.default.date_format
  138 + end
  139 +
  140 + should 'dont save site article date format option when a invalid option is passed' do
  141 + post :site_info, :environment => { :date_format => "invalid_format" }
  142 +
  143 + assert_not_equal "invalid_format", Environment.default.date_format
  144 + end
  145 +
133 146 should 'set portal community' do
134 147 e = Environment.default
135 148 @controller.stubs(:environment).returns(e)
... ...
test/functional/application_controller_test.rb
... ... @@ -484,7 +484,7 @@ class ApplicationControllerTest &lt; ActionController::TestCase
484 484 should 'change postgresql schema' do
485 485 uses_host 'schema1.com'
486 486 Noosfero::MultiTenancy.expects(:on?).returns(true)
487   - Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema1.com' => 'schema1' })
  487 + Noosfero::MultiTenancy.expects(:mapping).returns({ 'schema1.com' => 'schema1' }).at_least_once
488 488 exception = assert_raise(ActiveRecord::StatementInvalid) { get :index }
489 489 assert_match /SET search_path TO schema1/, exception.message
490 490 end
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -262,7 +262,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
262 262  
263 263 get :view_page, :profile => 'test_profile', :page => [ 'my-intranet' ]
264 264  
265   - assert_template "profile/_private_profile"
  265 + assert_template "shared/access_denied"
266 266 end
267 267  
268 268 should 'not give access to private articles if logged in but not member' do
... ... @@ -1527,12 +1527,12 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1527 1527 should 'use context method in extra toolbar actions on article from plugins' do
1528 1528 class Plugin1 < Noosfero::Plugin
1529 1529 def article_extra_toolbar_buttons(article)
1530   - if current_person.public?
  1530 + if profile.public?
1531 1531 {:title => 'some_title', :icon => 'some_icon', :url => '/someurl'}
1532 1532 else
1533 1533 {:title => 'another_title', :icon => 'another_icon', :url => '/anotherurl'}
1534 1534 end
1535   - end
  1535 + end
1536 1536 end
1537 1537 Noosfero::Plugin.stubs(:all).returns([Plugin1.name])
1538 1538  
... ... @@ -1547,4 +1547,31 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1547 1547 assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :href => "/anotherurl" }}
1548 1548 end
1549 1549  
  1550 + should 'show lead,image and title in compact blog visualization' do
  1551 + community = Community.create(:name => 'test-community')
  1552 + community.add_member(@profile)
  1553 + community.save!
  1554 +
  1555 + blog = community.articles.find_by_name("Blog")
  1556 + blog.visualization_format = 'compact'
  1557 + blog.save!
  1558 +
  1559 + article = TinyMceArticle.create(:name => 'Article to be shared with images',
  1560 + :body => 'This article should be shared with all social networks',
  1561 + :profile => @profile,
  1562 + :published => false,
  1563 + :abstract => "teste teste teste",
  1564 + :show_to_followers => true,
  1565 + :image_builder => { :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png')} )
  1566 + article.parent = blog
  1567 + article.save!
  1568 +
  1569 + login_as(@profile.identifier)
  1570 +
  1571 +
  1572 + get :view_page, :profile => community.identifier, "page" => 'blog'
  1573 +
  1574 + assert_tag :tag => 'div', :attributes => { :class => 'article-compact-image' }
  1575 + assert_tag :tag => 'div', :attributes => { :class => 'article-compact-abstract-with-image' }
  1576 + end
1550 1577 end
... ...
test/functional/friends_controller_test.rb
... ... @@ -46,7 +46,7 @@ class FriendsControllerTest &lt; ActionController::TestCase
46 46  
47 47 should 'display find people button' do
48 48 get :index, :profile => 'testuser'
49   - assert_tag :tag => 'a', :content => 'Find people', :attributes => { :href => '/assets/people' }
  49 + assert_tag :tag => 'a', :content => 'Find people', :attributes => { :href => '/search/assets?asset=people' }
50 50 end
51 51  
52 52 should 'not display invite friends button if any plugin tells not to' do
... ... @@ -76,25 +76,25 @@ class FriendsControllerTest &lt; ActionController::TestCase
76 76 end
77 77  
78 78 should 'display people suggestions' do
79   - profile.profile_suggestions.create(:suggestion => friend)
  79 + profile.suggested_profiles.create(:suggestion => friend)
80 80 get :suggest, :profile => 'testuser'
81 81 assert_tag :tag => 'a', :content => "+ #{friend.name}", :attributes => { :href => "/profile/#{friend.identifier}/add" }
82 82 end
83 83  
84 84 should 'display button to add friend suggestion' do
85   - profile.profile_suggestions.create(:suggestion => friend)
  85 + profile.suggested_profiles.create(:suggestion => friend)
86 86 get :suggest, :profile => 'testuser'
87 87 assert_tag :tag => 'a', :attributes => { :href => "/profile/#{friend.identifier}/add" }
88 88 end
89 89  
90 90 should 'display button to remove people suggestion' do
91   - profile.profile_suggestions.create(:suggestion => friend)
  91 + profile.suggested_profiles.create(:suggestion => friend)
92 92 get :suggest, :profile => 'testuser'
93 93 assert_tag :tag => 'a', :attributes => { :href => /\/myprofile\/testuser\/friends\/remove_suggestion\/#{friend.identifier}/ }
94 94 end
95 95  
96 96 should 'remove suggestion of friend' do
97   - suggestion = profile.profile_suggestions.create(:suggestion => friend)
  97 + suggestion = profile.suggested_profiles.create(:suggestion => friend)
98 98 post :remove_suggestion, :profile => 'testuser', :id => friend.identifier
99 99  
100 100 assert_response :success
... ...
test/functional/memberships_controller_test.rb
... ... @@ -331,35 +331,35 @@ class MembershipsControllerTest &lt; ActionController::TestCase
331 331  
332 332 should 'display list suggestions button' do
333 333 community = fast_create(Community)
334   - profile.profile_suggestions.create(:suggestion => community)
  334 + profile.suggested_profiles.create(:suggestion => community)
335 335 get :index, :profile => 'testuser'
336 336 assert_tag :tag => 'a', :content => 'See some suggestions of communities...', :attributes => { :href => "/myprofile/testuser/memberships/suggest" }
337 337 end
338 338  
339 339 should 'display communities suggestions' do
340 340 community = fast_create(Community)
341   - profile.profile_suggestions.create(:suggestion => community)
  341 + profile.suggested_profiles.create(:suggestion => community)
342 342 get :suggest, :profile => 'testuser'
343 343 assert_tag :tag => 'a', :content => "+ #{community.name}", :attributes => { :href => "/profile/#{community.identifier}/join" }
344 344 end
345 345  
346 346 should 'display button to join on community suggestion' do
347 347 community = fast_create(Community)
348   - profile.profile_suggestions.create(:suggestion => community)
  348 + profile.suggested_profiles.create(:suggestion => community)
349 349 get :suggest, :profile => 'testuser'
350 350 assert_tag :tag => 'a', :attributes => { :href => "/profile/#{community.identifier}/join" }
351 351 end
352 352  
353 353 should 'display button to remove community suggestion' do
354 354 community = fast_create(Community)
355   - profile.profile_suggestions.create(:suggestion => community)
  355 + profile.suggested_profiles.create(:suggestion => community)
356 356 get :suggest, :profile => 'testuser'
357 357 assert_tag :tag => 'a', :attributes => { :href => /\/myprofile\/testuser\/memberships\/remove_suggestion\/#{community.identifier}/ }
358 358 end
359 359  
360 360 should 'remove suggestion of community' do
361 361 community = fast_create(Community)
362   - suggestion = profile.profile_suggestions.create(:suggestion => community)
  362 + suggestion = profile.suggested_profiles.create(:suggestion => community)
363 363 post :remove_suggestion, :profile => 'testuser', :id => community.identifier
364 364  
365 365 assert_response :success
... ...
test/functional/organizations_controller_test.rb
... ... @@ -86,22 +86,22 @@ class OrganizationsControllerTest &lt; ActionController::TestCase
86 86  
87 87 should 'activate organization profile' do
88 88 organization = fast_create(Organization, :visible => false, :environment_id => environment.id)
89   - assert organization.disabled?
  89 + assert !organization.visible?
90 90  
91 91 get :activate, {:id => organization.id}
92 92 organization.reload
93 93  
94   - assert organization.enabled?
  94 + assert organization.visible
95 95 end
96 96  
97 97 should 'deactivate organization profile' do
98 98 organization = fast_create(Organization, :visible => true, :environment_id => environment.id)
99   - assert organization.enabled?
  99 + assert organization.visible
100 100  
101 101 get :deactivate, {:id => organization.id}
102 102 organization.reload
103 103  
104   - assert organization.disabled?
  104 + assert !organization.visible
105 105 end
106 106  
107 107 should 'destroy organization profile' do
... ...
test/functional/profile_controller_test.rb
... ... @@ -508,11 +508,15 @@ class ProfileControllerTest &lt; ActionController::TestCase
508 508 end
509 509  
510 510 should 'show description of person' do
  511 + environment = Environment.default
  512 + environment.custom_person_fields = {:description => { :active => true, :required => false, :signup => false }}
  513 + environment.save!
  514 + environment.reload
511 515 login_as(@profile.identifier)
512   - @profile.description = 'Person\'s description'
513   - @profile.save
  516 + @profile.description = 'Person description'
  517 + @profile.save!
514 518 get :index, :profile => @profile.identifier
515   - assert_tag :tag => 'div', :attributes => { :class => 'public-profile-description' }, :content => /Person\'s description/
  519 + assert_tag :tag => 'div', :attributes => { :class => 'public-profile-description' }, :content => /Person description/
516 520 end
517 521  
518 522 should 'not show description of orgarnization if not filled' do
... ...
test/functional/tasks_controller_test.rb
... ... @@ -520,4 +520,120 @@ class TasksControllerTest &lt; ActionController::TestCase
520 520 assert !json_response['success']
521 521 end
522 522  
  523 + should 'list tasks for user with only view_tasks permission' do
  524 + community = fast_create(Community)
  525 + @controller.stubs(:profile).returns(community)
  526 + person = create_user_with_permission('taskviewer', 'view_tasks', community)
  527 + login_as person.user.login
  528 + get :index
  529 + assert_response :success
  530 + assert assigns(:view_only)
  531 + end
  532 +
  533 + should 'forbid user with only view_tasks permission to close a task' do
  534 + community = fast_create(Community)
  535 + @controller.stubs(:profile).returns(community)
  536 + person = create_user_with_permission('taskviewer', 'view_tasks', community)
  537 + login_as person.user.login
  538 + post :close
  539 + assert_response 403
  540 + end
  541 +
  542 + should 'hide tasks actions when user has only view_tasks permission' do
  543 + community = fast_create(Community)
  544 + @controller.stubs(:profile).returns(community)
  545 + person = create_user_with_permission('taskviewer', 'view_tasks', community)
  546 + login_as person.user.login
  547 +
  548 + Task.create!(:requestor => person, :target => community)
  549 + get :index
  550 +
  551 + assert_select '.task-actions', 0
  552 + end
  553 +
  554 + should 'display tasks actions when user has perform_task permission' do
  555 + community = fast_create(Community)
  556 + @controller.stubs(:profile).returns(community)
  557 + person = create_user_with_permission('taskperformer', 'perform_task', community)
  558 + login_as person.user.login
  559 +
  560 + Task.create!(:requestor => person, :target => community)
  561 + get :index
  562 +
  563 + assert_select '.task-actions', 2
  564 + end
  565 +
  566 + should 'hide decision selector when user has only view_tasks permission' do
  567 + community = fast_create(Community)
  568 + @controller.stubs(:profile).returns(community)
  569 + person = create_user_with_permission('taskviewer', 'view_tasks', community)
  570 + login_as person.user.login
  571 +
  572 + Task.create!(:requestor => person, :target => community)
  573 + get :index
  574 +
  575 + assert_select '#up-set-all-tasks-to', 0
  576 + assert_select '#down-set-all-tasks-to', 0
  577 + end
  578 +
  579 + should 'display decision selector when user has perform_task permission' do
  580 + community = fast_create(Community)
  581 + @controller.stubs(:profile).returns(community)
  582 + person = create_user_with_permission('taskperformer', 'perform_task', community)
  583 + login_as person.user.login
  584 +
  585 + Task.create!(:requestor => person, :target => community)
  586 + get :index
  587 +
  588 + assert_select '#up-set-all-tasks-to'
  589 + assert_select '#down-set-all-tasks-to'
  590 + end
  591 +
  592 + should 'hide decision buttons when user has only view_tasks permission' do
  593 + community = fast_create(Community)
  594 + @controller.stubs(:profile).returns(community)
  595 + person = create_user_with_permission('taskviewer', 'view_tasks', community)
  596 + login_as person.user.login
  597 +
  598 + task = Task.create!(:requestor => person, :target => community)
  599 + get :index
  600 +
  601 + assert_select "#decision-finish-#{task.id}", 0
  602 + assert_select "#decision-cancel-#{task.id}", 0
  603 + assert_select "#decision-skip-#{task.id}", 0
  604 + end
  605 +
  606 + should 'display decision buttons when user has perform_task permission' do
  607 + community = fast_create(Community)
  608 + @controller.stubs(:profile).returns(community)
  609 + person = create_user_with_permission('taskperformer', 'perform_task', community)
  610 + login_as person.user.login
  611 +
  612 + task = Task.create!(:requestor => person, :target => community)
  613 + get :index
  614 +
  615 + assert_select "#decision-finish-#{task.id}"
  616 + assert_select "#decision-cancel-#{task.id}"
  617 + assert_select "#decision-skip-#{task.id}"
  618 + end
  619 +
  620 + should 'hide responsive selection when user has only view_tasks permission' do
  621 + community = fast_create(Community)
  622 + @controller.stubs(:profile).returns(community)
  623 + person = create_user_with_permission('taskviewer', 'view_tasks', community)
  624 + login_as person.user.login
  625 +
  626 + task = Task.create!(:requestor => person, :target => community, :responsible => person)
  627 + get :index
  628 +
  629 + assert_select ".task_responsible select", 0
  630 + assert_select ".task_responsible .value"
  631 + end
  632 +
  633 + should 'store the person who closes a task' do
  634 + t = profile.tasks.build; t.save!
  635 + post :close, :tasks => {t.id => {:decision => 'finish', :task => {}}}
  636 + assert_equal profile, t.reload.closed_by
  637 + end
  638 +
523 639 end
... ...
test/integration/routing_test.rb
... ... @@ -135,7 +135,7 @@ class RoutingTest &lt; ActionController::IntegrationTest
135 135 end
136 136  
137 137 def test_assets_routing
138   - assert_routing('/assets/my-asset/a/b/c', :controller => 'search', :action => 'assets', :asset => 'my-asset', :category_path => 'a/b/c')
  138 + assert_routing('/search/assets/a/b/c', :controller => 'search', :action => 'assets', :category_path => 'a/b/c')
139 139 end
140 140  
141 141 def test_content_view_with_dot
... ...
test/test_helper.rb
... ... @@ -262,10 +262,6 @@ module NoosferoTestHelper
262 262 arg
263 263 end
264 264  
265   - def show_date(date)
266   - date.to_s
267   - end
268   -
269 265 def strip_tags(html)
270 266 html.gsub(/<[^>]+>/, '')
271 267 end
... ...