Commit ee8fd9e4e3c8b50e569805fe27927c27294b868e
Exists in
master
and in
20 other branches
Merge branch 'noosfero' into rails4
Showing
76 changed files
with
2022 additions
and
165 deletions
Show diff stats
AUTHORS.md
@@ -90,15 +90,17 @@ Matheus Faria <matheus.sousa.faria@gmail.com> | @@ -90,15 +90,17 @@ Matheus Faria <matheus.sousa.faria@gmail.com> | ||
90 | Maurilio Atila <cabelotaina@gmail.com> | 90 | Maurilio Atila <cabelotaina@gmail.com> |
91 | M for Momo <mo@rtnp.org> | 91 | M for Momo <mo@rtnp.org> |
92 | Michal Čihař <michal@cihar.com> | 92 | Michal Čihař <michal@cihar.com> |
93 | -Michel Felipe <mfelipeof@gmail.com> | 93 | +Michel Felipe de Oliveira Ferreira <michel.ferreira@serpro.gov.br> |
94 | Moises Machado <moises@colivre.coop.br> | 94 | Moises Machado <moises@colivre.coop.br> |
95 | Naíla Alves <naila@colivre.coop.br> | 95 | Naíla Alves <naila@colivre.coop.br> |
96 | Nanda Lopes <nanda.listas+psl@gmail.com> | 96 | Nanda Lopes <nanda.listas+psl@gmail.com> |
97 | Niemand Jedermann <predatorix@web.de> | 97 | Niemand Jedermann <predatorix@web.de> |
98 | +Omar Junior <omarroinuj@gmail.com> | ||
98 | Parley Martins <parleypachecomartins@gmail.com> | 99 | Parley Martins <parleypachecomartins@gmail.com> |
99 | Paulo Meirelles <paulo@softwarelivre.org> | 100 | Paulo Meirelles <paulo@softwarelivre.org> |
100 | Pedro de Lyra <pedrodelyra@gmail.com> | 101 | Pedro de Lyra <pedrodelyra@gmail.com> |
101 | Pedro Leal | 102 | Pedro Leal |
103 | +Phillip Rohmberger <rohmberger@hotmail.de> | ||
102 | Rafael de Souza Queiroz <querafael@live.com> | 104 | Rafael de Souza Queiroz <querafael@live.com> |
103 | Rafael Gomes <rafaelgomes@techfree.com.br> | 105 | Rafael Gomes <rafaelgomes@techfree.com.br> |
104 | Rafael Martins <rmmartins@gmail.com> | 106 | Rafael Martins <rmmartins@gmail.com> |
@@ -112,6 +114,7 @@ Rodrigo Medeiros <rodrigo.mss01@gmail.com> | @@ -112,6 +114,7 @@ Rodrigo Medeiros <rodrigo.mss01@gmail.com> | ||
112 | Rodrigo Souto <rodrigo@colivre.coop.br> | 114 | Rodrigo Souto <rodrigo@colivre.coop.br> |
113 | Ronny Kursawe <kursawe.ronny@googlemail.com> | 115 | Ronny Kursawe <kursawe.ronny@googlemail.com> |
114 | Samuel R. C. Vale <srcvale@holoscopio.com> | 116 | Samuel R. C. Vale <srcvale@holoscopio.com> |
117 | +Simiao Carvalho <simiaosimis@gmail.com> | ||
115 | Tallys Martins <tallysmartins@yahoo.com.br> | 118 | Tallys Martins <tallysmartins@yahoo.com.br> |
116 | Thiago Casotti <thiago.casotti@uol.com.br> | 119 | Thiago Casotti <thiago.casotti@uol.com.br> |
117 | Thiago Kairala <thiagor.kairala@gmail.com> | 120 | Thiago Kairala <thiagor.kairala@gmail.com> |
@@ -123,6 +126,7 @@ Valessio Brito <contato@valessiobrito.com.br> | @@ -123,6 +126,7 @@ Valessio Brito <contato@valessiobrito.com.br> | ||
123 | Victor Costa <vfcosta@gmail.com> | 126 | Victor Costa <vfcosta@gmail.com> |
124 | Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com> | 127 | Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com> |
125 | Vinicius Cubas Brand <viniciuscb@gmail.com> | 128 | Vinicius Cubas Brand <viniciuscb@gmail.com> |
129 | +Vitor Barbosa <vitornga15@gmail.com> | ||
126 | Wilton Rodrigues <braynwilton@gmail.com> | 130 | Wilton Rodrigues <braynwilton@gmail.com> |
127 | Yann Lugrin <yann.lugrin@liquid-concept.ch> | 131 | Yann Lugrin <yann.lugrin@liquid-concept.ch> |
128 | 132 |
app/controllers/my_profile/cms_controller.rb
@@ -111,10 +111,7 @@ class CmsController < MyProfileController | @@ -111,10 +111,7 @@ class CmsController < MyProfileController | ||
111 | end | 111 | end |
112 | end | 112 | end |
113 | 113 | ||
114 | - unless @article.kind_of?(RssFeed) | ||
115 | - @escaped_body = CGI::escapeHTML(@article.body || '') | ||
116 | - @escaped_abstract = CGI::escapeHTML(@article.abstract || '') | ||
117 | - end | 114 | + escape_fields @article |
118 | end | 115 | end |
119 | 116 | ||
120 | def new | 117 | def new |
@@ -185,6 +182,8 @@ class CmsController < MyProfileController | @@ -185,6 +182,8 @@ class CmsController < MyProfileController | ||
185 | end | 182 | end |
186 | end | 183 | end |
187 | 184 | ||
185 | + escape_fields @article | ||
186 | + | ||
188 | render :action => 'edit' | 187 | render :action => 'edit' |
189 | end | 188 | end |
190 | 189 | ||
@@ -534,4 +533,10 @@ class CmsController < MyProfileController | @@ -534,4 +533,10 @@ class CmsController < MyProfileController | ||
534 | end | 533 | end |
535 | end | 534 | end |
536 | 535 | ||
536 | + def escape_fields article | ||
537 | + unless article.kind_of?(RssFeed) | ||
538 | + @escaped_body = CGI::escapeHTML(article.body || '') | ||
539 | + @escaped_abstract = CGI::escapeHTML(article.abstract || '') | ||
540 | + end | ||
541 | + end | ||
537 | end | 542 | end |
app/controllers/public/content_viewer_controller.rb
@@ -8,6 +8,7 @@ class ContentViewerController < ApplicationController | @@ -8,6 +8,7 @@ class ContentViewerController < ApplicationController | ||
8 | helper TagsHelper | 8 | helper TagsHelper |
9 | 9 | ||
10 | def view_page | 10 | def view_page |
11 | + | ||
11 | path = get_path(params[:page], params[:format]) | 12 | path = get_path(params[:page], params[:format]) |
12 | 13 | ||
13 | @version = params[:version].to_i | 14 | @version = params[:version].to_i |
@@ -38,7 +39,7 @@ class ContentViewerController < ApplicationController | @@ -38,7 +39,7 @@ class ContentViewerController < ApplicationController | ||
38 | end | 39 | end |
39 | 40 | ||
40 | # At this point the page will be showed | 41 | # At this point the page will be showed |
41 | - @page.hit unless user_is_a_bot? | 42 | + @page.hit unless user_is_a_bot? || already_visited?(@page) |
42 | 43 | ||
43 | @page = FilePresenter.for @page | 44 | @page = FilePresenter.for @page |
44 | 45 | ||
@@ -272,4 +273,18 @@ class ContentViewerController < ApplicationController | @@ -272,4 +273,18 @@ class ContentViewerController < ApplicationController | ||
272 | @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order] | 273 | @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order] |
273 | end | 274 | end |
274 | 275 | ||
276 | + private | ||
277 | + | ||
278 | + def already_visited?(element) | ||
279 | + user_id = if user.nil? then -1 else current_user.id end | ||
280 | + user_id = "#{user_id}_#{element.id}_#{element.class}" | ||
281 | + | ||
282 | + if cookies.signed[:visited] == user_id | ||
283 | + return true | ||
284 | + else | ||
285 | + cookies.permanent.signed[:visited] = user_id | ||
286 | + return false | ||
287 | + end | ||
288 | + end | ||
289 | + | ||
275 | end | 290 | end |
app/controllers/public/profile_controller.rb
@@ -66,7 +66,10 @@ class ProfileController < PublicController | @@ -66,7 +66,10 @@ class ProfileController < PublicController | ||
66 | 66 | ||
67 | def members | 67 | def members |
68 | if is_cache_expired?(profile.members_cache_key(params)) | 68 | if is_cache_expired?(profile.members_cache_key(params)) |
69 | - @members = profile.members_by_name.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage], :total_entries => profile.members.count) | 69 | + sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' |
70 | + @profile_admins = profile.admins.includes(relations_to_include).order("name #{sort}").paginate(:per_page => members_per_page, :page => params[:npage]) | ||
71 | + @profile_members = profile.members.includes(relations_to_include).order("name #{sort}").paginate(:per_page => members_per_page, :page => params[:npage]) | ||
72 | + @profile_members_url = url_for(:controller => 'profile', :action => 'members') | ||
70 | end | 73 | end |
71 | end | 74 | end |
72 | 75 |
app/helpers/article_helper.rb
@@ -88,7 +88,7 @@ module ArticleHelper | @@ -88,7 +88,7 @@ module ArticleHelper | ||
88 | content_tag( 'small', _('Who will be able to create new topics on this forum?')) + | 88 | content_tag( 'small', _('Who will be able to create new topics on this forum?')) + |
89 | content_tag('div', '', slider_options) + | 89 | content_tag('div', '', slider_options) + |
90 | hidden_field_tag('article[topic_creation]', article.topic_creation) + | 90 | hidden_field_tag('article[topic_creation]', article.topic_creation) + |
91 | - javascript_include_tag('topic-creation-config') | 91 | + javascript_include_tag("#{Noosfero.root}/assets/topic-creation-config.js") |
92 | end | 92 | end |
93 | 93 | ||
94 | def privacity_exceptions(article, tokenized_children) | 94 | def privacity_exceptions(article, tokenized_children) |
app/models/profile.rb
@@ -920,7 +920,8 @@ private :generate_url, :url_options | @@ -920,7 +920,8 @@ private :generate_url, :url_options | ||
920 | 920 | ||
921 | def members_cache_key(params = {}) | 921 | def members_cache_key(params = {}) |
922 | page = params[:npage] || '1' | 922 | page = params[:npage] || '1' |
923 | - cache_key + '-members-page-' + page | 923 | + sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' |
924 | + cache_key + '-members-page-' + page + '-' + sort | ||
924 | end | 925 | end |
925 | 926 | ||
926 | def more_recent_label | 927 | def more_recent_label |
app/models/profile_activity.rb
@@ -16,6 +16,7 @@ class ProfileActivity < ActiveRecord::Base | @@ -16,6 +16,7 @@ class ProfileActivity < ActiveRecord::Base | ||
16 | 16 | ||
17 | def self.update_activity activity | 17 | def self.update_activity activity |
18 | profile_activity = ProfileActivity.where(activity_id: activity.id, activity_type: activity.class.base_class.name).first | 18 | profile_activity = ProfileActivity.where(activity_id: activity.id, activity_type: activity.class.base_class.name).first |
19 | + return unless profile_activity | ||
19 | profile_activity.send :copy_timestamps | 20 | profile_activity.send :copy_timestamps |
20 | profile_activity.save! | 21 | profile_activity.save! |
21 | profile_activity | 22 | profile_activity |
app/models/scrap.rb
@@ -22,11 +22,11 @@ class Scrap < ActiveRecord::Base | @@ -22,11 +22,11 @@ class Scrap < ActiveRecord::Base | ||
22 | 22 | ||
23 | scope :not_replies, ->{ where scrap_id: nil } | 23 | scope :not_replies, ->{ where scrap_id: nil } |
24 | 24 | ||
25 | - track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.sender != s.receiver && s.sender != s.top_root.receiver}, :custom_target => :action_tracker_target | 25 | + track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.sender != s.receiver && s.sender != s.top_root.receiver}, :custom_target => :action_tracker_target, :custom_user => :sender |
26 | 26 | ||
27 | - track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender == s.receiver} | 27 | + track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender == s.receiver}, :custom_user => :sender |
28 | 28 | ||
29 | - track_actions :reply_scrap_on_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender != s.receiver && s.sender == s.top_root.receiver} | 29 | + track_actions :reply_scrap_on_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender != s.receiver && s.sender == s.top_root.receiver}, :custom_user => :sender |
30 | 30 | ||
31 | after_create :send_notification | 31 | after_create :send_notification |
32 | 32 |
app/views/cms/edit.html.erb
@@ -5,8 +5,6 @@ | @@ -5,8 +5,6 @@ | ||
5 | 5 | ||
6 | <%= hidden_field_tag("type", @type) if @type %> | 6 | <%= hidden_field_tag("type", @type) if @type %> |
7 | 7 | ||
8 | - <%= hidden_field_tag('parent_id', @parent_id) if @parent_id %> | ||
9 | - | ||
10 | <%= hidden_field_tag('back_to', @back_to) %> | 8 | <%= hidden_field_tag('back_to', @back_to) %> |
11 | 9 | ||
12 | <%= hidden_field_tag('success_back_to', @success_back_to) %> | 10 | <%= hidden_field_tag('success_back_to', @success_back_to) %> |
app/views/content_viewer/_article_toolbar.html.erb
@@ -29,10 +29,10 @@ | @@ -29,10 +29,10 @@ | ||
29 | <%= expirable_button @page, :locale, content, url %> | 29 | <%= expirable_button @page, :locale, content, url %> |
30 | <% end %> | 30 | <% end %> |
31 | 31 | ||
32 | - <%= modal_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : (@page.parent.nil? ? nil : @page.parent)))) unless remove_content_button(:new, @page) %> | 32 | + <%= modal_button(:new, label_for_new_article(@page), profile.admin_url.merge(:controller => 'cms', :action => 'new', :parent_id => (@page.folder? ? @page : @page.parent))) unless remove_content_button(:new, @page) %> |
33 | 33 | ||
34 | <% content = content_tag('span', label_for_clone_article(@page)) %> | 34 | <% content = content_tag('span', label_for_clone_article(@page)) %> |
35 | - <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'new', :id => @page.id, :clone => true, :type => @page.class }) %> | 35 | + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'new', :id => @page.id, :clone => true, :parent_id => (@page.folder? ? @page : @page.parent), :type => @page.class}) %> |
36 | <%= expirable_button @page, :clone, content, url %> | 36 | <%= expirable_button @page, :clone, content, url %> |
37 | <% end %> | 37 | <% end %> |
38 | 38 |
@@ -0,0 +1,16 @@ | @@ -0,0 +1,16 @@ | ||
1 | +<div id="profile-members-sort-options"> | ||
2 | + <%= label_tag("sort-#{role}", _("Sort by:")) %> | ||
3 | + <%= select_tag("sort-#{role}", | ||
4 | + options_for_select([ | ||
5 | + [_("Name A-Z"), 'asc'], | ||
6 | + [_("Name Z-A"), 'desc'], | ||
7 | + ], :selected => params[:sort]) | ||
8 | + ) %> | ||
9 | +</div> | ||
10 | +<ul class="profile-list-<%= role %>" > | ||
11 | + <% users.each do |u| %> | ||
12 | + <%= profile_image_link(u) %> | ||
13 | + <% end %> | ||
14 | +</ul> | ||
15 | + | ||
16 | +<%= pagination_links users, :param_name => 'npage' %> |
app/views/profile/members.html.erb
1 | <div class="common-profile-list-block"> | 1 | <div class="common-profile-list-block"> |
2 | 2 | ||
3 | -<h1><%= _("%s's members") % profile.name %></h1> | 3 | +<h1><%= _("Members (%d)") % @profile_members.total_entries %></h1> |
4 | +<h2 class="community-name"><%= profile.name %></h2> | ||
4 | 5 | ||
5 | <% cache_timeout(profile.members_cache_key(params), 4.hours) do %> | 6 | <% cache_timeout(profile.members_cache_key(params), 4.hours) do %> |
6 | - <ul class='profile-list'> | ||
7 | - <% @members.each do |member| %> | ||
8 | - <%= profile_image_link(member) %> | ||
9 | - <% end %> | ||
10 | - </ul> | 7 | + <div class="profile-members-tabs-container"> |
8 | + <% tabs = [] %> | ||
9 | + | ||
10 | + <% div_members = content_tag :div, :class => "profile-members" do | ||
11 | + render :partial => 'profile_members_list', | ||
12 | + :locals => { | ||
13 | + :users => @profile_members, | ||
14 | + :role => "members" | ||
15 | + } | ||
16 | + end %> | ||
17 | + | ||
18 | + <% tabs << {:title => _("%d Members") % @profile_members.total_entries, | ||
19 | + :id => "members-tab", | ||
20 | + :content => div_members | ||
21 | + } %> | ||
11 | 22 | ||
12 | - <div id='pagination-profiles'> | ||
13 | - <%= pagination_links @members, :param_name => 'npage' %> | ||
14 | - </div> | 23 | + <% div_admins = content_tag :div, :class => "profile-admins" do |
24 | + render :partial => 'profile_members_list', | ||
25 | + :locals => { | ||
26 | + :users => @profile_admins, | ||
27 | + :role => "admins" | ||
28 | + } | ||
29 | + end %> | ||
30 | + | ||
31 | + <% tabs << {:title => _("%d Administrators") % @profile_admins.total_entries, | ||
32 | + :id => "admins-tab", | ||
33 | + :content => div_admins | ||
34 | + } %> | ||
35 | + | ||
36 | + <%= render_tabs(tabs) %> | ||
37 | + </div><!-- end of class="profile-members-tabs-container" --> | ||
15 | <% end %> | 38 | <% end %> |
16 | 39 | ||
17 | <% button_bar do %> | 40 | <% button_bar do %> |
@@ -26,4 +49,7 @@ | @@ -26,4 +49,7 @@ | ||
26 | <% end %> | 49 | <% end %> |
27 | <% end %> | 50 | <% end %> |
28 | 51 | ||
29 | -</div><!-- fim class="common-profile-list-block" --> | 52 | +<%= hidden_field_tag "profile_url", @profile_members_url %> |
53 | +</div><!-- end of class="common-profile-list-block" --> | ||
54 | + | ||
55 | +<%= javascript_include_tag "members_page.js" %> |
debian/changelog
lib/authenticated_system.rb
@@ -2,12 +2,12 @@ module AuthenticatedSystem | @@ -2,12 +2,12 @@ module AuthenticatedSystem | ||
2 | 2 | ||
3 | protected | 3 | protected |
4 | 4 | ||
5 | - # See impl. from http://stackoverflow.com/a/2513456/670229 | ||
6 | def self.included base | 5 | def self.included base |
7 | - base.around_filter do | 6 | + # See impl. from http://stackoverflow.com/a/2513456/670229 |
7 | + base.around_filter do |&block| | ||
8 | begin | 8 | begin |
9 | User.current = current_user | 9 | User.current = current_user |
10 | - yield | 10 | + block.call |
11 | ensure | 11 | ensure |
12 | # to address the thread variable leak issues in Puma/Thin webserver | 12 | # to address the thread variable leak issues in Puma/Thin webserver |
13 | User.current = nil | 13 | User.current = nil |
lib/noosfero/plugin.rb
@@ -241,6 +241,16 @@ class Noosfero::Plugin | @@ -241,6 +241,16 @@ class Noosfero::Plugin | ||
241 | nil | 241 | nil |
242 | end | 242 | end |
243 | 243 | ||
244 | + # -> Customize the way comments are counted for Profiles and Environment | ||
245 | + # considering more than just articles comments | ||
246 | + # Used on statistic block | ||
247 | + # Ex: a plugin may want that Communities receive comments themselves | ||
248 | + # as evaluations | ||
249 | + # returns = the number of comments to be sum on the statistics | ||
250 | + def more_comments_count owner | ||
251 | + nil | ||
252 | + end | ||
253 | + | ||
244 | # -> Adds tabs to the profile | 254 | # -> Adds tabs to the profile |
245 | # returns = { :title => title, :id => id, :content => content, :start => start } | 255 | # returns = { :title => title, :id => id, :content => content, :start => start } |
246 | # title = name that will be displayed. | 256 | # title = name that will be displayed. |
lib/noosfero/version.rb
plugins/ldap/README.md
@@ -13,6 +13,7 @@ Dependences | @@ -13,6 +13,7 @@ Dependences | ||
13 | See the Noosfero install file. After install Noosfero, install LDAP dependences: | 13 | See the Noosfero install file. After install Noosfero, install LDAP dependences: |
14 | 14 | ||
15 | $ gem install net-ldap -v 0.3.1 | 15 | $ gem install net-ldap -v 0.3.1 |
16 | +$ sudo apt-get install ruby-magic | ||
16 | 17 | ||
17 | Enable Plugin | 18 | Enable Plugin |
18 | ------------- | 19 | ------------- |
plugins/ldap/lib/ldap_authentication.rb
@@ -19,6 +19,7 @@ require 'rubygems' | @@ -19,6 +19,7 @@ require 'rubygems' | ||
19 | require 'iconv' | 19 | require 'iconv' |
20 | require 'net/ldap' | 20 | require 'net/ldap' |
21 | require 'net/ldap/dn' | 21 | require 'net/ldap/dn' |
22 | +require 'magic' | ||
22 | 23 | ||
23 | class LdapAuthentication | 24 | class LdapAuthentication |
24 | 25 | ||
@@ -134,7 +135,18 @@ class LdapAuthentication | @@ -134,7 +135,18 @@ class LdapAuthentication | ||
134 | 135 | ||
135 | def self.get_attr(entry, attr_name) | 136 | def self.get_attr(entry, attr_name) |
136 | if !attr_name.blank? | 137 | if !attr_name.blank? |
137 | - entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] | 138 | + val = entry[attr_name].is_a?(Array) ? entry[attr_name].first : entry[attr_name] |
139 | + if val.nil? | ||
140 | + Rails.logger.warn "LDAP entry #{entry.dn} has no attr #{attr_name}." | ||
141 | + nil | ||
142 | + elsif val == '' || val == ' ' | ||
143 | + Rails.logger.warn "LDAP entry #{entry.dn} has attr #{attr_name} empty." | ||
144 | + '' | ||
145 | + else | ||
146 | + charset = Magic.guess_string_mime_encoding(val) | ||
147 | + val.encode 'utf-8', charset, invalid: :replace, undef: :replace | ||
148 | + end | ||
138 | end | 149 | end |
139 | end | 150 | end |
151 | + | ||
140 | end | 152 | end |
plugins/ldap/test/unit/ldap_authentication_test.rb
@@ -2,141 +2,177 @@ require_relative '../test_helper' | @@ -2,141 +2,177 @@ require_relative '../test_helper' | ||
2 | 2 | ||
3 | class LdapAuthenticationTest < ActiveSupport::TestCase | 3 | class LdapAuthenticationTest < ActiveSupport::TestCase |
4 | 4 | ||
5 | + def pseudoEntry(data) | ||
6 | + entry = data.clone | ||
7 | + def entry.dn; 'testDN'; end | ||
8 | + entry | ||
9 | + end | ||
10 | + | ||
5 | def setup | 11 | def setup |
6 | @ldap_config = load_ldap_config | 12 | @ldap_config = load_ldap_config |
7 | end | 13 | end |
8 | 14 | ||
9 | - should "host be nil as default" do | 15 | + should 'host be nil as default' do |
10 | ldap = LdapAuthentication.new | 16 | ldap = LdapAuthentication.new |
11 | assert_nil ldap.host | 17 | assert_nil ldap.host |
12 | end | 18 | end |
13 | 19 | ||
14 | - should "create with host passed as parameter" do | 20 | + should 'create with host passed as parameter' do |
15 | value = 'http://myhost.com' | 21 | value = 'http://myhost.com' |
16 | ldap = LdapAuthentication.new('host' => value) | 22 | ldap = LdapAuthentication.new('host' => value) |
17 | assert_equal value, ldap.host | 23 | assert_equal value, ldap.host |
18 | end | 24 | end |
19 | 25 | ||
20 | - should "port be 389 as default" do | 26 | + should 'port be 389 as default' do |
21 | ldap = LdapAuthentication.new | 27 | ldap = LdapAuthentication.new |
22 | assert_equal 389, ldap.port | 28 | assert_equal 389, ldap.port |
23 | end | 29 | end |
24 | 30 | ||
25 | - should "create with port passed as parameter" do | 31 | + should 'create with port passed as parameter' do |
26 | value = 555 | 32 | value = 555 |
27 | ldap = LdapAuthentication.new('port' => value) | 33 | ldap = LdapAuthentication.new('port' => value) |
28 | assert_equal value, ldap.port | 34 | assert_equal value, ldap.port |
29 | end | 35 | end |
30 | 36 | ||
31 | - should "account be nil as default" do | 37 | + should 'account be nil as default' do |
32 | ldap = LdapAuthentication.new | 38 | ldap = LdapAuthentication.new |
33 | assert_nil ldap.account | 39 | assert_nil ldap.account |
34 | end | 40 | end |
35 | 41 | ||
36 | - should "create with account passed as parameter" do | 42 | + should 'create with account passed as parameter' do |
37 | value = 'uid=sector,ou=Service,ou=corp,dc=company,dc=com,dc=br' | 43 | value = 'uid=sector,ou=Service,ou=corp,dc=company,dc=com,dc=br' |
38 | ldap = LdapAuthentication.new('account' => value) | 44 | ldap = LdapAuthentication.new('account' => value) |
39 | assert_equal value, ldap.account | 45 | assert_equal value, ldap.account |
40 | end | 46 | end |
41 | 47 | ||
42 | - should "account_password be nil as default" do | 48 | + should 'account_password be nil as default' do |
43 | ldap = LdapAuthentication.new | 49 | ldap = LdapAuthentication.new |
44 | assert_nil ldap.account_password | 50 | assert_nil ldap.account_password |
45 | end | 51 | end |
46 | 52 | ||
47 | - should "create with account_password passed as parameter" do | 53 | + should 'create with account_password passed as parameter' do |
48 | value = 'password' | 54 | value = 'password' |
49 | ldap = LdapAuthentication.new('account_password' => value) | 55 | ldap = LdapAuthentication.new('account_password' => value) |
50 | assert_equal value, ldap.account_password | 56 | assert_equal value, ldap.account_password |
51 | end | 57 | end |
52 | 58 | ||
53 | - should "base_dn be nil as default" do | 59 | + should 'base_dn be nil as default' do |
54 | ldap = LdapAuthentication.new | 60 | ldap = LdapAuthentication.new |
55 | assert_nil ldap.base_dn | 61 | assert_nil ldap.base_dn |
56 | end | 62 | end |
57 | 63 | ||
58 | - should "create with base_dn passed as parameter" do | 64 | + should 'create with base_dn passed as parameter' do |
59 | value = 'dc=company,dc=com,dc=br' | 65 | value = 'dc=company,dc=com,dc=br' |
60 | ldap = LdapAuthentication.new('base_dn' => value) | 66 | ldap = LdapAuthentication.new('base_dn' => value) |
61 | assert_equal value, ldap.base_dn | 67 | assert_equal value, ldap.base_dn |
62 | end | 68 | end |
63 | 69 | ||
64 | - should "attr_login be nil as default" do | 70 | + should 'attr_login be nil as default' do |
65 | ldap = LdapAuthentication.new | 71 | ldap = LdapAuthentication.new |
66 | assert_nil ldap.attr_login | 72 | assert_nil ldap.attr_login |
67 | end | 73 | end |
68 | 74 | ||
69 | - should "create with attr_login passed as parameter" do | 75 | + should 'create with attr_login passed as parameter' do |
70 | value = 'uid' | 76 | value = 'uid' |
71 | ldap = LdapAuthentication.new('attr_login' => value) | 77 | ldap = LdapAuthentication.new('attr_login' => value) |
72 | assert_equal value, ldap.attr_login | 78 | assert_equal value, ldap.attr_login |
73 | end | 79 | end |
74 | 80 | ||
75 | - should "attr_fullname be nil as default" do | 81 | + should 'attr_fullname be nil as default' do |
76 | ldap = LdapAuthentication.new | 82 | ldap = LdapAuthentication.new |
77 | assert_nil ldap.attr_fullname | 83 | assert_nil ldap.attr_fullname |
78 | end | 84 | end |
79 | 85 | ||
80 | - should "create with attr_fullname passed as parameter" do | 86 | + should 'create with attr_fullname passed as parameter' do |
81 | value = 'Noosfero System' | 87 | value = 'Noosfero System' |
82 | ldap = LdapAuthentication.new('attr_fullname' => value) | 88 | ldap = LdapAuthentication.new('attr_fullname' => value) |
83 | assert_equal value, ldap.attr_fullname | 89 | assert_equal value, ldap.attr_fullname |
84 | end | 90 | end |
85 | 91 | ||
86 | - should "attr_mail be nil as default" do | 92 | + should 'attr_mail be nil as default' do |
87 | ldap = LdapAuthentication.new | 93 | ldap = LdapAuthentication.new |
88 | assert_nil ldap.attr_mail | 94 | assert_nil ldap.attr_mail |
89 | end | 95 | end |
90 | 96 | ||
91 | - should "create with attr_mail passed as parameter" do | 97 | + should 'create with attr_mail passed as parameter' do |
92 | value = 'test@noosfero.com' | 98 | value = 'test@noosfero.com' |
93 | ldap = LdapAuthentication.new('attr_mail' => value) | 99 | ldap = LdapAuthentication.new('attr_mail' => value) |
94 | assert_equal value, ldap.attr_mail | 100 | assert_equal value, ldap.attr_mail |
95 | end | 101 | end |
96 | 102 | ||
97 | - should "onthefly_register be false as default" do | 103 | + should 'onthefly_register be false as default' do |
98 | ldap = LdapAuthentication.new | 104 | ldap = LdapAuthentication.new |
99 | refute ldap.onthefly_register | 105 | refute ldap.onthefly_register |
100 | end | 106 | end |
101 | 107 | ||
102 | - should "create with onthefly_register passed as parameter" do | 108 | + should 'create with onthefly_register passed as parameter' do |
103 | value = true | 109 | value = true |
104 | ldap = LdapAuthentication.new('onthefly_register' => value) | 110 | ldap = LdapAuthentication.new('onthefly_register' => value) |
105 | assert_equal value, ldap.onthefly_register | 111 | assert_equal value, ldap.onthefly_register |
106 | end | 112 | end |
107 | 113 | ||
108 | - should "filter be nil as default" do | 114 | + should 'filter be nil as default' do |
109 | ldap = LdapAuthentication.new | 115 | ldap = LdapAuthentication.new |
110 | assert_nil ldap.filter | 116 | assert_nil ldap.filter |
111 | end | 117 | end |
112 | 118 | ||
113 | - should "create with filter passed as parameter" do | 119 | + should 'create with filter passed as parameter' do |
114 | value = 'test' | 120 | value = 'test' |
115 | ldap = LdapAuthentication.new('filter' => value) | 121 | ldap = LdapAuthentication.new('filter' => value) |
116 | assert_equal value, ldap.filter | 122 | assert_equal value, ldap.filter |
117 | end | 123 | end |
118 | 124 | ||
119 | - should "tls be false as default" do | 125 | + should 'tls be false as default' do |
120 | ldap = LdapAuthentication.new | 126 | ldap = LdapAuthentication.new |
121 | refute ldap.tls | 127 | refute ldap.tls |
122 | end | 128 | end |
123 | 129 | ||
124 | - should "create with tls passed as parameter" do | 130 | + should 'create with tls passed as parameter' do |
125 | value = true | 131 | value = true |
126 | ldap = LdapAuthentication.new('tls' => value) | 132 | ldap = LdapAuthentication.new('tls' => value) |
127 | assert_equal value, ldap.tls | 133 | assert_equal value, ldap.tls |
128 | end | 134 | end |
129 | 135 | ||
130 | - should "onthefly_register? return true if onthefly_register is true" do | 136 | + should 'onthefly_register? return true if onthefly_register is true' do |
131 | ldap = LdapAuthentication.new('onthefly_register' => true) | 137 | ldap = LdapAuthentication.new('onthefly_register' => true) |
132 | assert ldap.onthefly_register? | 138 | assert ldap.onthefly_register? |
133 | end | 139 | end |
134 | 140 | ||
135 | - should "onthefly_register? return false if onthefly_register is false" do | 141 | + should 'onthefly_register? return false if onthefly_register is false' do |
136 | ldap = LdapAuthentication.new('onthefly_register' => false) | 142 | ldap = LdapAuthentication.new('onthefly_register' => false) |
137 | refute ldap.onthefly_register? | 143 | refute ldap.onthefly_register? |
138 | end | 144 | end |
139 | 145 | ||
146 | + should 'detect and convert non utf-8 charset from ldap' do | ||
147 | + entry = pseudoEntry('name' => "Jos\xE9 Jo\xE3o") | ||
148 | + name = LdapAuthentication.get_attr entry, 'name' | ||
149 | + assert_equal name, 'José João' | ||
150 | + end | ||
151 | + | ||
152 | + should 'dont crash when entry key is empty string' do | ||
153 | + entry = pseudoEntry('name' => "") | ||
154 | + name = LdapAuthentication.get_attr entry, 'name' | ||
155 | + assert_equal name, '' | ||
156 | + end | ||
157 | + | ||
158 | + should 'dont crash when entry key has only a space char' do | ||
159 | + entry = pseudoEntry('name' => " ") | ||
160 | + name = LdapAuthentication.get_attr entry, 'name' | ||
161 | + assert_equal name, '' | ||
162 | + end | ||
163 | + | ||
164 | + should 'dont crash when entry key is nil' do | ||
165 | + entry = pseudoEntry('name' => nil) | ||
166 | + name = LdapAuthentication.get_attr entry, 'name' | ||
167 | + assert_equal name, nil | ||
168 | + end | ||
169 | + | ||
170 | + should 'dont crash when entry key does not exists' do | ||
171 | + entry = pseudoEntry({}) | ||
172 | + name = LdapAuthentication.get_attr entry, 'name' | ||
173 | + assert_equal name, nil | ||
174 | + end | ||
175 | + | ||
140 | if ldap_configured? | 176 | if ldap_configured? |
141 | should 'return the user attributes' do | 177 | should 'return the user attributes' do |
142 | auth = LdapAuthentication.new(@ldap_config['server']) | 178 | auth = LdapAuthentication.new(@ldap_config['server']) |
plugins/organization_ratings/controllers/organization_ratings_plugin_admin_controller.rb
0 → 100644
@@ -0,0 +1,19 @@ | @@ -0,0 +1,19 @@ | ||
1 | +class OrganizationRatingsPluginAdminController < PluginAdminController | ||
2 | + | ||
3 | + include RatingsHelper | ||
4 | + helper :ratings | ||
5 | + append_view_path File.join(File.dirname(__FILE__) + '/../views') | ||
6 | + | ||
7 | + def index | ||
8 | + end | ||
9 | + | ||
10 | + def update | ||
11 | + if env_organization_ratings_config.update_attributes(params[:organization_ratings_config]) | ||
12 | + session[:notice] = _('Configuration updated successfully.') | ||
13 | + else | ||
14 | + session[:notice] = _('Configuration could not be saved.') | ||
15 | + end | ||
16 | + render :action => 'index' | ||
17 | + end | ||
18 | + | ||
19 | +end | ||
0 | \ No newline at end of file | 20 | \ No newline at end of file |
plugins/organization_ratings/controllers/organization_ratings_plugin_profile_controller.rb
0 → 100644
@@ -0,0 +1,76 @@ | @@ -0,0 +1,76 @@ | ||
1 | +class OrganizationRatingsPluginProfileController < ProfileController | ||
2 | + include RatingsHelper | ||
3 | + helper :ratings | ||
4 | + | ||
5 | + def new_rating | ||
6 | + @rating_available = user_can_rate_now? | ||
7 | + @users_ratings = get_ratings(profile.id).paginate( | ||
8 | + :per_page => env_organization_ratings_config.per_page, | ||
9 | + :page => params[:npage] | ||
10 | + ) | ||
11 | + if request.post? | ||
12 | + if @rating_available | ||
13 | + create_new_rate | ||
14 | + else | ||
15 | + session[:notice] = _("You can not vote on this %s") % profile.class.name | ||
16 | + end | ||
17 | + end | ||
18 | + end | ||
19 | + | ||
20 | + private | ||
21 | + | ||
22 | + def user_can_rate_now? | ||
23 | + return false unless user | ||
24 | + ratings = OrganizationRating.where( | ||
25 | + :organization_id => profile.id, | ||
26 | + :person_id => user.id | ||
27 | + ) | ||
28 | + | ||
29 | + return false if (!ratings.empty? && env_organization_ratings_config.vote_once) | ||
30 | + | ||
31 | + if ratings.empty? | ||
32 | + true | ||
33 | + else | ||
34 | + elapsed_time_since_last_rating = Time.zone.now - ratings.last.created_at | ||
35 | + elapsed_time_since_last_rating > env_organization_ratings_config.cooldown.hours | ||
36 | + end | ||
37 | + end | ||
38 | + | ||
39 | + def create_new_rate | ||
40 | + rating = OrganizationRating.new(params[:organization_rating]) | ||
41 | + rating.person = current_user.person | ||
42 | + rating.organization = profile | ||
43 | + rating.value = params[:organization_rating_value] if params[:organization_rating_value] | ||
44 | + | ||
45 | + if rating.save | ||
46 | + create_rating_comment(rating) | ||
47 | + session[:notice] = _("%s successfully rated!") % profile.name | ||
48 | + else | ||
49 | + session[:notice] = _("Sorry, there were problems rating this profile.") | ||
50 | + end | ||
51 | + | ||
52 | + redirect_to :controller => 'profile', :action => 'index' | ||
53 | + end | ||
54 | + | ||
55 | + def create_rating_comment(rating) | ||
56 | + if params[:comments] | ||
57 | + comment_task = CreateOrganizationRatingComment.create!( | ||
58 | + params[:comments].merge( | ||
59 | + :requestor => rating.person, | ||
60 | + :organization_rating_id => rating.id, | ||
61 | + :target => rating.organization | ||
62 | + ) | ||
63 | + ) | ||
64 | + comment_task.finish if can_perform?(params) | ||
65 | + end | ||
66 | + end | ||
67 | + | ||
68 | + def can_perform? (params) | ||
69 | + (params[:comments][:body].blank? || | ||
70 | + !env_organization_ratings_config.are_moderated) | ||
71 | + end | ||
72 | + | ||
73 | + def permission | ||
74 | + :manage_memberships | ||
75 | + end | ||
76 | +end |
plugins/organization_ratings/db/migrate/20150830225546_create_organization_ratings.rb
0 → 100644
@@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
1 | +class CreateOrganizationRatings < ActiveRecord::Migration | ||
2 | + def change | ||
3 | + create_table :organization_ratings do |t| | ||
4 | + t.belongs_to :organization | ||
5 | + t.belongs_to :person | ||
6 | + t.belongs_to :comment | ||
7 | + t.integer :value | ||
8 | + | ||
9 | + t.timestamps | ||
10 | + end | ||
11 | + end | ||
12 | +end |
plugins/organization_ratings/db/migrate/20150830225733_create_organization_ratings_config.rb
0 → 100644
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +class CreateOrganizationRatingsConfig < ActiveRecord::Migration | ||
2 | + | ||
3 | + def change | ||
4 | + create_table :organization_ratings_configs do |t| | ||
5 | + t.belongs_to :environment | ||
6 | + t.integer :cooldown, :integer, :default => 24 | ||
7 | + t.integer :default_rating, :integer, :default => 1 | ||
8 | + t.string :order, :string, :default => "recent" | ||
9 | + t.integer :per_page, :integer, :default => 10 | ||
10 | + t.boolean :vote_once, :boolean, :default => false | ||
11 | + t.boolean :are_moderated, :boolean, :default => true | ||
12 | + end | ||
13 | + end | ||
14 | +end |
plugins/organization_ratings/db/migrate/20150830230047_add_comments_count_to_profile.rb
0 → 100644
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +class AddCommentsCountToProfile < ActiveRecord::Migration | ||
2 | + def self.up | ||
3 | + change_table :profiles do |t| | ||
4 | + t.integer :comments_count | ||
5 | + end | ||
6 | + end | ||
7 | + | ||
8 | + def self.down | ||
9 | + remove_column :profiles, :comments_count | ||
10 | + end | ||
11 | +end | ||
0 | \ No newline at end of file | 12 | \ No newline at end of file |
plugins/organization_ratings/features/rate_community.feature
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +Feature: rate_community | ||
2 | + As a user | ||
3 | + I want to be able rate a community | ||
4 | + So that users can see my feedback about that community | ||
5 | + | ||
6 | + Background: | ||
7 | + Given plugin "OrganizationRatings" is enabled on environment | ||
8 | + Given the following user | ||
9 | + | login | name | | ||
10 | + | joaosilva | Joao Silva | | ||
11 | + And the following community | ||
12 | + | identifier | name | | ||
13 | + | mycommunity | My Community | | ||
14 | + And the following blocks | ||
15 | + | owner | type | | ||
16 | + | mycommunity | AverageRatingBlock | | ||
17 | + | mycommunity | OrganizationRatingsBlock | | ||
18 | + And the environment domain is "localhost" | ||
19 | + And I am logged in as "joaosilva" | ||
20 | + | ||
21 | + @selenium | ||
22 | + Scenario: display rate button inside average block | ||
23 | + Given I am on mycommunity's homepage | ||
24 | + Then I should see "Rate this Community" within ".average-rating-block" | ||
25 | + And I should see "Be the first to rate" within ".average-rating-block" | ||
26 | + | ||
27 | + @selenium | ||
28 | + Scenario: display rate button inside communities ratings block | ||
29 | + Given I am on mycommunity's homepage | ||
30 | + Then I should see "Rate Community" within ".make-report-block" |
plugins/organization_ratings/lib/average_rating_block.rb
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +class AverageRatingBlock < Block | ||
2 | + include RatingsHelper | ||
3 | + | ||
4 | + def self.description | ||
5 | + _('Organization Average Rating') | ||
6 | + end | ||
7 | + | ||
8 | + def help | ||
9 | + _('This block displays the organization average rating.') | ||
10 | + end | ||
11 | + | ||
12 | + def content(args = {}) | ||
13 | + profile_identifier = self.owner.identifier | ||
14 | + average_rating = OrganizationRating.average_rating self.owner.id | ||
15 | + | ||
16 | + proc do | ||
17 | + render( | ||
18 | + :file => 'blocks/display_organization_average_rating', | ||
19 | + :locals => { | ||
20 | + :profile_identifier => profile_identifier, | ||
21 | + :average_rating => average_rating | ||
22 | + } | ||
23 | + ) | ||
24 | + end | ||
25 | + end | ||
26 | + | ||
27 | + def cacheable? | ||
28 | + false | ||
29 | + end | ||
30 | +end |
plugins/organization_ratings/lib/create_organization_rating_comment.rb
0 → 100644
@@ -0,0 +1,131 @@ | @@ -0,0 +1,131 @@ | ||
1 | +class CreateOrganizationRatingComment < Task | ||
2 | + include Rails.application.routes.url_helpers | ||
3 | + | ||
4 | + validates_presence_of :requestor_id, :organization_rating_id, :target_id | ||
5 | + | ||
6 | + settings_items :organization_rating_id, :type => Integer, :default => nil | ||
7 | + settings_items :organization_rating_comment_id, :type => Integer, :default => nil | ||
8 | + | ||
9 | + attr_accessible :organization_rating_id, :body, :requestor | ||
10 | + attr_accessible :reject_explanation, :target | ||
11 | + | ||
12 | + before_save :update_comment_body | ||
13 | + | ||
14 | + DATA_FIELDS = ['body'] | ||
15 | + DATA_FIELDS.each do |field| | ||
16 | + settings_items field.to_sym | ||
17 | + end | ||
18 | + | ||
19 | + def update_comment_body | ||
20 | + if self.organization_rating_comment_id.nil? | ||
21 | + create_comment | ||
22 | + else | ||
23 | + comment = Comment.find_by_id(self.organization_rating_comment_id) | ||
24 | + comment.body = get_comment_message | ||
25 | + comment.save | ||
26 | + end | ||
27 | + end | ||
28 | + | ||
29 | + def create_comment | ||
30 | + if (self.body && !self.body.blank?) | ||
31 | + comment_body = _("Comment waiting for approval") | ||
32 | + comment = Comment.create!(:source => self.target, :body => comment_body, :author => self.requestor) | ||
33 | + | ||
34 | + | ||
35 | + self.organization_rating_comment_id = comment.id | ||
36 | + link_comment_with_its_rating(comment) | ||
37 | + end | ||
38 | + end | ||
39 | + | ||
40 | + def link_comment_with_its_rating(user_comment) | ||
41 | + rating = OrganizationRating.find(self.organization_rating_id) | ||
42 | + rating.comment = user_comment | ||
43 | + rating.save | ||
44 | + end | ||
45 | + | ||
46 | + def get_comment_message | ||
47 | + if self.status == Status::CANCELLED | ||
48 | + _("Comment rejected") | ||
49 | + elsif self.status == Status::FINISHED | ||
50 | + self.body | ||
51 | + else | ||
52 | + _("No comment") | ||
53 | + end | ||
54 | + end | ||
55 | + | ||
56 | + def accept_details | ||
57 | + true | ||
58 | + end | ||
59 | + | ||
60 | + def title | ||
61 | + _("New Comment") | ||
62 | + end | ||
63 | + | ||
64 | + def information | ||
65 | + message = _("<a href=%{requestor_url}>%{requestor}</a> wants to create a comment in this %{target_class}") % | ||
66 | + {:requestor_url => url_for(self.requestor.url), :requestor => self.requestor.name, :target_class => self.target.class.name.downcase} | ||
67 | + | ||
68 | + {:message => message} | ||
69 | + end | ||
70 | + | ||
71 | + def reject_details | ||
72 | + true | ||
73 | + end | ||
74 | + | ||
75 | + def icon | ||
76 | + {:type => :profile_image, :profile => requestor, :url => requestor.url} | ||
77 | + end | ||
78 | + | ||
79 | + # tells if this request was rejected | ||
80 | + def rejected? | ||
81 | + self.status == Task::Status::CANCELLED | ||
82 | + end | ||
83 | + | ||
84 | + # tells if this request was appoved | ||
85 | + def approved? | ||
86 | + self.status == Task::Status::FINISHED | ||
87 | + end | ||
88 | + | ||
89 | + def target_notification_description | ||
90 | + _("%{requestor} wants to create a comment in this \"%{target}\"") % | ||
91 | + {:requestor => self.requestor.name, :target => self.target.class.name.downcase } | ||
92 | + end | ||
93 | + | ||
94 | + def target_notification_message | ||
95 | + _("User \"%{user}\" just requested to create a comment in the %{target_class} | ||
96 | + \"%{target_name}\". | ||
97 | + You have to approve or reject it through the \"Pending Validations\" | ||
98 | + section in your control panel.\n") % | ||
99 | + { :user => self.requestor.name, :target_class => self.target.class.name.downcase, :target_name => self.target.name } | ||
100 | + end | ||
101 | + | ||
102 | + def task_created_message | ||
103 | + _("Your request for commenting at %{target} was | ||
104 | + just sent. Environment administrator will receive it and will approve or | ||
105 | + reject your request according to his methods and criteria. | ||
106 | + You will be notified as soon as environment administrator has a position | ||
107 | + about your request.") % | ||
108 | + { :target => self.target.name } | ||
109 | + end | ||
110 | + | ||
111 | + def task_cancelled_message | ||
112 | + _("Your request for commenting at %{target} was | ||
113 | + not approved by the environment administrator. The following explanation | ||
114 | + was given: \n\n%{explanation}") % | ||
115 | + { :target => self.target.name, | ||
116 | + :explanation => self.reject_explanation } | ||
117 | + end | ||
118 | + | ||
119 | + def task_finished_message | ||
120 | + _('Your request for commenting was approved. | ||
121 | + You can access %{url} to see your comment.') % | ||
122 | + { :url => ratings_url } | ||
123 | + end | ||
124 | + | ||
125 | + private | ||
126 | + | ||
127 | + def ratings_url | ||
128 | + url = url_for(self.target.public_profile_url) + "/plugin/organization_ratings/new_rating" | ||
129 | + end | ||
130 | + | ||
131 | +end |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +class OrganizationRating < ActiveRecord::Base | ||
2 | + belongs_to :person | ||
3 | + belongs_to :organization | ||
4 | + belongs_to :comment | ||
5 | + | ||
6 | + attr_accessible :value, :person, :organization, :comment | ||
7 | + | ||
8 | + validates :value, | ||
9 | + :presence => true, :inclusion => { | ||
10 | + in: 1..5, message: _("must be between 1 and 5") | ||
11 | + } | ||
12 | + | ||
13 | + validates :organization_id, :person_id, | ||
14 | + :presence => true | ||
15 | + | ||
16 | + | ||
17 | + def self.average_rating organization_id | ||
18 | + average = OrganizationRating.where(organization_id: organization_id).average(:value) | ||
19 | + | ||
20 | + if average | ||
21 | + (average - average.truncate) >= 0.5 ? average.ceil : average.floor | ||
22 | + end | ||
23 | + end | ||
24 | + | ||
25 | +end |
plugins/organization_ratings/lib/organization_ratings_block.rb
0 → 100644
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +class OrganizationRatingsBlock < Block | ||
2 | + include RatingsHelper | ||
3 | + | ||
4 | + def self.description | ||
5 | + _('Organization Ratings') | ||
6 | + end | ||
7 | + | ||
8 | + def help | ||
9 | + _('This block displays the community ratings.') | ||
10 | + end | ||
11 | + | ||
12 | + def content(args = {}) | ||
13 | + block = self | ||
14 | + | ||
15 | + proc do | ||
16 | + render( | ||
17 | + :file => 'blocks/organization_ratings_block', | ||
18 | + :locals => {:block => block} | ||
19 | + ) | ||
20 | + end | ||
21 | + end | ||
22 | + | ||
23 | + def limit_number_of_ratings | ||
24 | + env_organization_ratings_config.per_page | ||
25 | + end | ||
26 | + | ||
27 | + def cacheable? | ||
28 | + false | ||
29 | + end | ||
30 | +end |
plugins/organization_ratings/lib/organization_ratings_config.rb
0 → 100644
@@ -0,0 +1,53 @@ | @@ -0,0 +1,53 @@ | ||
1 | +class OrganizationRatingsConfig < ActiveRecord::Base | ||
2 | + | ||
3 | + belongs_to :environment | ||
4 | + | ||
5 | + attr_accessible :cooldown, :default_rating, :order, :per_page | ||
6 | + attr_accessible :vote_once, :are_moderated, :environment_id | ||
7 | + | ||
8 | + ORDER_OPTIONS = {recent: _('More Recent'), best: _('Best Ratings')} | ||
9 | + | ||
10 | + MINIMUM_RATING = 1 | ||
11 | + MAX_COOLDOWN = 1000 | ||
12 | + | ||
13 | + validates :default_rating, | ||
14 | + :presence => true, :numericality => { | ||
15 | + greater_than_or_equal_to: MINIMUM_RATING, | ||
16 | + less_than_or_equal_to: 5 | ||
17 | + } | ||
18 | + | ||
19 | + validates :cooldown, | ||
20 | + :presence => true, :numericality => { | ||
21 | + greater_than_or_equal_to: 0, | ||
22 | + less_than_or_equal_to: MAX_COOLDOWN | ||
23 | + } | ||
24 | + | ||
25 | + validates :per_page, | ||
26 | + :presence => true, :numericality => { | ||
27 | + :greater_than_or_equal_to => 5, | ||
28 | + :less_than_or_equal_to => 20 | ||
29 | + } | ||
30 | + | ||
31 | + | ||
32 | + def order_options | ||
33 | + ORDER_OPTIONS | ||
34 | + end | ||
35 | + | ||
36 | + def minimum_ratings | ||
37 | + MINIMUM_RATING | ||
38 | + end | ||
39 | + | ||
40 | + def max_cooldown | ||
41 | + MAX_COOLDOWN | ||
42 | + end | ||
43 | + | ||
44 | + class << self | ||
45 | + def instance | ||
46 | + environment = Environment.default | ||
47 | + environment.organization_ratings_config || create(environment_id: environment.id) | ||
48 | + end | ||
49 | + | ||
50 | + private :new | ||
51 | + end | ||
52 | + | ||
53 | +end |
plugins/organization_ratings/lib/organization_ratings_plugin.rb
0 → 100644
@@ -0,0 +1,73 @@ | @@ -0,0 +1,73 @@ | ||
1 | +class OrganizationRatingsPlugin < Noosfero::Plugin | ||
2 | + include Noosfero::Plugin::HotSpot | ||
3 | + | ||
4 | + def self.plugin_name | ||
5 | + "Organization Ratings" | ||
6 | + end | ||
7 | + | ||
8 | + def self.plugin_description | ||
9 | + _("A plugin that allows you to rate a organization and comment about it.") | ||
10 | + end | ||
11 | + | ||
12 | + module Hotspots | ||
13 | + def organization_ratings_plugin_comments_extra_fields | ||
14 | + nil | ||
15 | + end | ||
16 | + | ||
17 | + def organization_ratings_title | ||
18 | + nil | ||
19 | + end | ||
20 | + | ||
21 | + def organization_ratings_plugin_star_message | ||
22 | + nil | ||
23 | + end | ||
24 | + | ||
25 | + def organization_ratings_plugin_extra_fields_show_data user_rating | ||
26 | + nil | ||
27 | + end | ||
28 | + end | ||
29 | + | ||
30 | + # Plugin Hotspot to display the average rating | ||
31 | + def display_organization_average_rating organization | ||
32 | + unless organization.nil? | ||
33 | + average_rating = OrganizationRating.average_rating organization.id | ||
34 | + | ||
35 | + Proc::new { | ||
36 | + render :file => 'blocks/display_organization_average_rating', | ||
37 | + :locals => { | ||
38 | + :profile_identifier => organization.identifier, | ||
39 | + :average_rating => average_rating | ||
40 | + } | ||
41 | + } | ||
42 | + end | ||
43 | + end | ||
44 | + | ||
45 | + def more_comments_count owner | ||
46 | + if owner.kind_of?(Environment) then | ||
47 | + owner.profiles.sum(:comments_count) | ||
48 | + elsif owner.kind_of?(Profile) then | ||
49 | + owner.comments_count | ||
50 | + else | ||
51 | + 0 | ||
52 | + end | ||
53 | + end | ||
54 | + | ||
55 | + def self.extra_blocks | ||
56 | + { | ||
57 | + OrganizationRatingsBlock => {:type => [Enterprise, Community], :position => ['1']}, | ||
58 | + AverageRatingBlock => {:type => [Enterprise, Community]} | ||
59 | + } | ||
60 | + end | ||
61 | + | ||
62 | + def stylesheet? | ||
63 | + true | ||
64 | + end | ||
65 | + | ||
66 | + def js_files | ||
67 | + %w( | ||
68 | + public/rate.js | ||
69 | + public/comunities_rating_management.js | ||
70 | + ) | ||
71 | + end | ||
72 | + | ||
73 | +end |
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +module RatingsHelper | ||
2 | + | ||
3 | + def env_organization_ratings_config | ||
4 | + OrganizationRatingsConfig.instance | ||
5 | + end | ||
6 | + | ||
7 | + def get_ratings (profile_id) | ||
8 | + order_options = env_organization_ratings_config.order_options | ||
9 | + if env_organization_ratings_config.order.downcase == order_options[:recent] | ||
10 | + ratings = OrganizationRating.where(organization_id: profile_id).order("value DESC") | ||
11 | + else | ||
12 | + ratings = OrganizationRating.where(organization_id: profile_id).order("created_at DESC") | ||
13 | + end | ||
14 | + end | ||
15 | +end | ||
0 | \ No newline at end of file | 16 | \ No newline at end of file |
529 Bytes
509 Bytes
642 Bytes
642 Bytes
637 Bytes
637 Bytes
2.48 KB
plugins/organization_ratings/public/organization_rating_management.js
0 → 100644
@@ -0,0 +1,35 @@ | @@ -0,0 +1,35 @@ | ||
1 | +(function($) { | ||
2 | + "use strict"; | ||
3 | + | ||
4 | + var VoteOnce = { | ||
5 | + init: function() { | ||
6 | + this.cacheDom(); | ||
7 | + this.setEvents(); | ||
8 | + }, | ||
9 | + | ||
10 | + | ||
11 | + cacheDom: function() { | ||
12 | + this.$vote_once_checkbox = $("#environment_organization_ratings_vote_once"); | ||
13 | + this.$hours_timer_input = $("#environment_organization_ratings_cooldown"); | ||
14 | + }, | ||
15 | + | ||
16 | + | ||
17 | + setEvents: function() { | ||
18 | + this.$vote_once_checkbox.on("click", this.verifyHoursTimerDisable.bind(this)); | ||
19 | + }, | ||
20 | + | ||
21 | + | ||
22 | + verifyHoursTimerDisable: function() { | ||
23 | + if (this.$vote_once_checkbox.is(":checked")) { | ||
24 | + this.$hours_timer_input.attr("disabled", "disabled"); | ||
25 | + } else { | ||
26 | + this.$hours_timer_input.removeAttr("disabled"); | ||
27 | + } | ||
28 | + } | ||
29 | + } | ||
30 | + | ||
31 | + | ||
32 | + $(document).ready(function() { | ||
33 | + VoteOnce.init(); | ||
34 | + }); | ||
35 | +}) (jQuery); |
@@ -0,0 +1,122 @@ | @@ -0,0 +1,122 @@ | ||
1 | +;(function($, undefined) { | ||
2 | + "use strict"; | ||
3 | + | ||
4 | + /* | ||
5 | + * All global data that are used in the stars feature. | ||
6 | + */ | ||
7 | + var DATA = { | ||
8 | + selected_rate: 0, // The actual selected star when the user click on a star | ||
9 | + maximum_stars: 5, // (const) The maximum number of allowed stars | ||
10 | + minimum_stars: 1, // (const) The minimum number of allowed stars | ||
11 | + DATA_RATE_ATTRIBUTE: "data-star-rate", // (const) The data attribute with the star rate | ||
12 | + NOT_SELECTED_VALUE: 0 // (const) The value when there is no selected rate | ||
13 | + } | ||
14 | + | ||
15 | + | ||
16 | + /* | ||
17 | + * Prepare the global data that are variable. | ||
18 | + * If the user already rated the organization, set the selected_rate as the rated value | ||
19 | + */ | ||
20 | + function set_global_data() { | ||
21 | + var selected_rate = parseInt($("#selected-star-rate").val()); | ||
22 | + var minimum_stars = parseInt($("#minimum_stars").val()); | ||
23 | + DATA.selected_rate = selected_rate; | ||
24 | + DATA.minimum_stars = minimum_stars; | ||
25 | + } | ||
26 | + | ||
27 | + | ||
28 | + /* | ||
29 | + * Given a start rate, an end rate and the elements, it makes a regex that filter | ||
30 | + * the elements by the given range and returns it. | ||
31 | + */ | ||
32 | + function star_filter(start, end, elements) { | ||
33 | + var test_regex = undefined; | ||
34 | + | ||
35 | + // Verify if it is a valid range and makes its range regex: /[start-end]/ | ||
36 | + if (end >= start) { | ||
37 | + test_regex = new RegExp("["+(start)+"-"+(end)+"]"); | ||
38 | + } else { | ||
39 | + // If the range is invalid, make a regex that will return no element | ||
40 | + test_regex = new RegExp("[]"); | ||
41 | + } | ||
42 | + | ||
43 | + // Filter the elements that are in the given range | ||
44 | + var result = elements.filter(function(i, element) { | ||
45 | + var rate = parseInt(element.getAttribute(DATA.DATA_RATE_ATTRIBUTE)); | ||
46 | + | ||
47 | + return test_regex.test(rate); | ||
48 | + }); | ||
49 | + | ||
50 | + return result; | ||
51 | + } | ||
52 | + | ||
53 | + | ||
54 | + /* | ||
55 | + * Show or hide the stars depending on the mouse position and the limit rate. | ||
56 | + * Given the mouseover rate, the limit rate and the css classes to be swapped, | ||
57 | + * | ||
58 | + * It verify if the user already selected a star rate: | ||
59 | + * If true: | ||
60 | + * It swap the css classes from the selected star up to the given limit rate | ||
61 | + * If false: | ||
62 | + * It swap the css classes from the minimum rate up to the mouseover rate | ||
63 | + */ | ||
64 | + function change_stars_class(rate_mouseover, limit_rate, remove_class, add_class) { | ||
65 | + var previous_stars = undefined; | ||
66 | + | ||
67 | + // The default not selected rate value is 0 and minimum is 1. | ||
68 | + if (DATA.selected_rate >= DATA.minimum_stars) { | ||
69 | + previous_stars = star_filter(DATA.selected_rate+1, limit_rate, $("."+remove_class)); | ||
70 | + } else { | ||
71 | + previous_stars = star_filter(DATA.minimum_stars, rate_mouseover, $("."+remove_class)); | ||
72 | + } | ||
73 | + | ||
74 | + previous_stars.switchClass(remove_class, add_class); | ||
75 | + } | ||
76 | + | ||
77 | + | ||
78 | + /* | ||
79 | + * Sets the stars mouse events. | ||
80 | + */ | ||
81 | + function set_star_hover_actions() { | ||
82 | + $(".star-negative, .star-positive") | ||
83 | + .on("mouseover", function() { // On mouse over, show the current rate star | ||
84 | + var rate_mouseover = parseInt(this.getAttribute(DATA.DATA_RATE_ATTRIBUTE)); | ||
85 | + | ||
86 | + change_stars_class(rate_mouseover, rate_mouseover, "star-negative", "star-positive"); | ||
87 | + }) | ||
88 | + | ||
89 | + .on("mouseout", function() { // On mouse out, hide the stars | ||
90 | + var rate_mouseover = parseInt(this.getAttribute(DATA.DATA_RATE_ATTRIBUTE)); | ||
91 | + | ||
92 | + change_stars_class(rate_mouseover, DATA.maximum_stars, "star-positive", "star-negative"); | ||
93 | + }) | ||
94 | + | ||
95 | + .on("click", function() { // On mouse click, set the selected star rate | ||
96 | + var rate_mouseover = parseInt(this.getAttribute(DATA.DATA_RATE_ATTRIBUTE)); | ||
97 | + | ||
98 | + // If the new rate is different from actual, update it | ||
99 | + if (rate_mouseover !== DATA.selected_rate && rate_mouseover > DATA.minimum_stars) { | ||
100 | + DATA.selected_rate = rate_mouseover; | ||
101 | + } else { // or else, uncheck it | ||
102 | + DATA.selected_rate = DATA.minimum_stars; | ||
103 | + } | ||
104 | + | ||
105 | + // Mark the selected_rate | ||
106 | + $("#selected-star-rate").val(DATA.selected_rate); | ||
107 | + | ||
108 | + var star_notice = $(".star-notice"); | ||
109 | + star_notice.find("span").html(DATA.selected_rate); | ||
110 | + star_notice.removeClass("star-hide"); | ||
111 | + }); | ||
112 | + } | ||
113 | + | ||
114 | + | ||
115 | + /* | ||
116 | + * When the page DOM is ready, set all the stars events | ||
117 | + */ | ||
118 | + $(document).ready(function() { | ||
119 | + set_global_data(); | ||
120 | + set_star_hover_actions(); | ||
121 | + }); | ||
122 | +}) (jQuery); |
@@ -0,0 +1,200 @@ | @@ -0,0 +1,200 @@ | ||
1 | +.star-container { | ||
2 | + width: 100%; | ||
3 | + height: 20px; | ||
4 | +} | ||
5 | + | ||
6 | +.star-negative, .star-positive { | ||
7 | + width: 20px; | ||
8 | + height: 20px; | ||
9 | + background-repeat: no-repeat; | ||
10 | + margin-right: 2px; | ||
11 | + position: relative; | ||
12 | + float: left; | ||
13 | + cursor: pointer; | ||
14 | +} | ||
15 | + | ||
16 | +.star-negative { | ||
17 | + background-image: url('public/images/star-negative.png'); | ||
18 | +} | ||
19 | + | ||
20 | +.star-positive { | ||
21 | + background-image: url('public/images/star-positive.png'); | ||
22 | +} | ||
23 | + | ||
24 | +.small-star-negative, .small-star-positive { | ||
25 | + background-repeat: no-repeat; | ||
26 | + float: left; | ||
27 | + height: 15px; | ||
28 | + margin-right: 2px; | ||
29 | + position: relative; | ||
30 | + width: 15px; | ||
31 | +} | ||
32 | + | ||
33 | +.small-star-negative { | ||
34 | + background-image: url('public/images/small-star-negative.png'); | ||
35 | +} | ||
36 | + | ||
37 | +.small-star-positive { | ||
38 | + background-image: url('public/images/small-star-positive.png'); | ||
39 | +} | ||
40 | + | ||
41 | +.medium-star-negative, .medium-star-positive { | ||
42 | + background-repeat: no-repeat; | ||
43 | + float: left; | ||
44 | + height: 20px; | ||
45 | + margin-right: 2px; | ||
46 | + position: relative; | ||
47 | + width: 20px; | ||
48 | +} | ||
49 | + | ||
50 | +.medium-star-positive { | ||
51 | + background-image: url('public/images/star-positive-medium.png'); | ||
52 | +} | ||
53 | + | ||
54 | +.medium-star-negative { | ||
55 | + background-image: url('public/images/star-negative-medium.png'); | ||
56 | +} | ||
57 | + | ||
58 | +.star-hide { | ||
59 | + display: none; | ||
60 | +} | ||
61 | + | ||
62 | +.organization-average-rating-container { | ||
63 | + border-top: 1px dotted #D3D6DE; | ||
64 | + margin-top: 20px; | ||
65 | + padding-top: 10px; | ||
66 | +} | ||
67 | + | ||
68 | +.organization-average-rating-container .star-rate-text { | ||
69 | + float: left; | ||
70 | + margin-right: 10px; | ||
71 | + padding-top: 5px; | ||
72 | +} | ||
73 | + | ||
74 | +.organization-average-rating-container .rating-invitation { | ||
75 | + font-size: 14px; | ||
76 | + float: left; | ||
77 | + margin-right: 10px; | ||
78 | + padding-top: 3px; | ||
79 | +} | ||
80 | + | ||
81 | +.organization-average-rating-container .star-container { | ||
82 | + float: left; | ||
83 | + width: 120px; | ||
84 | +} | ||
85 | + | ||
86 | +.organization-average-rating-container .rate-this-organization { | ||
87 | + border-left: 1px dotted #D3D6DE; | ||
88 | + float: left; | ||
89 | + padding: 4px 0px 2px 10px; | ||
90 | +} | ||
91 | + | ||
92 | +.star-rate-data { | ||
93 | + width: 100%; | ||
94 | + padding-top: 20px; | ||
95 | + position: relative; | ||
96 | + overflow: auto; | ||
97 | +} | ||
98 | + | ||
99 | +.star-profile-information, .star-rate-form { | ||
100 | + display: table-cell; | ||
101 | + vertical-align: top; | ||
102 | + width: 362px; | ||
103 | +} | ||
104 | + | ||
105 | +.star-profile-information { | ||
106 | + width: 134px; | ||
107 | +} | ||
108 | + | ||
109 | +.star-rate-form { | ||
110 | + display: table-cell; | ||
111 | + vertical-align: top; | ||
112 | +} | ||
113 | + | ||
114 | +.star-profile-image, .star-profile-name { | ||
115 | + text-align: center; | ||
116 | +} | ||
117 | + | ||
118 | +.star-profile-name { | ||
119 | + word-break: break-word; | ||
120 | + margin: auto; | ||
121 | + margin-top: 5px; | ||
122 | + width: 66px; | ||
123 | +} | ||
124 | + | ||
125 | +.star-rate-data .star-rate-form .star-comment-container .formfield textarea { | ||
126 | + width: 361px; | ||
127 | +} | ||
128 | + | ||
129 | +/************* Users ratings list ****************/ | ||
130 | + | ||
131 | +.ratings-list .user-rating-block, | ||
132 | +.ratings-list .make-report-block { | ||
133 | + border-top: 1px solid #D3D6DE; | ||
134 | + margin-top: 25px; | ||
135 | + padding-top: 20px; | ||
136 | +} | ||
137 | + | ||
138 | +.ratings-list .make-report-block { | ||
139 | + padding-bottom: 25px; | ||
140 | +} | ||
141 | + | ||
142 | +.ratings-list .see-more{ | ||
143 | + border-top: 1px solid #D3D6DE; | ||
144 | +} | ||
145 | +.ratings-list .user-rating-block .user-testimony-container { | ||
146 | + display: table-cell; | ||
147 | + padding-left: 20px; | ||
148 | +} | ||
149 | + | ||
150 | +.ratings-list .make-report-block .make-report-container { | ||
151 | + display: table-cell; | ||
152 | +} | ||
153 | + | ||
154 | +.ratings-list .user-rating-block .user-testimony-container .star-container { | ||
155 | + display: table-cell; | ||
156 | +} | ||
157 | + | ||
158 | +.ratings-list .user-rating-block .user-testimony-container .testimony-rate-date { | ||
159 | + display: table-cell; | ||
160 | + max-width: 95px; | ||
161 | + min-width: 95px; | ||
162 | + padding-right: 160px; | ||
163 | + white-space: nowrap; | ||
164 | +} | ||
165 | + | ||
166 | +.ratings-list .user-rating-block .user-testimony-container .user-testimony { | ||
167 | + margin-top: 10px; | ||
168 | + word-break: break-word; | ||
169 | +} | ||
170 | + | ||
171 | +.ratings-list .make-report-block .make-report-container .make-report-message { | ||
172 | + font-size: 14px; | ||
173 | + font-style: italic; | ||
174 | + word-break: break-word; | ||
175 | +} | ||
176 | + | ||
177 | +.ratings-list .make-report-block .make-report-container .button-bar { | ||
178 | + overflow: auto; | ||
179 | + padding-top: 15px; | ||
180 | +} | ||
181 | + | ||
182 | +.ratings-list .user-rating-block .star-profile-information { | ||
183 | + border-right: 1px dotted #D3D6DE; | ||
184 | +} | ||
185 | + | ||
186 | +.ratings-list .icon-arrow-right-p { | ||
187 | + background: url(/designs/themes/base/imgs/arrow-right-p.png) 100% 50% no-repeat; | ||
188 | + display: block; | ||
189 | + float: right; | ||
190 | + margin-top: 20px; | ||
191 | + padding-right: 15px; | ||
192 | +} | ||
193 | + | ||
194 | +.task_information .comment { | ||
195 | + padding-left: 60px; | ||
196 | +} | ||
197 | + | ||
198 | +.average-rating-block { | ||
199 | + height: 55px; | ||
200 | +} |
plugins/organization_ratings/test/functional/organization_ratings_plugin_admin_controller_test.rb
0 → 100644
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper' | ||
2 | +require File.expand_path(File.dirname(__FILE__)) + '/../../controllers/organization_ratings_plugin_admin_controller' | ||
3 | + | ||
4 | +# Re-raise errors caught by the controller. | ||
5 | +class OrganizationRatingsPluginAdminController; def rescue_action(e) raise e end; end | ||
6 | + | ||
7 | +class OrganizationRatingsPluginAdminControllerTest < ActionController::TestCase | ||
8 | + | ||
9 | + def setup | ||
10 | + @controller = OrganizationRatingsPluginAdminController.new | ||
11 | + @request = ActionController::TestRequest.new | ||
12 | + @response = ActionController::TestResponse.new | ||
13 | + | ||
14 | + @environment = Environment.default | ||
15 | + @environment.enabled_plugins = ['OrganizationRatingsPlugin'] | ||
16 | + @environment.save | ||
17 | + | ||
18 | + @community = Community.create(:name => "TestCommunity") | ||
19 | + | ||
20 | + login_as(create_admin_user(@environment)) | ||
21 | + end | ||
22 | + | ||
23 | + test "should update organization rating plugin configuration" do | ||
24 | + post :update, :organization_ratings_config => { :default_rating => 5, | ||
25 | + :cooldown => 12, | ||
26 | + :order => "recent", | ||
27 | + :per_page => 10, | ||
28 | + :vote_once => true } | ||
29 | + | ||
30 | + assert :success | ||
31 | + @environment.reload | ||
32 | + assert_equal 5, @environment.organization_ratings_config.default_rating | ||
33 | + assert_equal "Configuration updated successfully.", session[:notice] | ||
34 | + end | ||
35 | + | ||
36 | + test "should not update organization rating plugin configuration with negative cooldown time" do | ||
37 | + post :update, :organization_ratings_config => { :default_rating => 5, | ||
38 | + :cooldown => -50, | ||
39 | + :order => "recent", | ||
40 | + :per_page => 10, | ||
41 | + :vote_once => true } | ||
42 | + | ||
43 | + assert :success | ||
44 | + @environment.reload | ||
45 | + assert_equal 24, @environment.organization_ratings_config.cooldown | ||
46 | + assert_equal "Configuration could not be saved.", session[:notice] | ||
47 | + end | ||
48 | +end | ||
49 | + |
plugins/organization_ratings/test/functional/organization_ratings_plugin_profile_controller_test.rb
0 → 100644
@@ -0,0 +1,104 @@ | @@ -0,0 +1,104 @@ | ||
1 | +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper' | ||
2 | +require File.expand_path(File.dirname(__FILE__)) + '/../../controllers/organization_ratings_plugin_profile_controller' | ||
3 | + | ||
4 | +# Re-raise errors caught by the controller. | ||
5 | +class OrganizationRatingsPluginProfileController; def rescue_action(e) raise e end; end | ||
6 | + | ||
7 | +class OrganizationRatingsPluginProfileControllerTest < ActionController::TestCase | ||
8 | + | ||
9 | + def setup | ||
10 | + @controller = OrganizationRatingsPluginProfileController.new | ||
11 | + @request = ActionController::TestRequest.new | ||
12 | + @response = ActionController::TestResponse.new | ||
13 | + | ||
14 | + @environment = Environment.default | ||
15 | + @environment.enabled_plugins = ['OrganizationRatingsPlugin'] | ||
16 | + @environment.save | ||
17 | + | ||
18 | + @person = create_user('testuser').person | ||
19 | + @community = Community.create(:name => "TestCommunity") | ||
20 | + @enterprise = fast_create(Enterprise) | ||
21 | + @config = OrganizationRatingsConfig.instance | ||
22 | + login_as(@person.identifier) | ||
23 | + @controller.stubs(:logged_in?).returns(true) | ||
24 | + @controller.stubs(:current_user).returns(@person.user) | ||
25 | + end | ||
26 | + | ||
27 | + test "should add new comment to community" do | ||
28 | + post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test"}, :organization_rating_value => 4 | ||
29 | + assert_equal "#{@community.name} successfully rated!", session[:notice] | ||
30 | + end | ||
31 | + | ||
32 | + test "Create community_rating without comment body" do | ||
33 | + post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => 2 | ||
34 | + | ||
35 | + assert_equal "#{@community.name} successfully rated!", session[:notice] | ||
36 | + end | ||
37 | + | ||
38 | + test "Do not create community_rating without a rate value" do | ||
39 | + post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => nil | ||
40 | + | ||
41 | + assert_equal "Sorry, there were problems rating this profile.", session[:notice] | ||
42 | + end | ||
43 | + | ||
44 | + test "do not create two ratings on Community when vote once config is true" do | ||
45 | + post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test"}, :organization_rating_value => 3 | ||
46 | + | ||
47 | + assert_equal "#{@community.name} successfully rated!", session[:notice] | ||
48 | + | ||
49 | + @environment.organization_ratings_config.vote_once = true | ||
50 | + @environment.save | ||
51 | + | ||
52 | + post :new_rating, profile: @community.identifier, :comments => {:body => "This is a test 2"}, :organization_rating_value => 3 | ||
53 | + assert_equal "You can not vote on this Community", session[:notice] | ||
54 | + end | ||
55 | + | ||
56 | + test "do not create two ratings on Enterprise when vote once config is true" do | ||
57 | + post :new_rating, profile: @enterprise.identifier, :comments => {:body => "This is a test"}, :organization_rating_value => 3 | ||
58 | + | ||
59 | + assert_equal "#{@enterprise.name} successfully rated!", session[:notice] | ||
60 | + | ||
61 | + @environment.organization_ratings_config.vote_once = true | ||
62 | + @environment.save | ||
63 | + | ||
64 | + post :new_rating, profile: @enterprise.identifier, :comments => {:body => "This is a test 2"}, :organization_rating_value => 3 | ||
65 | + assert_equal "You can not vote on this Enterprise", session[:notice] | ||
66 | + end | ||
67 | + | ||
68 | + test "should count organization ratings on statistic block when block owner = Environment" do | ||
69 | + block = StatisticsBlock.new | ||
70 | + enterprise = fast_create(Enterprise) | ||
71 | + post :new_rating, profile: enterprise.identifier, :comments => {:body => "body board"}, :organization_rating_value => 1 | ||
72 | + enterprise.reload | ||
73 | + @environment.reload | ||
74 | + block.expects(:owner).at_least_once.returns(@environment) | ||
75 | + assert_equal 1, block.comments | ||
76 | + end | ||
77 | + | ||
78 | + | ||
79 | + test "should count organization ratings on statistic block when block owner = Profile" do | ||
80 | + @config.cooldown = 0 | ||
81 | + @config.save | ||
82 | + | ||
83 | + block = StatisticsBlock.new | ||
84 | + | ||
85 | + post :new_rating, profile: @community.identifier, :comments => {:body => "body board"}, :organization_rating_value => 1 | ||
86 | + post :new_rating, profile: @community.identifier, :comments => {:body => "body surf"}, :organization_rating_value => 5 | ||
87 | + | ||
88 | + block.expects(:owner).at_least_once.returns(@community) | ||
89 | + @community.reload | ||
90 | + assert_equal 2, block.comments | ||
91 | + end | ||
92 | + | ||
93 | + test "Display unavailable rating message for users that must wait the rating cooldown time" do | ||
94 | + post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => 3 | ||
95 | + assert_not_match(/The administrators set the minimum time of/, @response.body) | ||
96 | + valid_rating = OrganizationRating.last | ||
97 | + | ||
98 | + post :new_rating, profile: @community.identifier, :comments => {:body => ""}, :organization_rating_value => 3 | ||
99 | + assert_match(/The administrators set the minimum time of/, @response.body) | ||
100 | + new_rating = OrganizationRating.last | ||
101 | + | ||
102 | + assert_equal valid_rating.id, new_rating.id | ||
103 | + end | ||
104 | +end |
plugins/organization_ratings/test/unit/organization_rating_config_test.rb
0 → 100644
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper' | ||
2 | + | ||
3 | +class OrganizationRatingConfigTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + def setup | ||
6 | + @environment = Environment.default | ||
7 | + @environment.enabled_plugins = ['OrganizationRatingsPlugin'] | ||
8 | + @environment.save | ||
9 | + @organization_ratings_config = OrganizationRatingsConfig.instance | ||
10 | + end | ||
11 | + | ||
12 | + test "Community ratings config default rating validation" do | ||
13 | + @organization_ratings_config.default_rating = 0 | ||
14 | + @organization_ratings_config.save | ||
15 | + | ||
16 | + assert_equal false, @organization_ratings_config.valid? | ||
17 | + assert_equal "must be greater than or equal to 1", @organization_ratings_config.errors[:default_rating].first | ||
18 | + | ||
19 | + @organization_ratings_config.default_rating = 6 | ||
20 | + assert_equal false, @organization_ratings_config.valid? | ||
21 | + | ||
22 | + assert_equal "must be less than or equal to 5", @organization_ratings_config.errors[:default_rating].first | ||
23 | + end | ||
24 | + | ||
25 | + test "Communities ratings config cooldown validation" do | ||
26 | + @organization_ratings_config.cooldown = -1 | ||
27 | + assert_equal false, @organization_ratings_config.valid? | ||
28 | + | ||
29 | + assert_equal "must be greater than or equal to 0", @organization_ratings_config.errors[:cooldown].first | ||
30 | + end | ||
31 | + | ||
32 | + # test "communities ratings per page validation" do | ||
33 | + # environment = Environment.new :communities_ratings_per_page => 4 | ||
34 | + # environment.valid? | ||
35 | + | ||
36 | + # assert_equal "must be greater than or equal to 5", environment.errors[:communities_ratings_per_page].first | ||
37 | + | ||
38 | + # environment.communities_ratings_per_page = 21 | ||
39 | + # environment.valid? | ||
40 | + | ||
41 | + # assert_equal "must be less than or equal to 20", environment.errors[:communities_ratings_per_page].first | ||
42 | + # end | ||
43 | +end |
plugins/organization_ratings/test/unit/organization_rating_test.rb
0 → 100644
@@ -0,0 +1,154 @@ | @@ -0,0 +1,154 @@ | ||
1 | +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper' | ||
2 | + | ||
3 | +class OrganizationRatingTest < ActiveSupport::TestCase | ||
4 | + test "The value must be between 1 and 5" do | ||
5 | + organization_rating1 = OrganizationRating.new :value => -1 | ||
6 | + organization_rating2 = OrganizationRating.new :value => 6 | ||
7 | + | ||
8 | + assert_equal false, organization_rating1.valid? | ||
9 | + assert_equal false, organization_rating2.valid? | ||
10 | + | ||
11 | + assert_equal true, organization_rating1.errors[:value].include?("must be between 1 and 5") | ||
12 | + assert_equal true, organization_rating2.errors[:value].include?("must be between 1 and 5") | ||
13 | + | ||
14 | + organization_rating1.value = 1 | ||
15 | + organization_rating1.valid? | ||
16 | + | ||
17 | + organization_rating2.value = 5 | ||
18 | + organization_rating2.valid? | ||
19 | + | ||
20 | + assert_equal false, organization_rating1.errors[:value].include?("must be between 1 and 5") | ||
21 | + assert_equal false, organization_rating2.errors[:value].include?("must be between 1 and 5") | ||
22 | + end | ||
23 | + | ||
24 | + test "Create task for create a rating comment" do | ||
25 | + person = create_user('molly').person | ||
26 | + person.email = "person@email.com" | ||
27 | + person.save! | ||
28 | + | ||
29 | + community = fast_create(Community) | ||
30 | + community.add_admin(person) | ||
31 | + | ||
32 | + organization_rating = OrganizationRating.create!( | ||
33 | + :value => 3, | ||
34 | + :person => person, | ||
35 | + :organization => community | ||
36 | + ) | ||
37 | + | ||
38 | + create_organization_rating_comment = CreateOrganizationRatingComment.create!( | ||
39 | + :requestor => person, | ||
40 | + :organization_rating_id => organization_rating.id, | ||
41 | + :target => community | ||
42 | + ) | ||
43 | + | ||
44 | + assert community.tasks.include?(create_organization_rating_comment) | ||
45 | + end | ||
46 | + | ||
47 | + test "Check comment message when Task status = ACTIVE" do | ||
48 | + person = create_user('molly').person | ||
49 | + person.email = "person@email.com" | ||
50 | + person.save! | ||
51 | + | ||
52 | + community = fast_create(Community) | ||
53 | + community.add_admin(person) | ||
54 | + | ||
55 | + | ||
56 | + organization_rating = OrganizationRating.create!( | ||
57 | + :value => 3, | ||
58 | + :person => person, | ||
59 | + :organization => community | ||
60 | + ) | ||
61 | + | ||
62 | + create_organization_rating_comment = CreateOrganizationRatingComment.create!( | ||
63 | + :requestor => person, | ||
64 | + :organization_rating_id => organization_rating.id, | ||
65 | + :target => community, | ||
66 | + :body => "sample comment" | ||
67 | + ) | ||
68 | + assert_equal 1, create_organization_rating_comment.status | ||
69 | + message = "Comment waiting for approval" | ||
70 | + comment = Comment.find_by_id(create_organization_rating_comment.organization_rating_comment_id) | ||
71 | + assert_equal message, comment.body | ||
72 | + end | ||
73 | + | ||
74 | + test "Check comment message when Task status = CANCELLED" do | ||
75 | + person = create_user('molly').person | ||
76 | + person.email = "person@email.com" | ||
77 | + person.save! | ||
78 | + | ||
79 | + community = fast_create(Community) | ||
80 | + community.add_admin(person) | ||
81 | + | ||
82 | + | ||
83 | + organization_rating = OrganizationRating.create!( | ||
84 | + :value => 3, | ||
85 | + :person => person, | ||
86 | + :organization => community | ||
87 | + ) | ||
88 | + | ||
89 | + create_organization_rating_comment = CreateOrganizationRatingComment.create!( | ||
90 | + :requestor => person, | ||
91 | + :organization_rating_id => organization_rating.id, | ||
92 | + :target => community, | ||
93 | + :body => "sample comment" | ||
94 | + ) | ||
95 | + create_organization_rating_comment.cancel | ||
96 | + assert_equal 2, create_organization_rating_comment.status | ||
97 | + message = "Comment rejected" | ||
98 | + comment = Comment.find_by_id(create_organization_rating_comment.organization_rating_comment_id) | ||
99 | + assert_equal message, comment.body | ||
100 | + end | ||
101 | + | ||
102 | + test "Check comment message when Task status = FINISHED" do | ||
103 | + person = create_user('molly').person | ||
104 | + person.email = "person@email.com" | ||
105 | + person.save! | ||
106 | + | ||
107 | + community = fast_create(Community) | ||
108 | + community.add_admin(person) | ||
109 | + | ||
110 | + comment = Comment.create!(source: community, | ||
111 | + body: "regular comment", | ||
112 | + author: person) | ||
113 | + | ||
114 | + organization_rating = OrganizationRating.create!( | ||
115 | + :value => 3, | ||
116 | + :person => person, | ||
117 | + :organization => community, | ||
118 | + :comment => comment | ||
119 | + ) | ||
120 | + | ||
121 | + create_organization_rating_comment = CreateOrganizationRatingComment.create!( | ||
122 | + :body => comment.body, | ||
123 | + :requestor => organization_rating.person, | ||
124 | + :organization_rating_id => organization_rating.id, | ||
125 | + :target => organization_rating.organization, | ||
126 | + :body => "sample comment" | ||
127 | + ) | ||
128 | + | ||
129 | + create_organization_rating_comment.finish | ||
130 | + assert_equal 3, create_organization_rating_comment.status | ||
131 | + message = "sample comment" | ||
132 | + comment = Comment.find_by_id(create_organization_rating_comment.organization_rating_comment_id) | ||
133 | + assert_equal message, comment.body | ||
134 | + end | ||
135 | + | ||
136 | + | ||
137 | + test "Should calculate community's rating average" do | ||
138 | + community = fast_create Community | ||
139 | + p1 = fast_create Person, :name=>"Person 1" | ||
140 | + p2 = fast_create Person, :name=>"Person 2" | ||
141 | + p3 = fast_create Person, :name=>"Person 3" | ||
142 | + | ||
143 | + OrganizationRating.create! :value => 2, :organization => community, :person => p1 | ||
144 | + OrganizationRating.create! :value => 3, :organization => community, :person => p2 | ||
145 | + OrganizationRating.create! :value => 5, :organization => community, :person => p3 | ||
146 | + | ||
147 | + assert_equal 3, OrganizationRating.average_rating(community) | ||
148 | + | ||
149 | + p4 = fast_create Person, :name=>"Person 4" | ||
150 | + OrganizationRating.create! :value => 4, :organization => community, :person => p4 | ||
151 | + | ||
152 | + assert_equal 4, OrganizationRating.average_rating(community) | ||
153 | + end | ||
154 | +end |
plugins/organization_ratings/test/unit/ratings_helper_test.rb
0 → 100644
@@ -0,0 +1,63 @@ | @@ -0,0 +1,63 @@ | ||
1 | +require File.expand_path(File.dirname(__FILE__)) + '/../../../../test/test_helper' | ||
2 | +require 'ratings_helper' | ||
3 | + | ||
4 | +class RatingsHelperTest < ActiveSupport::TestCase | ||
5 | + include RatingsHelper | ||
6 | + | ||
7 | + def setup | ||
8 | + | ||
9 | + @environment = Environment.default | ||
10 | + @environment.enabled_plugins = ['OrganizationRatingsPlugin'] | ||
11 | + @environment.save | ||
12 | + @person = create_user('testuser').person | ||
13 | + @community = Community.create(:name => "TestCommunity") | ||
14 | + @organization_ratings_config = OrganizationRatingsConfig.instance | ||
15 | + end | ||
16 | + | ||
17 | + should "get the ratings of a community ordered by most recent ratings" do | ||
18 | + ratings_array = [] | ||
19 | + | ||
20 | + first_rating = OrganizationRating.new | ||
21 | + first_rating.organization = @community | ||
22 | + first_rating.person = @person | ||
23 | + first_rating.value = 3 | ||
24 | + first_rating.save | ||
25 | + | ||
26 | + most_recent_rating = OrganizationRating.new | ||
27 | + most_recent_rating.organization = @community | ||
28 | + most_recent_rating.person = @person | ||
29 | + most_recent_rating.value = 5 | ||
30 | + sleep 2 | ||
31 | + most_recent_rating.save | ||
32 | + | ||
33 | + ratings_array << most_recent_rating | ||
34 | + ratings_array << first_rating | ||
35 | + | ||
36 | + assert_equal @organization_ratings_config.order, "recent" | ||
37 | + assert_equal ratings_array, get_ratings(@community.id) | ||
38 | + end | ||
39 | + | ||
40 | + should "get the ratings of a community ordered by best ratings" do | ||
41 | + ratings_array = [] | ||
42 | + @organization_ratings_config = "best" | ||
43 | + @environment.save | ||
44 | + | ||
45 | + first_rating = OrganizationRating.new | ||
46 | + first_rating.organization = @community | ||
47 | + first_rating.person = @person | ||
48 | + first_rating.value = 3 | ||
49 | + first_rating.save | ||
50 | + | ||
51 | + second_rating = OrganizationRating.new | ||
52 | + second_rating.organization = @community | ||
53 | + second_rating.person = @person | ||
54 | + second_rating.value = 5 | ||
55 | + sleep 2 | ||
56 | + second_rating.save | ||
57 | + | ||
58 | + ratings_array << second_rating | ||
59 | + ratings_array << first_rating | ||
60 | + | ||
61 | + assert_equal ratings_array, get_ratings(@community.id) | ||
62 | + end | ||
63 | +end |
plugins/organization_ratings/views/blocks/display_organization_average_rating.html.erb
0 → 100644
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +<div class="organization-average-rating-container"> | ||
2 | + <% if average_rating %> | ||
3 | + <div class="star-rate-text"> | ||
4 | + <%= _("Rating: ") %> | ||
5 | + </div> | ||
6 | + | ||
7 | + <div class="star-container"> | ||
8 | + <% (1..5).each do |star_number| %> | ||
9 | + <% if star_number <= average_rating %> | ||
10 | + <div class="medium-star-positive"></div> | ||
11 | + <% else %> | ||
12 | + <div class="medium-star-negative"></div> | ||
13 | + <% end %> | ||
14 | + <% end %> | ||
15 | + </div> | ||
16 | + <% else %> | ||
17 | + <div class="rating-invitation"> | ||
18 | + <%= _("Be the first to rate!") %> | ||
19 | + </div> | ||
20 | + <% end %> | ||
21 | + | ||
22 | + <div class="rate-this-organization"> | ||
23 | + <%= link_to _("Rate this %s" % profile.class.name), url_for(:controller => "organization_ratings_plugin_profile", :action => "new_rating", :profile=>profile_identifier) %> | ||
24 | + </div> | ||
25 | +</div> | ||
0 | \ No newline at end of file | 26 | \ No newline at end of file |
plugins/organization_ratings/views/blocks/organization_ratings_block.html.erb
0 → 100644
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +<div class="ratings-title"> | ||
2 | + <%= block_title(block.title) %> | ||
3 | + <% if block.get_ratings(block.owner.id).empty? %> | ||
4 | + <div class="ratings-list"> | ||
5 | + <%= render :partial => 'shared/make_report_block' %> | ||
6 | + </div> | ||
7 | + <% else %> | ||
8 | + <div class="ratings-list"> | ||
9 | + <% block.get_ratings(block.owner.id).each_with_index do |r, index| %> | ||
10 | + <% break if index >= block.limit_number_of_ratings %> | ||
11 | + <%= render :partial => "shared/user_rating_container", :locals => {:user_rate => r} %> | ||
12 | + <% end %> | ||
13 | + | ||
14 | + <%= render :partial => 'shared/make_report_block' %> | ||
15 | + | ||
16 | + <div class="see-more"> | ||
17 | + <%= link_to _('See more'), url_for(:controller => 'organization_ratings_plugin_profile', :action => 'new_rating'), :class => 'icon-arrow-right-p' %> | ||
18 | + </div> | ||
19 | + </div> | ||
20 | + <% end %> | ||
21 | +</div> |
plugins/organization_ratings/views/organization_ratings_plugin_admin/index.html.erb
0 → 100644
@@ -0,0 +1,54 @@ | @@ -0,0 +1,54 @@ | ||
1 | +<% config = env_organization_ratings_config %> | ||
2 | + | ||
3 | +<h1><%= _("Organization Rating Management") %> </h1> | ||
4 | + | ||
5 | +<%= labelled_form_for(:organization_ratings_config, :url => {:action => 'update'}) do |f| %> | ||
6 | + <%= labelled_fields_for(:organization_ratings_config, config) do |c| %> | ||
7 | + <table> | ||
8 | + <tr> | ||
9 | + <th><%= c_('Configuration') %></th> | ||
10 | + <th><%= _('Value') %></th> | ||
11 | + </tr> | ||
12 | + <tr> | ||
13 | + <td><%= _('Default amount of stars marked on evaluations') %></td> | ||
14 | + <td><%= c.select :default_rating, (config.minimum_ratings)..5 %></td> | ||
15 | + </tr> | ||
16 | + <tr> | ||
17 | + <td><%= _('Can rate an organization only once') %></td> | ||
18 | + <td><%= c.check_box :vote_once %></td> | ||
19 | + </tr> | ||
20 | + <tr> | ||
21 | + <td><%= _('The comments are moderated') %></td> | ||
22 | + <td><%= c.check_box :are_moderated %></td> | ||
23 | + </tr> | ||
24 | + <tr> | ||
25 | + <td> | ||
26 | + <%= _('Time in hours between evaluations from the same user.') %> | ||
27 | + <span class="hint" title=" <%= _('To disable cooldown use zero (0) value.') %> ">(?)</span> | ||
28 | + </td> | ||
29 | + <% hours_options = {size: 2} %> | ||
30 | + <% hours_options[:disabled] = "disabled" if config.vote_once %> | ||
31 | + <td><%= c.text_field :cooldown, hours_options %> | ||
32 | + </td> | ||
33 | + </tr> | ||
34 | + <tr> | ||
35 | + <td><%= _('Order ratings by') %></td> | ||
36 | + <% order_options = [] %> | ||
37 | + <% config.order_options.select{|k,v| order_options << v } %> | ||
38 | + <td><%= c.select :order, order_options %></td> | ||
39 | + </tr> | ||
40 | + <tr> | ||
41 | + <td><%= _('Ratings per page') %></td> | ||
42 | + <td> | ||
43 | + <%= c.select :per_page, 5..20 %> | ||
44 | + </td> | ||
45 | + </tr> | ||
46 | + </table> | ||
47 | + <div> | ||
48 | + <% button_bar do %> | ||
49 | + <%= submit_button('save', c_('Save changes')) %> | ||
50 | + <%= button :back, _('Back'), :controller => 'plugins' %> | ||
51 | + <% end %> | ||
52 | + </div> | ||
53 | + <% end %> | ||
54 | +<% end %> |
plugins/organization_ratings/views/organization_ratings_plugin_profile/_new_rating_fields.html.erb
0 → 100644
@@ -0,0 +1,80 @@ | @@ -0,0 +1,80 @@ | ||
1 | +<% min_rate = env_organization_ratings_config.minimum_ratings %> | ||
2 | +<% default_rating = env_organization_ratings_config.default_rating %> | ||
3 | + | ||
4 | +<div class="star-page-title"> | ||
5 | + <%= @plugins.dispatch(:organization_ratings_title).collect { |content| instance_exec(&content) }.join("") %> | ||
6 | +</div> | ||
7 | + | ||
8 | +<div class="star-rate-data"> | ||
9 | + | ||
10 | + <div class="star-profile-information"> | ||
11 | + <div class="star-profile-image"> | ||
12 | + <%= profile_image(current_user.person, :portrait) %> | ||
13 | + </div> | ||
14 | + | ||
15 | + <div class="star-profile-name"> | ||
16 | + <%= current_user.name %> | ||
17 | + </div> | ||
18 | + </div> | ||
19 | + | ||
20 | + <% if @rating_available %> | ||
21 | + <div class="star-rate-form"> | ||
22 | + <div data-rate-url=<%= url_for controller: "organization_ratings_plugin_profile", :action => "rate" %>> | ||
23 | + <div class="star-rate-text"> | ||
24 | + <%= @plugins.dispatch(:organization_ratings_plugin_star_message).collect { |content| instance_exec(&content) }.join("") %> | ||
25 | + </div> | ||
26 | + | ||
27 | + <div class="star-container" data-min-rate="<%= min_rate %>"> | ||
28 | + | ||
29 | + <% (1..5).each do |rate_number| %> | ||
30 | + <% if rate_number <= default_rating %> | ||
31 | + <div class="star-positive" data-star-rate="<%= rate_number %>"></div> | ||
32 | + <% else %> | ||
33 | + <div class="star-negative" data-star-rate="<%= rate_number %>"></div> | ||
34 | + <% end %> | ||
35 | + <% end %> | ||
36 | + </div> | ||
37 | + | ||
38 | + <div class="star-notice star-hide"> | ||
39 | + <%= _("Rated as") %> <span></span> <%= _("stars") %> | ||
40 | + </div> | ||
41 | + </div> | ||
42 | + | ||
43 | + <div class="star-comment-container"> | ||
44 | + <%= form_for :comments do |c| %> | ||
45 | + <div class="formfieldline formfield type-text"> | ||
46 | + <%= c.label :body, _('Comment (Optional):'), :class => "formlabel" %> | ||
47 | + <%= c.text_area :body %> | ||
48 | + </div> | ||
49 | + | ||
50 | + <%= @plugins.dispatch(:organization_ratings_plugin_comments_extra_fields).collect { |content| instance_exec(&content) }.join("") %> | ||
51 | + | ||
52 | + <div class="button-bar"> | ||
53 | + <%= submit_button(:save, _('Save'), :cancel => {controller: 'profile', action: 'index'}) %> | ||
54 | + </div> | ||
55 | + | ||
56 | + <input type="hidden" id="selected-star-rate" name="organization_rating_value" value="<%= @default_rate %>"> | ||
57 | + <input type="hidden" id="minimum_stars" name="organization_rating_min_value" value="<%= min_rate %>"> | ||
58 | + <% end %> | ||
59 | + </div> | ||
60 | + | ||
61 | + <% elsif env_organization_ratings_config.vote_once %> | ||
62 | + <div class="star-rate-form rating-vote-once"> | ||
63 | + <%= _("Hi, %s! The administrators set that you can vote") % current_user.name %> | ||
64 | + <strong><%= _("only once") %></strong> | ||
65 | + <%= _("for this %s.") % profile.class.name.downcase %> | ||
66 | + <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %> | ||
67 | + </div> | ||
68 | + <% else %> | ||
69 | + <div class="star-rate-form rating-cooldown"> | ||
70 | + <%= _("Hi, %s! The administrators set the minimum time of") % current_user.name %> | ||
71 | + <strong><%= _("%s hour(s)" % env_organization_ratings_config.cooldown) %></strong> | ||
72 | + <%= _("between each evaluation.") %> | ||
73 | + | ||
74 | + <%= render :partial => 'shared/rating_button', :locals => { :disabled => true } %> | ||
75 | + </div> | ||
76 | + <% end %> | ||
77 | + | ||
78 | + | ||
79 | + </div> | ||
80 | +</div> | ||
0 | \ No newline at end of file | 81 | \ No newline at end of file |
plugins/organization_ratings/views/organization_ratings_plugin_profile/new_rating.html.erb
0 → 100644
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +<% config = env_organization_ratings_config %> | ||
2 | +<% if logged_in? %> | ||
3 | + <%= render :partial => "new_rating_fields" %> | ||
4 | +<% else %> | ||
5 | + <div class="ratings-list"> | ||
6 | + <%= render :partial => "shared/make_report_block" %> | ||
7 | + </div> | ||
8 | +<% end %> | ||
9 | + | ||
10 | +<div class="ratings-list"> | ||
11 | + <% @users_ratings.each do |user_rate| %> | ||
12 | + <%= render :partial => "shared/user_rating_container", :locals => {:user_rate => user_rate} %> | ||
13 | + <% end %> | ||
14 | +</div> | ||
15 | + | ||
16 | +<div id='pagination-profiles'> | ||
17 | + <%= pagination_links @users_ratings, :param_name => 'npage' %> | ||
18 | +</div> | ||
0 | \ No newline at end of file | 19 | \ No newline at end of file |
plugins/organization_ratings/views/shared/_make_report_block.html.erb
0 → 100644
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +<% logged_in_image = profile_image(current_user.person, :portrait) if current_user %> | ||
2 | +<% logged_out_image = image_tag('plugins/organization_ratings/public/images/user-not-logged.png') %> | ||
3 | + | ||
4 | +<div class="make-report-block"> | ||
5 | + <div class="star-profile-information"> | ||
6 | + <div class="star-profile-image"> | ||
7 | + <%= logged_in? ? logged_in_image : logged_out_image %> | ||
8 | + </div> | ||
9 | + | ||
10 | + <div class="star-profile-name"> | ||
11 | + <%= logged_in? ? current_user.person.name : _('User not logged *') %> | ||
12 | + </div> | ||
13 | + </div> | ||
14 | + | ||
15 | + <div class="make-report-container"> | ||
16 | + <div class="make-report-message"> | ||
17 | + <%= _('Report your experiences.') %> | ||
18 | + </div> | ||
19 | + | ||
20 | + <%= render :partial => 'shared/rating_button', :locals => { :disabled => false } %> | ||
21 | + | ||
22 | + <% unless logged_in? %> | ||
23 | + <div class="alert"> | ||
24 | + <%= _('* You must be logged in to submit a report.') %> | ||
25 | + </div> | ||
26 | + <% end %> | ||
27 | + </div> | ||
28 | +</div> | ||
0 | \ No newline at end of file | 29 | \ No newline at end of file |
plugins/organization_ratings/views/shared/_rating_button.html.erb
0 → 100644
@@ -0,0 +1,10 @@ | @@ -0,0 +1,10 @@ | ||
1 | +<% button_bar do %> | ||
2 | + <% if logged_in? %> | ||
3 | + <%= button(:new,_("Rate %s ") % profile.class.name, | ||
4 | + {:controller => "organization_ratings_plugin_profile", | ||
5 | + :action => "new_rating"}) %> | ||
6 | + <% else %> | ||
7 | + <%= button(:login,_("Log in") , {:controller => 'account', | ||
8 | + :action => 'login'}) %> | ||
9 | + <% end %> | ||
10 | +<% end %> |
plugins/organization_ratings/views/shared/_user_rating_container.html.erb
0 → 100644
@@ -0,0 +1,33 @@ | @@ -0,0 +1,33 @@ | ||
1 | +<div class="user-rating-block"> | ||
2 | + <div class="star-profile-information"> | ||
3 | + <div class="star-profile-image"> | ||
4 | + <%= profile_image(user_rate.person, :portrait) %> | ||
5 | + </div> | ||
6 | + | ||
7 | + <div class="star-profile-name"> | ||
8 | + <%= user_rate.person.name %> | ||
9 | + </div> | ||
10 | + </div> | ||
11 | + | ||
12 | + <div class="user-testimony-container"> | ||
13 | + <div class="testimony-rate-date"> | ||
14 | + <%= time_ago_in_words(user_rate.created_at) %> | ||
15 | + </div> | ||
16 | + | ||
17 | + <div class="star-container"> | ||
18 | + <% (1..5).each do |rate_number| %> | ||
19 | + <% if rate_number <= user_rate.value %> | ||
20 | + <div class="small-star-positive"></div> | ||
21 | + <% else %> | ||
22 | + <div class="small-star-negative"></div> | ||
23 | + <% end %> | ||
24 | + <% end %> | ||
25 | + </div> | ||
26 | + | ||
27 | + <div class="user-testimony"> | ||
28 | + <%= user_rate.comment.nil? ? _("No comment") : user_rate.comment.body %> | ||
29 | + </div> | ||
30 | + | ||
31 | + <%= @plugins.dispatch(:organization_ratings_plugin_extra_fields_show_data, user_rate).collect { |content| instance_exec(&content) }.join("") %> | ||
32 | + </div> | ||
33 | +</div> |
plugins/organization_ratings/views/tasks/_create_organization_rating_comment_accept_details.html.erb
0 → 100644
plugins/people_block/controllers/people_block_plugin_profile_controller.rb
@@ -1,20 +0,0 @@ | @@ -1,20 +0,0 @@ | ||
1 | -class PeopleBlockPluginProfileController < ProfileController | ||
2 | - | ||
3 | - append_view_path File.join(File.dirname(__FILE__) + '/../views') | ||
4 | - | ||
5 | - def members | ||
6 | - if is_cache_expired?(profile.members_cache_key(params)) | ||
7 | - unless params[:role_key].blank? | ||
8 | - role = Role.find_by_key_and_environment_id(params[:role_key], profile.environment) | ||
9 | - @members = profile.members.with_role(role.id) | ||
10 | - @members_title = role.name | ||
11 | - else | ||
12 | - @members = profile.members | ||
13 | - @members_title = 'members' | ||
14 | - end | ||
15 | - @members = @members.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage], :total_entries => @members.count) | ||
16 | - end | ||
17 | - render "profile/members" | ||
18 | - end | ||
19 | - | ||
20 | -end |
plugins/people_block/test/functional/people_block_plugin_profile_controller_test.rb
@@ -1,72 +0,0 @@ | @@ -1,72 +0,0 @@ | ||
1 | -require_relative '../test_helper' | ||
2 | -require_relative '../../controllers/people_block_plugin_profile_controller' | ||
3 | - | ||
4 | -class PeopleBlockPluginProfileControllerTest < ActionController::TestCase | ||
5 | - | ||
6 | - def setup | ||
7 | - @controller = PeopleBlockPluginProfileController.new | ||
8 | - @request = ActionController::TestRequest.new | ||
9 | - @response = ActionController::TestResponse.new | ||
10 | - | ||
11 | - @profile = fast_create(Community) | ||
12 | - | ||
13 | - @environment = @profile.environment | ||
14 | - @environment.enabled_plugins = ['PeopleBlockPlugin'] | ||
15 | - @environment.save! | ||
16 | - | ||
17 | - MembersBlock.delete_all | ||
18 | - @block = MembersBlock.new | ||
19 | - @block.box = @profile.boxes.first | ||
20 | - @block.save! | ||
21 | - | ||
22 | - @admin = create_user('adminprofile').person | ||
23 | - @member = create_user('memberprofile').person | ||
24 | - @moderator = create_user('moderatorprofile').person | ||
25 | - @profile.add_moderator(@moderator) | ||
26 | - @profile.add_member(@member) | ||
27 | - @profile.add_admin(@admin) | ||
28 | - end | ||
29 | - | ||
30 | - attr_accessor :profile, :block, :admin, :member, :moderator | ||
31 | - | ||
32 | - should 'list members without role_key' do | ||
33 | - get :members, :profile => profile.identifier, :role_key => "" | ||
34 | - assert_response :success | ||
35 | - assert_template 'members' | ||
36 | - assert_equivalent [@admin, @member, @moderator], assigns(:members) | ||
37 | - assert_match /adminprofile/, @response.body | ||
38 | - assert_match /memberprofile/, @response.body | ||
39 | - assert_match /moderatorprofile/, @response.body | ||
40 | - end | ||
41 | - | ||
42 | - should 'list members with role_key=nil' do | ||
43 | - get :members, :profile => profile.identifier, :role_key => nil | ||
44 | - assert_response :success | ||
45 | - assert_template 'members' | ||
46 | - assert_equivalent [@admin, @member, @moderator], assigns(:members) | ||
47 | - assert_match /adminprofile/, @response.body | ||
48 | - assert_match /memberprofile/, @response.body | ||
49 | - assert_match /moderatorprofile/, @response.body | ||
50 | - end | ||
51 | - | ||
52 | - should 'list members only' do | ||
53 | - get :members, :profile => profile.identifier, :role_key => Profile::Roles.member(profile.environment.id).key | ||
54 | - assert_response :success | ||
55 | - assert_template 'members' | ||
56 | - assert_equal [@member], assigns(:members) | ||
57 | - assert_no_match /adminprofile/, @response.body | ||
58 | - assert_match /memberprofile/, @response.body | ||
59 | - assert_no_match /moderatorprofile/, @response.body | ||
60 | - end | ||
61 | - | ||
62 | - should 'list moderators only' do | ||
63 | - get :members, :profile => profile.identifier, :role_key => Profile::Roles.moderator(profile.environment.id).key | ||
64 | - assert_response :success | ||
65 | - assert_template 'members' | ||
66 | - assert_equal [@moderator], assigns(:members) | ||
67 | - assert_no_match /adminprofile/, @response.body | ||
68 | - assert_no_match /memberprofile/, @response.body | ||
69 | - assert_match /moderatorprofile/, @response.body | ||
70 | - end | ||
71 | - | ||
72 | -end |
plugins/people_block/test/unit/members_block_test.rb
@@ -147,11 +147,11 @@ class MembersBlockTest < ActionView::TestCase | @@ -147,11 +147,11 @@ class MembersBlockTest < ActionView::TestCase | ||
147 | 147 | ||
148 | instance_eval(&block.footer) | 148 | instance_eval(&block.footer) |
149 | assert_select 'a.view-all' do |elements| | 149 | assert_select 'a.view-all' do |elements| |
150 | - assert_select '[href=/profile/mytestuser/plugin/people_block/members]' | 150 | + assert_select "[href=/profile/mytestuser/members#members-tab]" |
151 | end | 151 | end |
152 | end | 152 | end |
153 | 153 | ||
154 | - should 'provide link to members page with a selected role' do | 154 | + should 'provide link to members page when visible_role is profile_member' do |
155 | profile = create_user('mytestuser').person | 155 | profile = create_user('mytestuser').person |
156 | block = MembersBlock.new | 156 | block = MembersBlock.new |
157 | block.box = profile.boxes.first | 157 | block.box = profile.boxes.first |
@@ -160,7 +160,33 @@ class MembersBlockTest < ActionView::TestCase | @@ -160,7 +160,33 @@ class MembersBlockTest < ActionView::TestCase | ||
160 | 160 | ||
161 | instance_eval(&block.footer) | 161 | instance_eval(&block.footer) |
162 | assert_select 'a.view-all' do |elements| | 162 | assert_select 'a.view-all' do |elements| |
163 | - assert_select '[href=/profile/mytestuser/plugin/people_block/members?role_key=profile_member]' | 163 | + assert_select '[href=/profile/mytestuser/members#members-tab]' |
164 | + end | ||
165 | + end | ||
166 | + | ||
167 | + should 'provide link to members page when visible_role is profile_moderator' do | ||
168 | + profile = create_user('mytestuser').person | ||
169 | + block = MembersBlock.new | ||
170 | + block.box = profile.boxes.first | ||
171 | + block.visible_role = 'profile_moderator' | ||
172 | + block.save! | ||
173 | + | ||
174 | + instance_eval(&block.footer) | ||
175 | + assert_select 'a.view-all' do |elements| | ||
176 | + assert_select '[href=/profile/mytestuser/members#members-tab]' | ||
177 | + end | ||
178 | + end | ||
179 | + | ||
180 | + should 'provide link to admins page when visible_role is profile_admin' do | ||
181 | + profile = create_user('mytestuser').person | ||
182 | + block = MembersBlock.new | ||
183 | + block.box = profile.boxes.first | ||
184 | + block.visible_role = 'profile_admin' | ||
185 | + block.save! | ||
186 | + | ||
187 | + instance_eval(&block.footer) | ||
188 | + assert_select 'a.view-all' do |elements| | ||
189 | + assert_select '[href=/profile/mytestuser/members#admins-tab]' | ||
164 | end | 190 | end |
165 | end | 191 | end |
166 | 192 |
plugins/people_block/views/blocks/members.html.erb
1 | -<%= link_to c_('View all'), {:profile => profile.identifier, :controller => 'people_block_plugin_profile', :action => 'members', :role_key => role_key}, :class => 'view-all' %> | 1 | +<% anchor = role_key == "profile_admin" ? "admins-tab" : "members-tab" %> |
2 | +<%= link_to c_('View all'), {:profile => profile.identifier, :controller => 'profile', :action => 'members', :anchor =>anchor }, :class => 'view-all' %> | ||
2 | 3 | ||
3 | <% if show_join_leave_button %> | 4 | <% if show_join_leave_button %> |
4 | <%= render :partial => 'blocks/profile_info_actions/join_leave_community' %> | 5 | <%= render :partial => 'blocks/profile_info_actions/join_leave_community' %> |
plugins/statistics/lib/statistics_block.rb
@@ -128,11 +128,12 @@ class StatisticsBlock < Block | @@ -128,11 +128,12 @@ class StatisticsBlock < Block | ||
128 | end | 128 | end |
129 | end | 129 | end |
130 | 130 | ||
131 | + include Noosfero::Plugin::HotSpot | ||
131 | def comments | 132 | def comments |
132 | if owner.kind_of?(Environment) then | 133 | if owner.kind_of?(Environment) then |
133 | - owner.profiles.joins(:articles).sum(:comments_count).to_i | 134 | + owner.articles.sum(:comments_count).to_i + plugins.dispatch(:more_comments_count, owner).first.to_i |
134 | elsif owner.kind_of?(Profile) then | 135 | elsif owner.kind_of?(Profile) then |
135 | - owner.articles.sum(:comments_count) | 136 | + owner.articles.sum(:comments_count) + plugins.dispatch(:more_comments_count, owner).first.to_i |
136 | else | 137 | else |
137 | 0 | 138 | 0 |
138 | end | 139 | end |
public/designs/themes/base/style.scss
@@ -231,6 +231,10 @@ body, th, td, input { | @@ -231,6 +231,10 @@ body, th, td, input { | ||
231 | border-left: 0px; | 231 | border-left: 0px; |
232 | } | 232 | } |
233 | 233 | ||
234 | +.menu-submenu-list>li{ | ||
235 | + width: 100%; | ||
236 | +} | ||
237 | + | ||
234 | #navigation .menu-submenu ul{ | 238 | #navigation .menu-submenu ul{ |
235 | border: 1px solid #888a85; | 239 | border: 1px solid #888a85; |
236 | border-top: 0px; | 240 | border-top: 0px; |
@@ -1534,3 +1538,7 @@ table#recaptcha_table tr:hover td { | @@ -1534,3 +1538,7 @@ table#recaptcha_table tr:hover td { | ||
1534 | width: 494px; | 1538 | width: 494px; |
1535 | padding-left: 2px; | 1539 | padding-left: 2px; |
1536 | } | 1540 | } |
1541 | + | ||
1542 | +.profile-members-title-sort { | ||
1543 | + clear: both; | ||
1544 | +} |
@@ -0,0 +1,24 @@ | @@ -0,0 +1,24 @@ | ||
1 | +(function($) { | ||
2 | + "use strict"; | ||
3 | + | ||
4 | + function set_members_sort() { | ||
5 | + var profile_members_url = $("#profile_url").val(); | ||
6 | + | ||
7 | + $("#sort-members, #sort-admins").on("change", function() { | ||
8 | + var sort_value = this.value; | ||
9 | + var role = this.id; | ||
10 | + role = role.replace("sort-", ''); | ||
11 | + var actual_page_content = $(".profile-list-"+role); | ||
12 | + | ||
13 | + $.get(profile_members_url, {sort: sort_value}, function(response) { | ||
14 | + var html_response = $(response); | ||
15 | + | ||
16 | + actual_page_content.html(html_response.find(".profile-list-"+role).html()); | ||
17 | + }); | ||
18 | + }); | ||
19 | + } | ||
20 | + | ||
21 | + $(document).ready(function() { | ||
22 | + set_members_sort(); | ||
23 | + }); | ||
24 | +}) (jQuery); |
public/stylesheets/application.css
@@ -4775,6 +4775,11 @@ h1#agenda-title { | @@ -4775,6 +4775,11 @@ h1#agenda-title { | ||
4775 | background-image: url(../images/control-panel/role-management.gif) | 4775 | background-image: url(../images/control-panel/role-management.gif) |
4776 | } | 4776 | } |
4777 | /* ==> public/stylesheets/controller_profile_members.css <== */ | 4777 | /* ==> public/stylesheets/controller_profile_members.css <== */ |
4778 | + | ||
4779 | +.profile-members-tabs-container .ui-corner-all { | ||
4780 | + overflow: auto; | ||
4781 | +} | ||
4782 | + | ||
4778 | .controller-profile_members .no-boxes { | 4783 | .controller-profile_members .no-boxes { |
4779 | margin: 30px | 4784 | margin: 30px |
4780 | } | 4785 | } |
@@ -5430,6 +5435,7 @@ h1#agenda-title { | @@ -5430,6 +5435,7 @@ h1#agenda-title { | ||
5430 | margin: 0; | 5435 | margin: 0; |
5431 | padding: 0; | 5436 | padding: 0; |
5432 | width: 100%; | 5437 | width: 100%; |
5438 | + height: 92px; | ||
5433 | } | 5439 | } |
5434 | #content .menu-submenu-content ul { | 5440 | #content .menu-submenu-content ul { |
5435 | margin: 0; | 5441 | margin: 0; |
script/authors.sed
@@ -161,6 +161,10 @@ s/Marcos da Silva Ramos <ms.ramos@outlook.com>/Marcos Ramos <ms.ramos@outlook.co | @@ -161,6 +161,10 @@ s/Marcos da Silva Ramos <ms.ramos@outlook.com>/Marcos Ramos <ms.ramos@outlook.co | ||
161 | s/Marcos Ramos <ms.ramos@outlook.com$/Marcos Ramos <ms.ramos@outlook.com>/ | 161 | s/Marcos Ramos <ms.ramos@outlook.com$/Marcos Ramos <ms.ramos@outlook.com>/ |
162 | s/Marcos <marcos.rpj2@gmail.com>/Marcos Ronaldo <marcos.rpj2@gmail.com>/ | 162 | s/Marcos <marcos.rpj2@gmail.com>/Marcos Ronaldo <marcos.rpj2@gmail.com>/ |
163 | 163 | ||
164 | +s/Michel Felipe <mfelipeof@gmail.com>/Michel Felipe de Oliveira Ferreira <michel.ferreira@serpro.gov.br>/ | ||
165 | + | ||
166 | +s/Omar Júnior/Omar Junior/ | ||
167 | + | ||
164 | s/Parley Martins <parley@outlook.com>/Parley Martins <parleypachecomartins@gmail.com>/ | 168 | s/Parley Martins <parley@outlook.com>/Parley Martins <parleypachecomartins@gmail.com>/ |
165 | 169 | ||
166 | s/Paulo Meirelles$/Paulo Meirelles <paulo@softwarelivre.org>/ | 170 | s/Paulo Meirelles$/Paulo Meirelles <paulo@softwarelivre.org>/ |
@@ -180,6 +184,8 @@ s/Pedro Leal <carlos88morais@gmail.com>/Pedro Leal/ | @@ -180,6 +184,8 @@ s/Pedro Leal <carlos88morais@gmail.com>/Pedro Leal/ | ||
180 | s/Pedro Leal <diegoamc90@gmail.com>/Pedro Leal/ | 184 | s/Pedro Leal <diegoamc90@gmail.com>/Pedro Leal/ |
181 | s/Pedro Leal <jaodsilv@linux.ime.usp.br>/Pedro Leal/ | 185 | s/Pedro Leal <jaodsilv@linux.ime.usp.br>/Pedro Leal/ |
182 | 186 | ||
187 | +s/^pedrodelyra/Pedro de Lyra/ | ||
188 | + | ||
183 | s/Rafael Manzo$/Rafael Reggiani Manzo <rr.manzo@gmail.com>/ | 189 | s/Rafael Manzo$/Rafael Reggiani Manzo <rr.manzo@gmail.com>/ |
184 | s/Rafael Manzo <alessandro.palmeira@gmail.com>/Rafael Reggiani Manzo <rr.manzo@gmail.com>/ | 190 | s/Rafael Manzo <alessandro.palmeira@gmail.com>/Rafael Reggiani Manzo <rr.manzo@gmail.com>/ |
185 | s/Rafael Manzo <caio.csalgado@gmail.com>/Rafael Reggiani Manzo <rr.manzo@gmail.com>/ | 191 | s/Rafael Manzo <caio.csalgado@gmail.com>/Rafael Reggiani Manzo <rr.manzo@gmail.com>/ |
@@ -214,6 +220,10 @@ s/Valéssio Brito <contato@valessiobrito.com.br>/Valessio Brito <contato@valessi | @@ -214,6 +220,10 @@ s/Valéssio Brito <contato@valessiobrito.com.br>/Valessio Brito <contato@valessi | ||
214 | s/Valessio Brito <contato@valessiobrito.info>/Valessio Brito <contato@valessiobrito.com.br>/ | 220 | s/Valessio Brito <contato@valessiobrito.info>/Valessio Brito <contato@valessiobrito.com.br>/ |
215 | s/Valessio Brito <valessio@gmail.com>/Valessio Brito <contato@valessiobrito.com.br>/ | 221 | s/Valessio Brito <valessio@gmail.com>/Valessio Brito <contato@valessiobrito.com.br>/ |
216 | /Visita <visita@debian.(none)>/d | 222 | /Visita <visita@debian.(none)>/d |
223 | + | ||
224 | +s/Vítor Barbosa/Vitor Barbosa/ | ||
225 | +s/vitormga15@gmail.com/vitornga15@gmail.com/ | ||
226 | + | ||
217 | s/vfcosta <vfcosta@gmail.com>/Victor Costa <vfcosta@gmail.com>/ | 227 | s/vfcosta <vfcosta@gmail.com>/Victor Costa <vfcosta@gmail.com>/ |
218 | s/Victor Carvalho <victorhugodf.ac@gmail.com>/Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com>/ | 228 | s/Victor Carvalho <victorhugodf.ac@gmail.com>/Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com>/ |
219 | 229 |
script/install-dependencies/debian-wheezy.sh
1 | -binary_packages='deb http://download.noosfero.org/debian/wheezy-1.2 ./' | 1 | +binary_packages='deb http://download.noosfero.org/debian/wheezy-1.3 ./' |
2 | 2 | ||
3 | source_packages=$(echo "$binary_packages" | sed -e 's/^deb/deb-src/') | 3 | source_packages=$(echo "$binary_packages" | sed -e 's/^deb/deb-src/') |
4 | 4 |
test/functional/application_controller_test.rb
@@ -188,6 +188,16 @@ class ApplicationControllerTest < ActionController::TestCase | @@ -188,6 +188,16 @@ class ApplicationControllerTest < ActionController::TestCase | ||
188 | assert_tag :tag => 'option', :attributes => { :value => 'it' }, :content => 'Italiano' | 188 | assert_tag :tag => 'option', :attributes => { :value => 'it' }, :content => 'Italiano' |
189 | end | 189 | end |
190 | 190 | ||
191 | + should 'set and unset the current user' do | ||
192 | + testuser = create_user 'testuser' | ||
193 | + login_as 'testuser' | ||
194 | + User.expects(:current=).with do |user| | ||
195 | + user == testuser | ||
196 | + end.at_least_once | ||
197 | + User.expects(:current=).with(nil).at_least_once | ||
198 | + get :index | ||
199 | + end | ||
200 | + | ||
191 | should 'display link to webmail if enabled for system' do | 201 | should 'display link to webmail if enabled for system' do |
192 | @controller.stubs(:get_layout).returns('application') | 202 | @controller.stubs(:get_layout).returns('application') |
193 | login_as('ze') | 203 | login_as('ze') |
test/functional/cms_controller_test.rb
@@ -557,8 +557,17 @@ class CmsControllerTest < ActionController::TestCase | @@ -557,8 +557,17 @@ class CmsControllerTest < ActionController::TestCase | ||
557 | end | 557 | end |
558 | 558 | ||
559 | should 'keep informed parent_id' do | 559 | should 'keep informed parent_id' do |
560 | + fast_create(:blog, :name=>"Sample blog", :profile_id=>@profile.id) | ||
561 | + | ||
562 | + profile.home_page = profile.blogs.find_by_name "Sample blog" | ||
563 | + profile.save! | ||
564 | + | ||
560 | get :new, :profile => @profile.identifier, :parent_id => profile.home_page.id, :type => 'TextileArticle' | 565 | get :new, :profile => @profile.identifier, :parent_id => profile.home_page.id, :type => 'TextileArticle' |
561 | - assert_tag :tag => 'input', :attributes => { :name => 'parent_id', :value => profile.home_page.id } | 566 | + assert_tag :tag => 'select', |
567 | + :attributes => { :id => 'article_parent_id' }, | ||
568 | + :child => { | ||
569 | + :tag => "option", :attributes => {:value => profile.home_page.id, :selected => "selected"} | ||
570 | + } | ||
562 | end | 571 | end |
563 | 572 | ||
564 | should 'list folders before others' do | 573 | should 'list folders before others' do |
@@ -1836,14 +1845,6 @@ class CmsControllerTest < ActionController::TestCase | @@ -1836,14 +1845,6 @@ class CmsControllerTest < ActionController::TestCase | ||
1836 | assert_equal 'first version', assigns(:article).name | 1845 | assert_equal 'first version', assigns(:article).name |
1837 | end | 1846 | end |
1838 | 1847 | ||
1839 | - should 'clone article with its content' do | ||
1840 | - article = profile.articles.create(:name => 'first version') | ||
1841 | - | ||
1842 | - get :new, :profile => profile.identifier, :id => article.id, :clone => true, :type => 'TinyMceArticle' | ||
1843 | - | ||
1844 | - assert_match article.name, @response.body | ||
1845 | - end | ||
1846 | - | ||
1847 | should 'save article with content from older version' do | 1848 | should 'save article with content from older version' do |
1848 | article = profile.articles.create(:name => 'first version') | 1849 | article = profile.articles.create(:name => 'first version') |
1849 | article.name = 'second version'; article.save | 1850 | article.name = 'second version'; article.save |
@@ -1894,6 +1895,33 @@ class CmsControllerTest < ActionController::TestCase | @@ -1894,6 +1895,33 @@ class CmsControllerTest < ActionController::TestCase | ||
1894 | assert_equal '[{"label":"linux","value":"linux"}]', @response.body | 1895 | assert_equal '[{"label":"linux","value":"linux"}]', @response.body |
1895 | end | 1896 | end |
1896 | 1897 | ||
1898 | + should 'clone an article with its parent' do | ||
1899 | + login_as(profile.identifier) | ||
1900 | + | ||
1901 | + f = Folder.new(:name => 'f') | ||
1902 | + profile.articles << f | ||
1903 | + f.save! | ||
1904 | + | ||
1905 | + post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :parent_id => f.id, | ||
1906 | + :article => { :name => 'Main Article', :body => 'some content' } | ||
1907 | + | ||
1908 | + main_article = profile.articles.find_by_name('Main Article') | ||
1909 | + assert_not_nil main_article | ||
1910 | + | ||
1911 | + post :new, :type => 'TinyMceArticle', :profile => profile.identifier, :parent_id => f.id, | ||
1912 | + :id => main_article.id, :clone => true | ||
1913 | + | ||
1914 | + cloned_main_article = profile.articles.find_by_name('Main Article') | ||
1915 | + assert_not_nil cloned_main_article | ||
1916 | + | ||
1917 | + assert_equal main_article.parent_id, cloned_main_article.parent_id | ||
1918 | + | ||
1919 | + get :new, :profile => profile.identifier, :id => cloned_main_article.id, | ||
1920 | + :clone => true, :type => 'TinyMceArticle' | ||
1921 | + | ||
1922 | + assert_match main_article.body, @response.body | ||
1923 | + end | ||
1924 | + | ||
1897 | protected | 1925 | protected |
1898 | 1926 | ||
1899 | # FIXME this is to avoid adding an extra dependency for a proper JSON parser. | 1927 | # FIXME this is to avoid adding an extra dependency for a proper JSON parser. |
test/functional/content_viewer_controller_test.rb
@@ -1584,4 +1584,33 @@ class ContentViewerControllerTest < ActionController::TestCase | @@ -1584,4 +1584,33 @@ class ContentViewerControllerTest < ActionController::TestCase | ||
1584 | assert_tag :tag => 'div', :attributes => { :class => 'article-compact-image' } | 1584 | assert_tag :tag => 'div', :attributes => { :class => 'article-compact-image' } |
1585 | assert_tag :tag => 'div', :attributes => { :class => 'article-compact-abstract-with-image' } | 1585 | assert_tag :tag => 'div', :attributes => { :class => 'article-compact-abstract-with-image' } |
1586 | end | 1586 | end |
1587 | + | ||
1588 | + should 'not count a visit twice for the same user' do | ||
1589 | + profile = create_user('someone').person | ||
1590 | + login_as(@profile.identifier) | ||
1591 | + page = profile.articles.build(:name => 'myarticle', :body => 'the body of the text') | ||
1592 | + page.save! | ||
1593 | + | ||
1594 | + get :view_page, :profile => profile.identifier, :page => 'myarticle' | ||
1595 | + page.reload | ||
1596 | + assert_equal 1, page.hits | ||
1597 | + | ||
1598 | + get :view_page, :profile => profile.identifier, :page => 'myarticle' | ||
1599 | + page.reload | ||
1600 | + assert_equal 1, page.hits | ||
1601 | + end | ||
1602 | + | ||
1603 | + should 'not count a visit twice for unlogged users' do | ||
1604 | + profile = create_user('someone').person | ||
1605 | + page = profile.articles.build(:name => 'myarticle', :body => 'the body of the text') | ||
1606 | + page.save! | ||
1607 | + | ||
1608 | + get :view_page, :profile => profile.identifier, :page => 'myarticle' | ||
1609 | + page.reload | ||
1610 | + assert_equal 1, page.hits | ||
1611 | + | ||
1612 | + get :view_page, :profile => profile.identifier, :page => 'myarticle' | ||
1613 | + page.reload | ||
1614 | + assert_equal 1, page.hits | ||
1615 | + end | ||
1587 | end | 1616 | end |
test/functional/profile_controller_test.rb
@@ -52,7 +52,8 @@ class ProfileControllerTest < ActionController::TestCase | @@ -52,7 +52,8 @@ class ProfileControllerTest < ActionController::TestCase | ||
52 | 52 | ||
53 | assert_response :success | 53 | assert_response :success |
54 | assert_template 'members' | 54 | assert_template 'members' |
55 | - assert assigns(:members) | 55 | + assert assigns(:profile_members) |
56 | + assert assigns(:profile_admins) | ||
56 | end | 57 | end |
57 | 58 | ||
58 | should 'list favorite enterprises' do | 59 | should 'list favorite enterprises' do |
@@ -940,7 +941,7 @@ class ProfileControllerTest < ActionController::TestCase | @@ -940,7 +941,7 @@ class ProfileControllerTest < ActionController::TestCase | ||
940 | @controller.stubs(:current_user).returns(user) | 941 | @controller.stubs(:current_user).returns(user) |
941 | Person.any_instance.stubs(:follows?).returns(true) | 942 | Person.any_instance.stubs(:follows?).returns(true) |
942 | get :index, :profile => p1.identifier | 943 | get :index, :profile => p1.identifier |
943 | - assert_equal [s3,s2], assigns(:activities).map(&:activity) | 944 | + assert_equal [s3,s2], assigns(:activities).map(&:activity).select {|a| a.kind_of?(Scrap)} |
944 | end | 945 | end |
945 | 946 | ||
946 | should 'the activities be the received scraps in community profile' do | 947 | should 'the activities be the received scraps in community profile' do |
@@ -1746,4 +1747,68 @@ class ProfileControllerTest < ActionController::TestCase | @@ -1746,4 +1747,68 @@ class ProfileControllerTest < ActionController::TestCase | ||
1746 | assert_no_tag :tag => 'td', :descendant => { :tag => 'a', :content => /#{person.enterprises.count}/, :attributes => { :href => /profile\/#{person.identifier}\/enterprises$/ }} | 1747 | assert_no_tag :tag => 'td', :descendant => { :tag => 'a', :content => /#{person.enterprises.count}/, :attributes => { :href => /profile\/#{person.identifier}\/enterprises$/ }} |
1747 | end | 1748 | end |
1748 | 1749 | ||
1750 | + should 'admins from a community be present in admin users div and members div' do | ||
1751 | + community = fast_create(Community) | ||
1752 | + another_user = create_user('another_user').person | ||
1753 | + | ||
1754 | + login_as(@profile.identifier) | ||
1755 | + | ||
1756 | + community.add_admin(@profile) | ||
1757 | + | ||
1758 | + assert community.admins.include? @profile | ||
1759 | + get :members, :profile => community.identifier | ||
1760 | + | ||
1761 | + assert_tag :tag => 'ul', :attributes => { :class => /profile-list-admins/}, | ||
1762 | + :descendant => { :tag => 'a', :attributes => { :title => "testuser" } } | ||
1763 | + | ||
1764 | + assert_tag :tag => 'ul', :attributes => { :class => /profile-list-members/}, | ||
1765 | + :descendant => { :tag => 'a', :attributes => { :title => "testuser" } } | ||
1766 | + end | ||
1767 | + | ||
1768 | + should 'all members, except admins, be present in members div' do | ||
1769 | + community = fast_create(Community) | ||
1770 | + community.add_member(@profile) | ||
1771 | + | ||
1772 | + another_user = create_user('another_user').person | ||
1773 | + community.add_member(another_user) | ||
1774 | + | ||
1775 | + assert_equal false, community.admins.include?(another_user) | ||
1776 | + | ||
1777 | + get :members, :profile => community.identifier | ||
1778 | + | ||
1779 | + assert_tag :tag => 'ul', :attributes => { :class => /profile-list-members/}, | ||
1780 | + :descendant => { :tag => 'a', :attributes => { :title => "another_user" } } | ||
1781 | + | ||
1782 | + assert_no_tag :tag => 'ul', :attributes => { :class => /profile-list-admins/}, | ||
1783 | + :descendant => { :tag => 'a', :attributes => { :title => "another_user" } } | ||
1784 | + end | ||
1785 | + | ||
1786 | + should 'members be sorted by name in ascendant order' do | ||
1787 | + community = fast_create(Community) | ||
1788 | + another_user = create_user('another_user').person | ||
1789 | + different_user = create_user('different_user').person | ||
1790 | + | ||
1791 | + community.add_member(@profile) | ||
1792 | + community.add_member(another_user) | ||
1793 | + community.add_member(different_user) | ||
1794 | + | ||
1795 | + get :members, :profile => community.identifier, :sort => "asc" | ||
1796 | + | ||
1797 | + assert @response.body.index("another_user") < @response.body.index("different_user") | ||
1798 | + end | ||
1799 | + | ||
1800 | + should 'members be sorted by name in descendant order' do | ||
1801 | + community = fast_create(Community) | ||
1802 | + another_user = create_user('another_user').person | ||
1803 | + different_user = create_user('different_user').person | ||
1804 | + | ||
1805 | + community.add_member(@profile) | ||
1806 | + community.add_member(another_user) | ||
1807 | + community.add_member(different_user) | ||
1808 | + | ||
1809 | + get :members, :profile => community.identifier, :sort => "desc" | ||
1810 | + | ||
1811 | + assert @response.body.index("another_user") > @response.body.index("different_user") | ||
1812 | + end | ||
1813 | + | ||
1749 | end | 1814 | end |
@@ -0,0 +1,21 @@ | @@ -0,0 +1,21 @@ | ||
1 | +require_relative "../test_helper" | ||
2 | + | ||
3 | +class CloneArticleTest < ActiveSupport::TestCase | ||
4 | + | ||
5 | + should 'cloned article have its source attributes' do | ||
6 | + community = fast_create(Community) | ||
7 | + folder = fast_create(Folder, :profile_id => community.id) | ||
8 | + article = fast_create(TinyMceArticle, :profile_id => community.id) | ||
9 | + article.parent_id = folder.id | ||
10 | + article.save! | ||
11 | + | ||
12 | + article.reload | ||
13 | + cloned_article = article.copy_without_save({:parent_id => article.parent_id}) | ||
14 | + | ||
15 | + assert_equal folder.id, cloned_article.parent_id | ||
16 | + assert_equal article.body , cloned_article.body | ||
17 | + assert_equal article.name, cloned_article.name | ||
18 | + assert_equal article.setting, cloned_article.setting | ||
19 | + end | ||
20 | + | ||
21 | +end | ||
0 | \ No newline at end of file | 22 | \ No newline at end of file |
test/unit/scrap_test.rb
@@ -6,6 +6,7 @@ class ScrapTest < ActiveSupport::TestCase | @@ -6,6 +6,7 @@ class ScrapTest < ActiveSupport::TestCase | ||
6 | Person.destroy_all | 6 | Person.destroy_all |
7 | Scrap.destroy_all | 7 | Scrap.destroy_all |
8 | ActionTracker::Record.destroy_all | 8 | ActionTracker::Record.destroy_all |
9 | + Delayed::Job.destroy_all | ||
9 | end | 10 | end |
10 | 11 | ||
11 | should "have the content" do | 12 | should "have the content" do |