Commit 4d9daa44dbf61490640b32a8fb9f6f49f0f8b152
Exists in
staging
and in
1 other branch
Merge branch 'master' into staging
Showing
136 changed files
with
1279 additions
and
399 deletions
Show diff stats
.travis.yml
RELEASING.md
... | ... | @@ -3,37 +3,30 @@ Noosfero release tasks |
3 | 3 | |
4 | 4 | This file documents release-related activities. |
5 | 5 | |
6 | -Working with translations | |
7 | -------------------------- | |
8 | - | |
9 | -* Update translation files: `rake updatepo`. Then `git commit` them. | |
10 | -* Send the PO files to the translators. | |
11 | -* Get the PO files back from translators, put in `po/` under the correct language name (e.,g. `po/pt_BR/`) and `git commit`. | |
12 | -* test translations: `rake makemo` and browse the application on the web. | |
13 | - | |
14 | 6 | Releasing noosfero |
15 | 7 | ------------------ |
16 | 8 | |
17 | -Considering you are on a Debian GNU/Linux or Debian-based system | |
9 | +Considering you are on a Debian GNU/Linux or Debian-based system, the following | |
10 | +packages are required during the release process: | |
18 | 11 | |
19 | - # apt-get install devscripts debhelper | |
12 | +``` | |
13 | +# apt install git devscripts debhelper | |
14 | +``` | |
20 | 15 | |
21 | 16 | To prepare a release of noosfero, you must follow the steps below: |
22 | 17 | |
23 | -* Finish all requirements and bugs assigned to the to-be-released version | |
18 | +* Disable the automatic pushing of translation updates in weblate. | |
24 | 19 | * Make sure all tests pass |
25 | -* Write release notes at the version's wiki topic | |
26 | 20 | * Generate packages with `rake noosfero:release[(stable|test)]`. This task will: |
27 | 21 | * Update the version in lib/noosfero.rb and debian/changelog. |
28 | 22 | * Create the tarbal and the deb pkg under pkg/ directory. |
29 | 23 | * Create a git tag and push it. |
30 | - * Upload the pkg to the configured repository (if configured) on ~/.dput.cf. | |
24 | + * Upload the packages to the configured repository (if configured) on ~/.dput.cf. | |
31 | 25 | * Test that the tarball and deb package are ok |
32 | -* Go to the version's wiki topic and edit it to reflect the new reality | |
33 | -* Edit the topic WebPreferences and update DEBIAN_REPOSITORY_TOPICS setting | |
34 | -* Attach the generated packages to that topic. Before attaching calculate the sha1 of the package (with sha1sum and paste the SHA1 hash as comment in the attachment form) | |
35 | -* Download the attached and verify the MD5 hash | |
36 | 26 | * Update an eventual demonstration version that you run. |
37 | -* Write an announcement e-mail to the relevant mailing lists pointing to the release notes, and maybe to the demonstration version. | |
27 | +* Write an announcement e-mail to the relevant mailing lists pointing to the | |
28 | + release notes, and maybe to the demonstration version. | |
29 | +* Re-enable the automatic pushing of trasnlatio updates in weblate. | |
38 | 30 | |
39 | -If you had any problem during these steps, you can do `rake clobber_package` to completely delete the generated packages and start the process again. | |
31 | +If you had any problem during these steps, you can do `rake clobber_package` to | |
32 | +completely delete the generated packages and start the process again. | ... | ... |
app/controllers/box_organizer_controller.rb
... | ... | @@ -83,12 +83,9 @@ class BoxOrganizerController < ApplicationController |
83 | 83 | |
84 | 84 | def save |
85 | 85 | @block = boxes_holder.blocks.find(params[:id]) |
86 | - if @block.kind_of?(RawHTMLBlock) && !user.is_admin?(environment) | |
87 | - render_access_denied | |
88 | - else | |
89 | - @block.update(params[:block]) | |
90 | - redirect_to :action => 'index' | |
91 | - end | |
86 | + return render_access_denied unless @block.editable?(user) | |
87 | + @block.update(params[:block]) | |
88 | + redirect_to :action => 'index' | |
92 | 89 | end |
93 | 90 | |
94 | 91 | def boxes_editor? | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -32,7 +32,8 @@ class CmsController < MyProfileController |
32 | 32 | end |
33 | 33 | |
34 | 34 | protect_if :only => [:new, :upload_files] do |c, user, profile| |
35 | - parent = profile.articles.find_by_id(c.params[:parent_id]) | |
35 | + parent_id = c.params[:article].present? ? c.params[:article][:parent_id] : c.params[:parent_id] | |
36 | + parent = profile.articles.find_by_id(parent_id) | |
36 | 37 | user && user.can_post_content?(profile, parent) |
37 | 38 | end |
38 | 39 | ... | ... |
app/controllers/my_profile/profile_members_controller.rb
... | ... | @@ -2,8 +2,27 @@ class ProfileMembersController < MyProfileController |
2 | 2 | protect 'manage_memberships', :profile |
3 | 3 | |
4 | 4 | def index |
5 | - @members = profile.members_by_name | |
6 | - @member_role = environment.roles.find_by_name('member') | |
5 | + @filters = params[:filters] || {:roles => []} | |
6 | + all_roles = Profile::Roles.organization_member_roles(environment.id) | Profile::Roles.organization_custom_roles(environment.id, profile.id) | |
7 | + @filters[:roles] = all_roles unless @filters[:roles].present? | |
8 | + @data = {} | |
9 | + field = 'name' | |
10 | + field = 'email' if @filters[:name] =~ /\@/ | |
11 | + | |
12 | + @data[:members] = profile.members_by(field,@filters[:name]).by_role(@filters[:roles]) | |
13 | + session[:members_filtered] = @data[:members].map{|m|m.id} if request.post? | |
14 | + @data[:roles] = all_roles | |
15 | + | |
16 | + end | |
17 | + | |
18 | + def send_mail | |
19 | + session[:members_filtered] = params[:members_filtered].select{|value| value!="0"} | |
20 | + if session[:members_filtered].present? | |
21 | + redirect_to :controller => :profile, :action => :send_mail | |
22 | + else | |
23 | + session[:notice] = _("Select at least one member.") | |
24 | + redirect_to :action => :index | |
25 | + end | |
7 | 26 | end |
8 | 27 | |
9 | 28 | def update_roles |
... | ... | @@ -156,4 +175,13 @@ class ProfileMembersController < MyProfileController |
156 | 175 | end |
157 | 176 | end |
158 | 177 | |
178 | + def search_members | |
179 | + field = 'name' | |
180 | + field = 'email' if params[:filter_name] =~ /\@/ | |
181 | + | |
182 | + result = profile.members_like field, params[:filter_name] | |
183 | + result = result.select{|member| member.can_view_field?(current_person, "email") } if field=="email" | |
184 | + render :json => result.map { |member| {:label => "#{member.name}#{member.can_view_field?(current_person, "email") ? " <#{member.email}>" : ""}", :value => member.name }} | |
185 | + end | |
186 | + | |
159 | 187 | end | ... | ... |
app/controllers/public/account_controller.rb
... | ... | @@ -198,7 +198,7 @@ class AccountController < ApplicationController |
198 | 198 | if request.post? |
199 | 199 | begin |
200 | 200 | unless verify_recaptcha |
201 | - @change_password.errors.add(:base, _('Please type the words correctly')) | |
201 | + @change_password.errors.add(:base, _('Please type the captcha text correctly')) | |
202 | 202 | return false |
203 | 203 | end |
204 | 204 | ... | ... |
app/controllers/public/content_viewer_controller.rb
... | ... | @@ -68,11 +68,7 @@ class ContentViewerController < ApplicationController |
68 | 68 | process_comments(params) |
69 | 69 | |
70 | 70 | if request.xhr? and params[:comment_order] |
71 | - if @comment_order == 'newest' | |
72 | - @comments = @comments.reverse | |
73 | - end | |
74 | - | |
75 | - return render :partial => 'comment/comment', :collection => @comments | |
71 | + return render :partial => 'comment/comments_with_pagination' | |
76 | 72 | end |
77 | 73 | |
78 | 74 | if params[:slideshow] |
... | ... | @@ -209,8 +205,6 @@ class ContentViewerController < ApplicationController |
209 | 205 | |
210 | 206 | def rendered_file_download(view = nil) |
211 | 207 | if @page.download? view |
212 | - headers['Content-Type'] = @page.mime_type | |
213 | - headers.merge! @page.download_headers | |
214 | 208 | data = @page.data |
215 | 209 | |
216 | 210 | # TODO test the condition |
... | ... | @@ -218,7 +212,12 @@ class ContentViewerController < ApplicationController |
218 | 212 | raise "No data for file" |
219 | 213 | end |
220 | 214 | |
221 | - render :text => data, :layout => false | |
215 | + if @page.published && @page.uploaded_file? | |
216 | + redirect_to @page.public_filename | |
217 | + else | |
218 | + send_data data, @page.download_headers | |
219 | + end | |
220 | + | |
222 | 221 | return true |
223 | 222 | end |
224 | 223 | |
... | ... | @@ -244,8 +243,12 @@ class ContentViewerController < ApplicationController |
244 | 243 | |
245 | 244 | def get_posts(year = nil, month = nil) |
246 | 245 | if year && month |
247 | - filter_date = DateTime.parse("#{year}-#{month}-01") | |
248 | - return @page.posts.by_range(filter_date..filter_date.at_end_of_month) | |
246 | + begin | |
247 | + filter_date = DateTime.parse("#{year}-#{month}-01") | |
248 | + return @page.posts.by_range(filter_date..filter_date.at_end_of_month) | |
249 | + rescue ArgumentError | |
250 | + return @page.posts | |
251 | + end | |
249 | 252 | else |
250 | 253 | return @page.posts |
251 | 254 | end |
... | ... | @@ -276,8 +279,12 @@ class ContentViewerController < ApplicationController |
276 | 279 | @comments = @page.comments.without_spam |
277 | 280 | @comments = @plugins.filter(:unavailable_comments, @comments) |
278 | 281 | @comments_count = @comments.count |
279 | - @comments = @comments.without_reply.paginate(:per_page => per_page, :page => params[:comment_page] ) | |
280 | 282 | @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order] |
283 | + @comments = @comments.without_reply | |
284 | + if @comment_order == 'newest' | |
285 | + @comments = @comments.reverse | |
286 | + end | |
287 | + @comments = @comments.paginate(:per_page => per_page, :page => params[:comment_page] ) | |
281 | 288 | end |
282 | 289 | |
283 | 290 | private | ... | ... |
app/controllers/public/profile_controller.rb
... | ... | @@ -155,6 +155,18 @@ class ProfileController < PublicController |
155 | 155 | end |
156 | 156 | end |
157 | 157 | |
158 | + def follow_article | |
159 | + article = profile.environment.articles.find params[:article_id] | |
160 | + article.person_followers << user | |
161 | + redirect_to article.url | |
162 | + end | |
163 | + | |
164 | + def unfollow_article | |
165 | + article = profile.environment.articles.find params[:article_id] | |
166 | + article.person_followers.delete(user) | |
167 | + redirect_to article.url | |
168 | + end | |
169 | + | |
158 | 170 | def unblock |
159 | 171 | if current_user.person.is_admin?(profile.environment) |
160 | 172 | profile.unblock |
... | ... | @@ -362,6 +374,7 @@ class ProfileController < PublicController |
362 | 374 | def send_mail |
363 | 375 | @mailing = profile.mailings.build(params[:mailing]) |
364 | 376 | @email_templates = profile.email_templates.find_all_by_template_type(:organization_members) |
377 | + @mailing.data = session[:members_filtered] ? {:members_filtered => session[:members_filtered]} : {} | |
365 | 378 | if request.post? |
366 | 379 | @mailing.locale = locale |
367 | 380 | @mailing.person = user | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -150,14 +150,8 @@ module ApplicationHelper |
150 | 150 | link_to text, profile_path(:profile => profile) , options |
151 | 151 | end |
152 | 152 | |
153 | - def link_to_homepage(text, profile = nil, options = {}) | |
154 | - p = if profile | |
155 | - Profile[profile] | |
156 | - else | |
157 | - user | |
158 | - end | |
159 | - | |
160 | - link_to text, p.url, options | |
153 | + def link_to_homepage(text, profile, options = {}) | |
154 | + link_to text, profile.url, options | |
161 | 155 | end |
162 | 156 | |
163 | 157 | def link_if_permitted(link, permission = nil, target = nil) |
... | ... | @@ -556,14 +550,25 @@ module ApplicationHelper |
556 | 550 | trigger_class = 'enterprise-trigger' |
557 | 551 | end |
558 | 552 | end |
559 | - extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) | |
553 | + | |
554 | + extra_info_tag = '' | |
555 | + img_class = 'profile-image' | |
556 | + | |
557 | + if extra_info.is_a? Hash | |
558 | + extra_info_tag = content_tag( 'span', extra_info[:value], :class => 'extra_info '+extra_info[:class]) | |
559 | + img_class +=' '+extra_info[:class] | |
560 | + else | |
561 | + extra_info_tag = content_tag( 'span', extra_info, :class => 'extra_info' ) | |
562 | + end | |
563 | + | |
560 | 564 | links = links_for_balloon(profile) |
561 | 565 | content_tag('div', content_tag(tag, |
562 | - (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") + | |
566 | + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? | |
567 | + popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") + | |
563 | 568 | link_to( |
564 | - content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) + | |
569 | + content_tag( 'span', profile_image( profile, size ), :class => img_class ) + | |
565 | 570 | content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + |
566 | - extra_info + profile_sex_icon( profile ), | |
571 | + extra_info_tag + profile_sex_icon( profile ), | |
567 | 572 | profile.url, |
568 | 573 | :class => 'profile_link url', |
569 | 574 | :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, |
... | ... | @@ -711,7 +716,7 @@ module ApplicationHelper |
711 | 716 | class NoosferoFormBuilder < ActionView::Helpers::FormBuilder |
712 | 717 | extend ActionView::Helpers::TagHelper |
713 | 718 | |
714 | - def self.output_field(text, field_html, field_id = nil, options = {}) | |
719 | + def self.output_field(text, field_html, field_id = nil) | |
715 | 720 | # try to guess an id if none given |
716 | 721 | if field_id.nil? |
717 | 722 | field_html =~ /id=['"]([^'"]*)['"]/ |
... | ... | @@ -1040,10 +1045,11 @@ module ApplicationHelper |
1040 | 1045 | end |
1041 | 1046 | |
1042 | 1047 | def search_contents_menu |
1048 | + host = environment.default_hostname | |
1043 | 1049 | links = [ |
1044 | - {s_('contents|More recent') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_recent'})}}, | |
1045 | - {s_('contents|More viewed') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_popular'})}}, | |
1046 | - {s_('contents|Most commented') => {:href => url_for({:controller => 'search', :action => 'contents', :filter => 'more_comments'})}} | |
1050 | + {s_('contents|More recent') => {href: url_for({host: host, controller: 'search', action: 'contents', filter: 'more_recent'})}}, | |
1051 | + {s_('contents|More viewed') => {href: url_for({host: host, controller: 'search', action: 'contents', filter: 'more_popular'})}}, | |
1052 | + {s_('contents|Most commented') => {href: url_for({host: host, controller: 'search', action: 'contents', filter: 'more_comments'})}} | |
1047 | 1053 | ] |
1048 | 1054 | if logged_in? |
1049 | 1055 | links.push(_('New content') => modal_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})})) |
... | ... | @@ -1055,10 +1061,11 @@ module ApplicationHelper |
1055 | 1061 | alias :browse_contents_menu :search_contents_menu |
1056 | 1062 | |
1057 | 1063 | def search_people_menu |
1064 | + host = environment.default_hostname | |
1058 | 1065 | links = [ |
1059 | - {s_('people|More recent') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_recent'})}}, | |
1060 | - {s_('people|More active') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_active'})}}, | |
1061 | - {s_('people|More popular') => {:href => url_for({:controller => 'search', :action => 'people', :filter => 'more_popular'})}} | |
1066 | + {s_('people|More recent') => {href: url_for({host: host, controller: 'search', action: 'people', filter: 'more_recent'})}}, | |
1067 | + {s_('people|More active') => {href: url_for({host: host, controller: 'search', action: 'people', filter: 'more_active'})}}, | |
1068 | + {s_('people|More popular') => {href: url_for({host: host, controller: 'search', action: 'people', filter: 'more_popular'})}} | |
1062 | 1069 | ] |
1063 | 1070 | if logged_in? |
1064 | 1071 | links.push(_('My friends') => {:href => url_for({:profile => current_user.login, :controller => 'friends'})}) |
... | ... | @@ -1071,10 +1078,11 @@ module ApplicationHelper |
1071 | 1078 | alias :browse_people_menu :search_people_menu |
1072 | 1079 | |
1073 | 1080 | def search_communities_menu |
1081 | + host = environment.default_hostname | |
1074 | 1082 | links = [ |
1075 | - {s_('communities|More recent') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_recent'})}}, | |
1076 | - {s_('communities|More active') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_active'})}}, | |
1077 | - {s_('communities|More popular') => {:href => url_for({:controller => 'search', :action => 'communities', :filter => 'more_popular'})}} | |
1083 | + {s_('communities|More recent') => {href: url_for({host: host, controller: 'search', action: 'communities', filter: 'more_recent'})}}, | |
1084 | + {s_('communities|More active') => {href: url_for({host: host, controller: 'search', action: 'communities', filter: 'more_active'})}}, | |
1085 | + {s_('communities|More popular') => {href: url_for({host: host, controller: 'search', action: 'communities', filter: 'more_popular'})}} | |
1078 | 1086 | ] |
1079 | 1087 | if logged_in? |
1080 | 1088 | links.push(_('My communities') => {:href => url_for({:profile => current_user.login, :controller => 'memberships'})}) | ... | ... |
app/helpers/article_helper.rb
... | ... | @@ -169,4 +169,30 @@ module ArticleHelper |
169 | 169 | _('Edit') |
170 | 170 | end |
171 | 171 | |
172 | + def follow_button_text(article) | |
173 | + if article.event? | |
174 | + _('Attend') | |
175 | + else | |
176 | + _('Follow') | |
177 | + end | |
178 | + end | |
179 | + | |
180 | + def unfollow_button_text(article) | |
181 | + if article.event? | |
182 | + _('Unattend') | |
183 | + else | |
184 | + _('Unfollow') | |
185 | + end | |
186 | + end | |
187 | + | |
188 | + def following_button(page, user) | |
189 | + if !user.blank? and user != page.author | |
190 | + if page.is_followed_by? user | |
191 | + button :cancel, unfollow_button_text(page), {:controller => 'profile', :action => 'unfollow_article', :article_id => page.id} | |
192 | + else | |
193 | + button :add, follow_button_text(page), {:controller => 'profile', :action => 'follow_article', :article_id => page.id} | |
194 | + end | |
195 | + end | |
196 | + end | |
197 | + | |
172 | 198 | end | ... | ... |
app/helpers/block_helper.rb
... | ... | @@ -14,6 +14,7 @@ module BlockHelper |
14 | 14 | </td> |
15 | 15 | <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td> |
16 | 16 | <td>#{text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 1}</td> |
17 | + <td>#{check_box_tag 'block[images][][new_window]', '1', image[:new_window], :class => 'highlight-new_window', :size => 1}</td> | |
17 | 18 | </tr><tr class=\"image-title\" data-row-number='#{row_number}'> |
18 | 19 | <td colspan=\"3\"><label>#{ |
19 | 20 | content_tag('span', _('Title')) + | ... | ... |
app/helpers/boxes_helper.rb
... | ... | @@ -250,7 +250,7 @@ module BoxesHelper |
250 | 250 | end |
251 | 251 | end |
252 | 252 | |
253 | - if editable?(block) | |
253 | + if editable?(block, user) | |
254 | 254 | buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id }) |
255 | 255 | end |
256 | 256 | |
... | ... | @@ -296,7 +296,7 @@ module BoxesHelper |
296 | 296 | return block.movable? || user.is_admin? |
297 | 297 | end |
298 | 298 | |
299 | - def editable?(block) | |
300 | - return block.editable? || user.is_admin? | |
299 | + def editable?(block, user=nil) | |
300 | + return block.editable?(user) || user.is_admin? | |
301 | 301 | end |
302 | 302 | end | ... | ... |
app/helpers/forms_helper.rb
... | ... | @@ -7,9 +7,10 @@ module FormsHelper |
7 | 7 | |
8 | 8 | def labelled_check_box( human_name, name, value = "1", checked = false, options = {} ) |
9 | 9 | options[:id] ||= 'checkbox-' + FormsHelper.next_id_number |
10 | - hidden_field_tag(name, '0') + | |
11 | - check_box_tag( name, value, checked, options ) + | |
12 | - content_tag( 'label', human_name, :for => options[:id] ) | |
10 | + html = options[:add_hidden] == false ? "" : hidden_field_tag(name, '0') | |
11 | + | |
12 | + html += check_box_tag( name, value, checked, options ) + | |
13 | + content_tag( 'label', human_name, :for => options[:id] ) | |
13 | 14 | end |
14 | 15 | |
15 | 16 | def labelled_text_field( human_name, name, value=nil, options={} ) | ... | ... |
app/mailers/mailing.rb
... | ... | @@ -2,7 +2,10 @@ require_dependency 'mailing_job' |
2 | 2 | |
3 | 3 | class Mailing < ActiveRecord::Base |
4 | 4 | |
5 | - attr_accessible :subject, :body | |
5 | + acts_as_having_settings :field => :data | |
6 | + | |
7 | + attr_accessible :subject, :body, :data | |
8 | + | |
6 | 9 | validates_presence_of :source_id, :subject, :body |
7 | 10 | belongs_to :source, :foreign_key => :source_id, :polymorphic => true |
8 | 11 | belongs_to :person | ... | ... |
app/mailers/organization_mailing.rb
... | ... | @@ -5,9 +5,17 @@ class OrganizationMailing < Mailing |
5 | 5 | end |
6 | 6 | |
7 | 7 | def recipients(offset=0, limit=100) |
8 | - source.members.order(:id).offset(offset).limit(limit) | |
9 | - .joins("LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)") | |
8 | + result = source.members.order(:id).offset(offset).limit(limit) | |
9 | + | |
10 | + if data.present? and data.is_a?(Hash) and data[:members_filtered] | |
11 | + result = result.where('profiles.id IN (?)', data[:members_filtered]) | |
12 | + end | |
13 | + | |
14 | + if result.blank? | |
15 | + result = result.joins("LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)") | |
10 | 16 | .where("m.person_id" => nil) |
17 | + end | |
18 | + result | |
11 | 19 | end |
12 | 20 | |
13 | 21 | def each_recipient | ... | ... |
app/models/article.rb
... | ... | @@ -8,8 +8,9 @@ class Article < ActiveRecord::Base |
8 | 8 | :accept_comments, :feed, :published, :source, :source_name, |
9 | 9 | :highlighted, :notify_comments, :display_hits, :slug, |
10 | 10 | :external_feed_builder, :display_versions, :external_link, |
11 | - :author, :published_at, :person_followers, :show_to_followers, | |
12 | - :image_builder, :display_preview, :archived | |
11 | + :image_builder, :show_to_followers, | |
12 | + :author, :display_preview, :published_at, :person_followers, | |
13 | + :archived | |
13 | 14 | |
14 | 15 | acts_as_having_image |
15 | 16 | |
... | ... | @@ -83,6 +84,10 @@ class Article < ActiveRecord::Base |
83 | 84 | |
84 | 85 | has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc' |
85 | 86 | |
87 | + has_many :article_followers, :dependent => :destroy | |
88 | + has_many :person_followers, :class_name => 'Person', :through => :article_followers, :source => :person | |
89 | + has_many :person_followers_emails, :class_name => 'User', :through => :person_followers, :source => :user, :select => :email | |
90 | + | |
86 | 91 | has_many :article_categorizations, -> { where 'articles_categories.virtual = ?', false } |
87 | 92 | has_many :categories, :through => :article_categorizations |
88 | 93 | |
... | ... | @@ -95,7 +100,6 @@ class Article < ActiveRecord::Base |
95 | 100 | settings_items :author_name, :type => :string, :default => "" |
96 | 101 | settings_items :allow_members_to_edit, :type => :boolean, :default => false |
97 | 102 | settings_items :moderate_comments, :type => :boolean, :default => false |
98 | - settings_items :followers, :type => Array, :default => [] | |
99 | 103 | has_and_belongs_to_many :article_privacy_exceptions, :class_name => 'Person', :join_table => 'article_privacy_exceptions' |
100 | 104 | |
101 | 105 | belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id' |
... | ... | @@ -173,7 +177,6 @@ class Article < ActiveRecord::Base |
173 | 177 | end |
174 | 178 | end |
175 | 179 | |
176 | - | |
177 | 180 | def is_trackable? |
178 | 181 | self.published? && self.notifiable? && self.advertise? && self.profile.public_profile |
179 | 182 | end |
... | ... | @@ -374,6 +377,10 @@ class Article < ActiveRecord::Base |
374 | 377 | self.parent and self.parent.forum? |
375 | 378 | end |
376 | 379 | |
380 | + def person_followers_email_list | |
381 | + person_followers_emails.map{|p|p.email} | |
382 | + end | |
383 | + | |
377 | 384 | def info_from_last_update |
378 | 385 | last_comment = comments.last |
379 | 386 | if last_comment |
... | ... | @@ -383,6 +390,10 @@ class Article < ActiveRecord::Base |
383 | 390 | end |
384 | 391 | end |
385 | 392 | |
393 | + def full_path | |
394 | + profile.hostname.blank? ? "/#{profile.identifier}/#{path}" : "/#{path}" | |
395 | + end | |
396 | + | |
386 | 397 | def url |
387 | 398 | @url ||= self.profile.url.merge(:page => path.split('/')) |
388 | 399 | end |
... | ... | @@ -408,13 +419,19 @@ class Article < ActiveRecord::Base |
408 | 419 | end |
409 | 420 | |
410 | 421 | def download? view = nil |
411 | - (self.uploaded_file? and not self.image?) or | |
412 | - (self.image? and view.blank?) or | |
413 | - (not self.uploaded_file? and self.mime_type != 'text/html') | |
422 | + false | |
423 | + end | |
424 | + | |
425 | + def is_followed_by?(user) | |
426 | + self.person_followers.include? user | |
427 | + end | |
428 | + | |
429 | + def download_disposition | |
430 | + 'inline' | |
414 | 431 | end |
415 | 432 | |
416 | 433 | def download_headers |
417 | - {} | |
434 | + { :filename => filename, :type => mime_type, :disposition => download_disposition} | |
418 | 435 | end |
419 | 436 | |
420 | 437 | def alternate_languages | ... | ... |
app/models/block.rb
... | ... | @@ -195,8 +195,8 @@ class Block < ActiveRecord::Base |
195 | 195 | nil |
196 | 196 | end |
197 | 197 | |
198 | - # Is this block editable? (Default to <tt>false</tt>) | |
199 | - def editable? | |
198 | + # Is this block editable? (Default to <tt>true</tt>) | |
199 | + def editable?(user=nil) | |
200 | 200 | self.edit_modes == "all" |
201 | 201 | end |
202 | 202 | ... | ... |
app/models/comment.rb
... | ... | @@ -6,13 +6,14 @@ class Comment < ActiveRecord::Base |
6 | 6 | :body => {:label => _('Content'), :weight => 2}, |
7 | 7 | } |
8 | 8 | |
9 | - attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source | |
9 | + attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source, :follow_article | |
10 | 10 | |
11 | 11 | validates_presence_of :body |
12 | 12 | |
13 | 13 | belongs_to :source, :counter_cache => true, :polymorphic => true |
14 | 14 | alias :article :source |
15 | 15 | alias :article= :source= |
16 | + attr_accessor :follow_article | |
16 | 17 | |
17 | 18 | belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' |
18 | 19 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
... | ... | @@ -102,10 +103,9 @@ class Comment < ActiveRecord::Base |
102 | 103 | |
103 | 104 | after_create :new_follower |
104 | 105 | def new_follower |
105 | - if source.kind_of?(Article) | |
106 | - article.followers += [author_email] | |
107 | - article.followers -= article.profile.notification_emails | |
108 | - article.followers.uniq! | |
106 | + if source.kind_of?(Article) and !author.nil? and @follow_article | |
107 | + article.person_followers += [author] | |
108 | + article.person_followers.uniq! | |
109 | 109 | article.save |
110 | 110 | end |
111 | 111 | end |
... | ... | @@ -147,7 +147,7 @@ class Comment < ActiveRecord::Base |
147 | 147 | if !notification_emails.empty? |
148 | 148 | CommentNotifier.notification(self).deliver |
149 | 149 | end |
150 | - emails = article.followers - [author_email] | |
150 | + emails = article.person_followers_email_list - [author_email] | |
151 | 151 | if !emails.empty? |
152 | 152 | CommentNotifier.mail_to_followers(self, emails).deliver |
153 | 153 | end | ... | ... |
app/models/disabled_enterprise_message_block.rb
app/models/environment.rb
... | ... | @@ -56,6 +56,7 @@ class Environment < ActiveRecord::Base |
56 | 56 | 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'), |
57 | 57 | 'edit_appearance' => N_('Edit appearance'), |
58 | 58 | 'manage_email_templates' => N_('Manage Email Templates'), |
59 | + 'edit_raw_html_block' => N_('Edit Raw HTML block'), | |
59 | 60 | } |
60 | 61 | |
61 | 62 | module Roles | ... | ... |
app/models/highlights_block.rb
... | ... | @@ -15,6 +15,8 @@ class HighlightsBlock < Block |
15 | 15 | if !Noosfero.root.nil? and !i[:address].start_with?(Noosfero.root + '/') |
16 | 16 | i[:address] = Noosfero.root + i[:address] |
17 | 17 | end |
18 | + i[:new_window] = i[:new_window] == '1' ? true : false | |
19 | + | |
18 | 20 | begin |
19 | 21 | file = UploadedFile.find(i[:image_id]) |
20 | 22 | i[:image_src] = file.public_filename | ... | ... |
app/models/person.rb
1 | 1 | # A person is the profile of an user holding all relationships with the rest of the system |
2 | 2 | class Person < Profile |
3 | 3 | |
4 | - attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, | |
5 | - :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, | |
6 | - :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, | |
7 | - :custom_area_of_study, :professional_activity, :organization_website, :following_articles | |
4 | + attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website, :following_articles | |
8 | 5 | |
9 | 6 | SEARCH_FILTERS = { |
10 | 7 | :order => %w[more_recent more_popular more_active], |
... | ... | @@ -19,26 +16,29 @@ class Person < Profile |
19 | 16 | acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)} |
20 | 17 | acts_as_accessor |
21 | 18 | |
22 | - scope :members_of, -> resources { | |
19 | + scope :members_of, lambda { |resources, field = ''| | |
23 | 20 | resources = Array(resources) |
21 | + joins = [:role_assignments] | |
22 | + joins << :user if User.attribute_names.include? field | |
23 | + | |
24 | 24 | conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') |
25 | - select('DISTINCT profiles.*').joins(:role_assignments).where([conditions]) | |
25 | + distinct.select('profiles.*').joins(joins).where([conditions]) | |
26 | 26 | } |
27 | 27 | |
28 | 28 | scope :not_members_of, -> resources { |
29 | 29 | resources = Array(resources) |
30 | 30 | conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') |
31 | - select('DISTINCT profiles.*').where('"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "role_assignments" ON "role_assignments"."accessor_id" = "profiles"."id" AND "role_assignments"."accessor_type" = (Profile) WHERE "profiles"."type" IN (Person) AND (%s))' % conditions) | |
31 | + distinct.select('profiles.*').where('"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "role_assignments" ON "role_assignments"."accessor_id" = "profiles"."id" AND "role_assignments"."accessor_type" = (Profile) WHERE "profiles"."type" IN (Person) AND (%s))' % conditions) | |
32 | 32 | } |
33 | 33 | |
34 | 34 | scope :by_role, -> roles { |
35 | 35 | roles = Array(roles) |
36 | - select('DISTINCT profiles.*').joins(:role_assignments).where('role_assignments.role_id IN (?)', roles) | |
36 | + distinct.select('profiles.*').joins(:role_assignments).where('role_assignments.role_id IN (?)', roles) | |
37 | 37 | } |
38 | 38 | |
39 | 39 | scope :not_friends_of, -> resources { |
40 | 40 | resources = Array(resources) |
41 | - select('DISTINCT profiles.*').where('"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "friendships" ON "friendships"."person_id" = "profiles"."id" WHERE "friendships"."friend_id" IN (%s))' % resources.map(&:id)) | |
41 | + distinct.select('profiles.*').where('"profiles"."id" NOT IN (SELECT DISTINCT profiles.id FROM "profiles" INNER JOIN "friendships" ON "friendships"."person_id" = "profiles"."id" WHERE "friendships"."friend_id" IN (%s))' % resources.map(&:id)) | |
42 | 42 | } |
43 | 43 | |
44 | 44 | scope :visible_for_person, lambda { |person| |
... | ... | @@ -51,8 +51,7 @@ class Person < Profile |
51 | 51 | ['( roles.key = ? AND role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR ( |
52 | 52 | ( ( friendships.person_id = ? ) OR (profiles.public_profile = ?)) AND (profiles.visible = ?) )', 'environment_administrator', Profile.name, person.id, person.id, true, true] |
53 | 53 | ).uniq |
54 | - } | |
55 | - | |
54 | + } | |
56 | 55 | |
57 | 56 | def has_permission_with_admin?(permission, resource) |
58 | 57 | return true if resource.blank? || resource.admins.include?(self) |
... | ... | @@ -90,7 +89,8 @@ class Person < Profile |
90 | 89 | has_many :article_followers, :dependent => :destroy |
91 | 90 | has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article |
92 | 91 | has_many :comments, :foreign_key => :author_id |
93 | - | |
92 | + has_many :article_followers, :dependent => :destroy | |
93 | + has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article | |
94 | 94 | has_many :friendships, :dependent => :destroy |
95 | 95 | has_many :friends, :class_name => 'Person', :through => :friendships |
96 | 96 | |
... | ... | @@ -123,10 +123,10 @@ class Person < Profile |
123 | 123 | scope :more_popular, -> { order 'friends_count DESC' } |
124 | 124 | |
125 | 125 | scope :abusers, -> { |
126 | - joins(:abuse_complaints).where('tasks.status = 3').select('DISTINCT profiles.*') | |
126 | + joins(:abuse_complaints).where('tasks.status = 3').distinct.select('profiles.*') | |
127 | 127 | } |
128 | 128 | scope :non_abusers, -> { |
129 | - select("DISTINCT profiles.*"). | |
129 | + distinct.select("profiles.*"). | |
130 | 130 | joins("LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'"). |
131 | 131 | where("tasks.status != 3 OR tasks.id is NULL") |
132 | 132 | } |
... | ... | @@ -135,6 +135,11 @@ class Person < Profile |
135 | 135 | scope :activated, -> { joins(:user).where('users.activation_code IS NULL AND users.activated_at IS NOT NULL') } |
136 | 136 | scope :deactivated, -> { joins(:user).where('NOT (users.activation_code IS NULL AND users.activated_at IS NOT NULL)') } |
137 | 137 | |
138 | + scope :with_role, -> role_id { | |
139 | + distinct.joins(:role_assignments). | |
140 | + where("role_assignments.role_id = #{role_id}") | |
141 | + } | |
142 | + | |
138 | 143 | after_destroy do |person| |
139 | 144 | Friendship.where(friend_id: person.id).each{ |friendship| friendship.destroy } |
140 | 145 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -78,6 +78,9 @@ class Profile < ActiveRecord::Base |
78 | 78 | def self.organization_member_roles(env_id) |
79 | 79 | all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? || !r.profile_id.nil?} |
80 | 80 | end |
81 | + def self.organization_custom_roles(env_id, profile_id) | |
82 | + all_roles(env_id).where('profile_id = ?', profile_id) | |
83 | + end | |
81 | 84 | def self.all_roles(env_id) |
82 | 85 | Role.where(environment_id: env_id) |
83 | 86 | end |
... | ... | @@ -119,7 +122,7 @@ class Profile < ActiveRecord::Base |
119 | 122 | include Noosfero::Plugin::HotSpot |
120 | 123 | |
121 | 124 | scope :memberships_of, -> person { |
122 | - select('DISTINCT profiles.*'). | |
125 | + distinct.select('profiles.*'). | |
123 | 126 | joins(:role_assignments). |
124 | 127 | where('role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id) |
125 | 128 | } |
... | ... | @@ -185,15 +188,23 @@ class Profile < ActiveRecord::Base |
185 | 188 | |
186 | 189 | include TimeScopes |
187 | 190 | |
188 | - def members | |
191 | + def members(by_field = '') | |
189 | 192 | scopes = plugins.dispatch_scopes(:organization_members, self) |
190 | - scopes << Person.members_of(self) | |
193 | + scopes << Person.members_of(self,by_field) | |
191 | 194 | return scopes.first if scopes.size == 1 |
192 | 195 | ScopeTool.union *scopes |
193 | 196 | end |
194 | 197 | |
195 | - def members_by_name | |
196 | - members.order('profiles.name') | |
198 | + def members_by(field,value = nil) | |
199 | + if value and !value.blank? | |
200 | + members_like(field,value).order('profiles.name') | |
201 | + else | |
202 | + members.order('profiles.name') | |
203 | + end | |
204 | + end | |
205 | + | |
206 | + def members_like(field,value) | |
207 | + members(field).where("LOWER(#{field}) LIKE ?", "%#{value.downcase}%") if value | |
197 | 208 | end |
198 | 209 | |
199 | 210 | class << self |
... | ... | @@ -781,13 +792,13 @@ private :generate_url, :url_options |
781 | 792 | end |
782 | 793 | |
783 | 794 | # Adds a person as member of this Profile. |
784 | - def add_member(person) | |
795 | + def add_member(person, attributes={}) | |
785 | 796 | if self.has_members? |
786 | 797 | if self.closed? && members.count > 0 |
787 | 798 | AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person) |
788 | 799 | else |
789 | - self.affiliate(person, Profile::Roles.admin(environment.id)) if members.count == 0 | |
790 | - self.affiliate(person, Profile::Roles.member(environment.id)) | |
800 | + self.affiliate(person, Profile::Roles.admin(environment.id), attributes) if members.count == 0 | |
801 | + self.affiliate(person, Profile::Roles.member(environment.id), attributes) | |
791 | 802 | end |
792 | 803 | person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } |
793 | 804 | remove_from_suggestion_list person |
... | ... | @@ -1164,6 +1175,10 @@ private :generate_url, :url_options |
1164 | 1175 | end |
1165 | 1176 | end |
1166 | 1177 | |
1178 | + def can_view_field? current_person, field | |
1179 | + display_private_info_to?(current_person) || (public_fields.include?(field) && public?) | |
1180 | + end | |
1181 | + | |
1167 | 1182 | validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true |
1168 | 1183 | def preferred_login_redirection |
1169 | 1184 | redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login | ... | ... |
app/models/raw_html_block.rb
app/models/rss_feed.rb
app/models/uploaded_file.rb
... | ... | @@ -2,6 +2,9 @@ |
2 | 2 | # |
3 | 3 | # Limitation: only file metadata are versioned. Only the latest version |
4 | 4 | # of the file itself is kept. (FIXME?) |
5 | + | |
6 | +require 'sdbm' | |
7 | + | |
5 | 8 | class UploadedFile < Article |
6 | 9 | |
7 | 10 | attr_accessible :uploaded_data, :title |
... | ... | @@ -10,6 +13,19 @@ class UploadedFile < Article |
10 | 13 | _('File') |
11 | 14 | end |
12 | 15 | |
16 | + DBM_PRIVATE_FILE = 'cache/private_files' | |
17 | + after_save do |uploaded_file| | |
18 | + if uploaded_file.published_changed? | |
19 | + dbm = SDBM.open(DBM_PRIVATE_FILE) | |
20 | + if uploaded_file.published | |
21 | + dbm.delete(uploaded_file.public_filename) | |
22 | + else | |
23 | + dbm.store(uploaded_file.public_filename, uploaded_file.full_path) | |
24 | + end | |
25 | + dbm.close | |
26 | + end | |
27 | + end | |
28 | + | |
13 | 29 | track_actions :upload_image, :after_create, :keep_params => ["view_url", "thumbnail_path", "parent.url", "parent.name"], :if => Proc.new { |a| a.published? && a.image? && !a.parent.nil? && a.parent.gallery? }, :custom_target => :parent |
14 | 30 | |
15 | 31 | def title |
... | ... | @@ -106,10 +122,13 @@ class UploadedFile < Article |
106 | 122 | self.name ||= self.filename |
107 | 123 | end |
108 | 124 | |
109 | - def download_headers | |
110 | - { | |
111 | - 'Content-Disposition' => "attachment; filename=\"#{self.filename}\"", | |
112 | - } | |
125 | + def download_disposition | |
126 | + case content_type | |
127 | + when 'application/pdf' | |
128 | + 'inline' | |
129 | + else | |
130 | + 'attachment' | |
131 | + end | |
113 | 132 | end |
114 | 133 | |
115 | 134 | def data | ... | ... |
app/views/account/forgot_password.html.erb
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <%= form_tag({:action => 'forgot_password'}, :method => 'post', :id => 'forgot-password-form') do %> |
6 | 6 | <%= labelled_form_field fields_label, text_field_tag(:value) %> |
7 | 7 | |
8 | - <h3><%= _('Please type the two words below') %></h3> | |
8 | + <h3><%= _('Please type the captcha text below') %></h3> | |
9 | 9 | <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> |
10 | 10 | |
11 | 11 | <div> | ... | ... |
app/views/account/index.html.erb
app/views/blocks/highlights.html.erb
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | <div class='highlights-border'> |
4 | 4 | <div class='highlights-container'> |
5 | 5 | <% block.featured_images.each do |img| %> |
6 | - <a href="<%= img[:address] %>" title="<%= img[:title] %>" class="highlights-image-link"> | |
6 | + <a href="<%= img[:address] %>" <%= 'target="_blank"' if img[:new_window] %> title="<%= img[:title] %>" class="highlights-image-link"> | |
7 | 7 | <%= image_tag [Noosfero.root, img[:image_src]].join, alt: img[:title] %> |
8 | 8 | <p class="highlights-label"><%= img[:title] %></p> |
9 | 9 | </a> | ... | ... |
app/views/box_organizer/_highlights_block.html.erb
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | <strong><%= _('Highlights') %></strong> |
4 | 4 | |
5 | 5 | <table class="noborder"><tbody id="highlights-data-table"> |
6 | - <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th></tr> | |
6 | + <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th><th><%= _('New Window') %></th></tr> | |
7 | 7 | <% @block.images.each_with_index do |image, index| %> |
8 | 8 | <%= highlights_block_config_image_fields @block, image, index %> |
9 | 9 | <% end %> | ... | ... |
app/views/cms/_drag_and_drop_note.html.erb
app/views/cms/_text_editor_sidebar.html.erb
... | ... | @@ -17,8 +17,8 @@ |
17 | 17 | :parent_id, profile, default_folder, {}, {}, |
18 | 18 | "type='Folder' or type='Gallery'" |
19 | 19 | ) %> |
20 | + <%= button(:newfolder, _('New folder'), '#', :id => 'new-folder-button') %> | |
20 | 21 | </div> |
21 | - <%= button(:newfolder, _('New folder'), '#', :id => 'new-folder-button') %> | |
22 | 22 | <p><%= file_field_tag('file', :multiple => true) %></p> |
23 | 23 | <% end %> |
24 | 24 | </div> |
... | ... | @@ -31,7 +31,7 @@ |
31 | 31 | <div id='published-media' class='text-editor-sidebar-box' data-url='<%= url_for({:controller => 'cms', :action => 'published_media_items', :profile => profile.identifier}) %>'> |
32 | 32 | <%= select_profile_folder(nil, :parent_id, profile, 'recent-media', {}, {}, |
33 | 33 | "type='Folder' or type='Gallery'", {:root_label => _('Recent media')}) %> |
34 | - <%= labelled_form_field _('Search'), text_field_tag('q') %> | |
34 | + <%= labelled_form_field _('Search among your uploaded files'), text_field_tag('q', '', placeholder: _('Write words about the file you are looking for')) %> | |
35 | 35 | <%= render :partial => 'drag_and_drop_note' %> |
36 | 36 | <div class='items'> |
37 | 37 | <%= render :partial => 'published_media_items' %> | ... | ... |
app/views/comment/_comment_form.html.erb
... | ... | @@ -77,6 +77,10 @@ function check_captcha(button, confirm_action) { |
77 | 77 | <%= labelled_form_field(_('Title'), f.text_field(:title)) %> |
78 | 78 | <%= required labelled_form_field(_('Enter your comment'), f.text_area(:body, :rows => 5)) %> |
79 | 79 | |
80 | + <% if logged_in? %> | |
81 | + <%= labelled_form_field check_box(:comment, :follow_article, {}, true, false) + _('Follow this article'), '' %> | |
82 | + <% end%> | |
83 | + | |
80 | 84 | <%= hidden_field_tag(:confirm, 'false') %> |
81 | 85 | <%= hidden_field_tag(:view, params[:view])%> |
82 | 86 | <%= f.hidden_field(:reply_of_id) %> | ... | ... |
app/views/content_viewer/_article_toolbar.html.erb
app/views/content_viewer/_publishing_info.html.erb
... | ... | @@ -10,6 +10,24 @@ |
10 | 10 | <%= (" - %s") % link_to_comments(@page)%> |
11 | 11 | </span> |
12 | 12 | <% end %> |
13 | + | |
14 | +<span class="followers-count"> | |
15 | +| | |
16 | +<% if @page.event? %> | |
17 | + <% if @page.person_followers.size > 0 %> | |
18 | + <%= _("%s will attend this event.") % [ pluralize(@page.person_followers.size, _("person"))]%> | |
19 | + <% else %> | |
20 | + <%= _("No one attending this event yet.") %> | |
21 | + <% end %> | |
22 | +<% else %> | |
23 | + <% if @page.person_followers.size > 0 %> | |
24 | + <%= _("%s following this article.") % [ pluralize(@page.person_followers.size, _("person"))]%> | |
25 | + <% else %> | |
26 | + <%= _("No one following this article yet.") %> | |
27 | + <% end %> | |
28 | +<% end %> | |
29 | +</span> | |
30 | + | |
13 | 31 | </span> |
14 | 32 | |
15 | 33 | <% if @page.display_hits? || @page.license.present? %> | ... | ... |
app/views/content_viewer/view_page.html.erb
... | ... | @@ -81,7 +81,7 @@ |
81 | 81 | <ul class="article-comments-list"> |
82 | 82 | <% if @comments.present? %> |
83 | 83 | <%= render :partial => 'comment/comment', :collection => @comments %> |
84 | - <%= pagination_links @comments, :param_name => 'comment_page' %> | |
84 | + <%= pagination_links @comments, :param_name => 'comment_page', :params => { :comment_order => @comment_order } %> | |
85 | 85 | <% end %> |
86 | 86 | </ul> |
87 | 87 | ... | ... |
app/views/file_presenter/_generic.html.erb
... | ... | @@ -2,4 +2,4 @@ |
2 | 2 | <%= generic.abstract %> |
3 | 3 | </div> |
4 | 4 | |
5 | -<%= button(:download, _('Download'), [Noosfero.root, generic.public_filename].join, class:'download-link', option:'primary', size:'lg') %> | |
5 | +<%= button(:download, _('Download'), generic.url, class:'download-link', option:'primary', size:'lg', :target => "_blank") %> | ... | ... |
app/views/profile/_profile_members_list.html.erb
... | ... | @@ -9,7 +9,8 @@ |
9 | 9 | </div> |
10 | 10 | <ul class="profile-list-<%= role %>" > |
11 | 11 | <% users.each do |u| %> |
12 | - <%= profile_image_link(u, :thumb) %> | |
12 | + <% extra_info = u.member_since_date(profile) == Date.today ? {:value =>_('New'), :class => 'new-profile'}:'' %> | |
13 | + <%= profile_image_link(u, :thumb, 'li', extra_info) %> | |
13 | 14 | <% end %> |
14 | 15 | </ul> |
15 | 16 | ... | ... |
app/views/profile/members.html.erb
app/views/profile/send_mail.html.erb
... | ... | @@ -10,6 +10,9 @@ |
10 | 10 | </div> |
11 | 11 | <% end %> |
12 | 12 | |
13 | + <% to = @mailing.data[:members_filtered].present? ? @mailing.recipients.map{|r| r.name}.join(', ') : _('All members')%> | |
14 | + <%= labelled_form_field(_('To:'), text_area(:data, 'members_filtered', :value => to, :rows => 4, :disabled => 'disabled', :class => 'send-mail-recipients')) %> | |
15 | + | |
13 | 16 | <%= form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %> |
14 | 17 | |
15 | 18 | <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %> | ... | ... |
app/views/profile_members/_index_buttons.html.erb
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <%= button :person, _('Invite people to join'), :controller => 'invite', :action => 'invite_friends' %> |
6 | 6 | <% end %> |
7 | 7 | <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %> |
8 | - <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> | |
8 | + <%= submit_button(:send, _('Send e-mail to members')) %> | |
9 | 9 | <% end %> |
10 | 10 | <% @plugins.dispatch(:manage_members_extra_buttons).each do |plugin_button| %> |
11 | 11 | <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %> | ... | ... |
... | ... | @@ -0,0 +1,18 @@ |
1 | +<%= form_tag '#', :method => 'post' do %> | |
2 | + | |
3 | + <%= field_set_tag _('Filter'), :class => 'filter_fields' do %> | |
4 | + <p> | |
5 | + <%= labelled_text_field(_('Name or Email')+': ', "filters[name]", @filters[:name], {:id => 'filter-name-autocomplete',:size => 30}) %> | |
6 | + </p> | |
7 | + | |
8 | + <p><%= _('Roles:') %> </p> | |
9 | + <% @data[:roles].each do |r| %> | |
10 | + <%= labelled_check_box(r.name, 'filters[roles][]', r.id, @filters[:roles].include?(r.id.to_s), :add_hidden => false) %><br/> | |
11 | + <% end %> | |
12 | + <p> | |
13 | + <%= submit_button(:search, _('Search')) %> | |
14 | + </p> | |
15 | + <% end %> | |
16 | +<% end %> | |
17 | + | |
18 | +<%= javascript_include_tag params[:controller] %> | |
0 | 19 | \ No newline at end of file | ... | ... |
app/views/profile_members/_members_list.html.erb
1 | -<% collection = @collection == :profile_admins ? profile.admins : profile.members_by_name %> | |
1 | +<% members = @data ? @data[:members] : profile.members_by('name') %> | |
2 | +<% collection = @collection == :profile_admins ? profile.admins : members %> | |
2 | 3 | <% title = @title ? @title : _('Current members') %> |
3 | 4 | <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %> |
5 | +<%= javascript_include_tag params[:controller] %> | |
4 | 6 | |
5 | 7 | <h3><%= title %></h3> |
6 | 8 | |
7 | 9 | <table> |
10 | + <col width="1"> | |
8 | 11 | <tr> |
12 | + <th><%= check_box_tag 'checkbox-all', 1, false, :onClick => "toggle(this)" %></th> | |
9 | 13 | <th><%= _('Member') %></th> |
10 | 14 | <th><%= _('Actions') %></th> |
11 | 15 | </tr> |
16 | + | |
12 | 17 | <% collection.each do |m| %> |
13 | 18 | <tr title="<%= m.name %>"> |
19 | + <td><%= labelled_check_box('', 'members_filtered[]', m.id.to_s, false, :id => 'checkbox-'+m.identifier) %></td> | |
14 | 20 | <td><%= link_to_profile m.short_name, m.identifier, :title => m.name %> </td> |
15 | 21 | <td> |
16 | 22 | <div class="members-buttons-cell"> |
... | ... | @@ -27,3 +33,8 @@ |
27 | 33 | </tr> |
28 | 34 | <% end %> |
29 | 35 | </table> |
36 | +<% if collection.empty? %> | |
37 | + <p> | |
38 | + <em><%= _('No members found to: %s') % profile.name %></em> | |
39 | + </p> | |
40 | +<% end %> | ... | ... |
app/views/profile_members/index.html.erb
1 | 1 | <h1><%= h profile.short_name(50) %></h1> |
2 | 2 | |
3 | -<%= render :partial => 'index_buttons' %> | |
3 | +<%= render :partial => 'members_filter' %> | |
4 | 4 | |
5 | -<div id="members-list"> | |
6 | - <%= render :partial => 'members_list' %> | |
7 | -</div> | |
5 | +<%= form_tag 'profile_members/send_mail', :method => 'post' do %> | |
6 | + <div id="members-list"> | |
7 | + <%= render :partial => 'members_list' %> | |
8 | + </div> | |
8 | 9 | |
9 | -<%= render :partial => 'index_buttons' %> | |
10 | + <%= render :partial => 'index_buttons' %> | |
11 | + | |
12 | +<% end %> | ... | ... |
app/views/region_validators/region.html.erb
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | <ul> |
6 | 6 | <% for validator in @region.validators %> |
7 | 7 | <li> |
8 | - <%= link_to_homepage validator.name, validator.identifier %> | |
8 | + <%= link_to_homepage validator.name, validator %> | |
9 | 9 | <%= link_to _('Remove validation rights'), { :action => 'remove', :id => @region.id, :validator_id => validator }, :method => 'post' %> |
10 | 10 | </li> |
11 | 11 | <% end %> | ... | ... |
app/views/search/_full_enterprise.html.erb
... | ... | @@ -5,7 +5,7 @@ |
5 | 5 | @order == 'more_recent' ? enterprise.send(@order + '_label') + show_date(enterprise.created_at) : enterprise.send(@order + '_label') %> |
6 | 6 | </div> |
7 | 7 | <div class="search-enterprise-item-column-right"> |
8 | - <%= link_to_homepage(enterprise.name, enterprise.identifier, :class => "search-result-title") %> | |
8 | + <%= link_to_homepage enterprise.name, enterprise, class: "search-result-title" %> | |
9 | 9 | <div class="search-enterprise-description"> |
10 | 10 | <% if enterprise.description %> |
11 | 11 | <% body_stripped = strip_tags(enterprise.description) %> | ... | ... |
app/views/search/_full_product.html.erb
... | ... | @@ -44,7 +44,7 @@ |
44 | 44 | <div class="search-product-item-second-column"> |
45 | 45 | <%= link_to_product product, :class => 'search-result-title' %> |
46 | 46 | <div class="search-product-supplier"> |
47 | - <span class="search-field-label"><%= _('Supplier') %> </span><%= link_to_homepage(product.enterprise.name, product.enterprise.identifier) %> | |
47 | + <span class="search-field-label"><%= _('Supplier') %> </span><%= link_to_homepage product.enterprise.name, product.enterprise %> | |
48 | 48 | </div> |
49 | 49 | <div class="search-product-description"> |
50 | 50 | <% if product.description %> | ... | ... |
app/views/search/_image.html.erb
... | ... | @@ -26,7 +26,7 @@ |
26 | 26 | <% end %> |
27 | 27 | <% elsif image.is_a? Gallery %> |
28 | 28 | <div class="search-gallery-items"> |
29 | - <% r = image.children.order(:updated_at).where('type = ?', 'UploadedFile').last(3) %> | |
29 | + <% r = image.children.latest.images.limit(3) %> | |
30 | 30 | <% if r.length > 0 %> |
31 | 31 | <% r.each_index do |i| img = r[i] %> |
32 | 32 | <%= link_to '', img.view_url, :class => "search-image-pic pic-num#{i+1}", |
... | ... | @@ -47,6 +47,8 @@ |
47 | 47 | <% else %> |
48 | 48 | <div class="search-no-image"><span><%= _('No image') %></span></div> |
49 | 49 | <% end %> |
50 | + <% elsif image.first_image.present? %> | |
51 | + <img src="<%= image.first_image %>" class="automatic-abstract-thumb search-image-pic"> | |
50 | 52 | <% else %> |
51 | 53 | <div class="search-content-type-icon icon-content-<%=image.class.to_s.underscore.dasherize%>"></div> |
52 | 54 | <% end %> | ... | ... |
app/views/user_mailer/activation_code.text.erb
1 | 1 | <%= _('Hi, %{recipient}!') % { :recipient => @recipient } %> |
2 | 2 | |
3 | -<%= word_wrap(_('Welcome to %{environment}! To activate your account, follow the link: %{activation_url}') % { :environment => @environment.name, :activation_url => @url + url_for(:controller => :account, :action => :activate, :activation_code => @activation_code, :redirection => @redirection, :join => @join) }) %> | |
3 | +<%= word_wrap(_('Welcome to %{environment}! To activate your account, follow the link: %{activation_url}') % { :environment => @environment.name, :activation_url => url_for(:controller => :account, :action => :activate, :activation_code => @activation_code, :redirection => @redirection, :join => @join) }) %> | |
4 | 4 | |
5 | 5 | <%= _("Greetings,") %> |
6 | 6 | |
7 | 7 | -- |
8 | 8 | <%= _('%s team.') % @environment.name %> |
9 | -<%= url_for @url %> | |
9 | +<%= @url %> | ... | ... |
db/migrate/20150103134141_add_edit_raw_html_block_to_admin_role.rb
0 → 100644
... | ... | @@ -0,0 +1,17 @@ |
1 | +class AddEditRawHtmlBlockToAdminRole < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + Environment.all.map(&:id).each do |id| | |
4 | + role = Environment::Roles.admin(id) | |
5 | + role.permissions << 'edit_raw_html_block' | |
6 | + role.save! | |
7 | + end | |
8 | + end | |
9 | + | |
10 | + def self.down | |
11 | + Environment.all.map(&:id).each do |id| | |
12 | + role = Environment::Roles.admin(id) | |
13 | + role.permissions -= ['edit_raw_html_block'] | |
14 | + role.save! | |
15 | + end | |
16 | + end | |
17 | +end | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +class CreateArticleFollowers < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + execute("CREATE TABLE article_followers AS (SELECT profiles.id AS person_id, t.id AS article_id, clock_timestamp() AS since FROM (SELECT articles.id, regexp_split_to_table(replace(replace(substring(articles.setting FROM ':followers:[^:]*'), ':followers:', ''), '- ', ''), '\n') AS follower FROM articles) t INNER JOIN users ON users.email = follower INNER JOIN profiles ON users.id = profiles.user_id WHERE follower != '');") | |
4 | + add_timestamps :article_followers | |
5 | + add_index :article_followers, :person_id | |
6 | + add_index :article_followers, :article_id | |
7 | + add_index :article_followers, [:person_id, :article_id], :unique => true | |
8 | + end | |
9 | + | |
10 | + def self.down | |
11 | + drop_table :article_followers | |
12 | + end | |
13 | +end | ... | ... |
db/migrate/20151210230319_add_followers_count_to_article.rb
0 → 100644
... | ... | @@ -0,0 +1,10 @@ |
1 | +class AddFollowersCountToArticle < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + add_column :articles, :followers_count, :integer, :default => 0 | |
4 | + execute "update articles set followers_count = (select count(*) from article_followers where article_followers.article_id = articles.id)" | |
5 | + end | |
6 | + | |
7 | + def self.down | |
8 | + remove_column :articles, :followers_count | |
9 | + end | |
10 | +end | ... | ... |
db/migrate/20160202142247_add_timestamps_to_role_assignments.rb
0 → 100644
db/schema.rb
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | # |
12 | 12 | # It's strongly recommended that you check this file into your version control system. |
13 | 13 | |
14 | -ActiveRecord::Schema.define(version: 20151221105330) do | |
14 | +ActiveRecord::Schema.define(version: 20160224132937) do | |
15 | 15 | |
16 | 16 | # These are extensions that must be enabled in order to support this database |
17 | 17 | enable_extension "plpgsql" |
... | ... | @@ -88,9 +88,9 @@ ActiveRecord::Schema.define(version: 20151221105330) do |
88 | 88 | t.integer "profile_id" |
89 | 89 | end |
90 | 90 | |
91 | - create_table "article_followers", force: :cascade do |t| | |
92 | - t.integer "person_id", null: false | |
93 | - t.integer "article_id", null: false | |
91 | + create_table "article_followers", id: false, force: :cascade do |t| | |
92 | + t.integer "person_id" | |
93 | + t.integer "article_id" | |
94 | 94 | t.datetime "since" |
95 | 95 | t.datetime "created_at" |
96 | 96 | t.datetime "updated_at" |
... | ... | @@ -699,6 +699,7 @@ ActiveRecord::Schema.define(version: 20151221105330) do |
699 | 699 | t.string "locale" |
700 | 700 | t.datetime "created_at" |
701 | 701 | t.datetime "updated_at" |
702 | + t.text "data" | |
702 | 703 | end |
703 | 704 | |
704 | 705 | create_table "mark_comment_as_read_plugin", force: :cascade do |t| |
... | ... | @@ -1071,12 +1072,14 @@ ActiveRecord::Schema.define(version: 20151221105330) do |
1071 | 1072 | end |
1072 | 1073 | |
1073 | 1074 | create_table "role_assignments", force: :cascade do |t| |
1074 | - t.integer "accessor_id", null: false | |
1075 | - t.string "accessor_type" | |
1076 | - t.integer "resource_id" | |
1077 | - t.string "resource_type" | |
1078 | - t.integer "role_id", null: false | |
1079 | - t.boolean "is_global" | |
1075 | + t.integer "accessor_id", null: false | |
1076 | + t.string "accessor_type" | |
1077 | + t.integer "resource_id" | |
1078 | + t.string "resource_type" | |
1079 | + t.integer "role_id", null: false | |
1080 | + t.boolean "is_global" | |
1081 | + t.datetime "created_at" | |
1082 | + t.datetime "updated_at" | |
1080 | 1083 | end |
1081 | 1084 | |
1082 | 1085 | create_table "roles", force: :cascade do |t| | ... | ... |
debian/apache2/virtualhost.conf
... | ... | @@ -8,6 +8,19 @@ DocumentRoot "/usr/share/noosfero/public" |
8 | 8 | |
9 | 9 | RewriteEngine On |
10 | 10 | |
11 | +# If your XMPP XMPP/BOSH isn't in localhost, change the config below to correct | |
12 | +# point to address | |
13 | +RewriteRule /http-bind http://localhost:5280/http-bind [P,QSA,L] | |
14 | +<Proxy http://localhost:5280/http-bind> | |
15 | + Order Allow,Deny | |
16 | + Allow from All | |
17 | +</Proxy> | |
18 | + | |
19 | +# Pass access to private files to backend | |
20 | +RewriteMap private_files "dbm=sdbm:/usr/share/noosfero/cache/private_files" | |
21 | +RewriteCond ${private_files:$1|NOT_FOUND} !NOT_FOUND | |
22 | +RewriteRule ^(/articles/.*) ${private_files:$1} [P,QSA,L] | |
23 | + | |
11 | 24 | # Rewrite index to check for static index.html |
12 | 25 | RewriteRule ^/$ /index.html [QSA] |
13 | 26 | ... | ... |
debian/changelog
debian/dbinstall
... | ... | @@ -5,8 +5,6 @@ set -e |
5 | 5 | # dbconfig-common uses "pgsql", but we want "postgresql" |
6 | 6 | sed -i -e 's/adapter: pgsql/adapter: postgresql/' /etc/noosfero/database.yml |
7 | 7 | |
8 | -/etc/init.d/noosfero setup | |
9 | - | |
10 | 8 | cd /usr/share/noosfero && su noosfero -c "rake db:schema:load RAILS_ENV=production" |
11 | 9 | cd /usr/share/noosfero && su noosfero -c "rake db:migrate RAILS_ENV=production SCHEMA=/dev/null" |
12 | 10 | cd /usr/share/noosfero && su noosfero -c "rake db:data:minimal RAILS_ENV=production" | ... | ... |
debian/dbupgrade
debian/noosfero.links
1 | 1 | var/tmp/noosfero usr/share/noosfero/tmp |
2 | 2 | var/log/noosfero usr/share/noosfero/log |
3 | +var/cache/noosfero usr/share/noosfero/cache | |
3 | 4 | etc/noosfero/database.yml usr/share/noosfero/config/database.yml |
4 | 5 | etc/noosfero/unicorn.rb usr/share/noosfero/config/unicorn.rb |
5 | 6 | etc/noosfero/plugins usr/share/noosfero/config/plugins | ... | ... |
debian/noosfero.postinst
... | ... | @@ -68,10 +68,17 @@ if [ ! -z "$RET" ]; then |
68 | 68 | export NOOSFERO_DOMAIN="$RET" |
69 | 69 | fi |
70 | 70 | |
71 | +/etc/init.d/noosfero setup | |
72 | + | |
71 | 73 | # dbconfig-common magic |
72 | 74 | . /usr/share/dbconfig-common/dpkg/postinst |
73 | 75 | dbc_go noosfero $@ |
74 | 76 | |
77 | +if [ ! -f /usr/share/noosfero/cache/private_files.pag ] && [ $1 = "configure" ] && [ -n $2 ]; then | |
78 | + echo "Creating private files dbm map..." | |
79 | + cd /usr/share/noosfero && su noosfero -c "rake cache:private_files RAILS_ENV=production" | |
80 | +fi | |
81 | + | |
75 | 82 | # stop debconf to avoid the problem with infinite hanging, cfe |
76 | 83 | # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=295477 |
77 | 84 | db_stop | ... | ... |
debian/update-noosfero-apache
... | ... | @@ -17,13 +17,13 @@ if test -x /usr/share/noosfero/script/apacheconf; then |
17 | 17 | if ! test -e "$apache_site"; then |
18 | 18 | echo "Generating apache virtual host ..." |
19 | 19 | cd /usr/share/noosfero && su noosfero -c "RAILS_ENV=production ./script/apacheconf virtualhosts" > "$apache_site" |
20 | - else | |
21 | - pattern="Include \/etc\/noosfero\/apache\/virtualhost.conf" | |
22 | - include="Include \/usr\/share\/noosfero\/util\/chat\/apache\/xmpp.conf" | |
23 | - if ! cat $apache_site | grep "^ *$include" > /dev/null ; then | |
24 | - echo "Updating apache virtual host ..." | |
25 | - sed -i "s/.*$pattern.*/ $include\n&/" $apache_site | |
26 | - fi | |
20 | + fi | |
21 | + | |
22 | + # remove old way to include chat config | |
23 | + pattern="Include \/usr\/share\/noosfero\/util\/chat\/apache\/xmpp.conf" | |
24 | + if cat $apache_site | grep "^ *$pattern" > /dev/null ; then | |
25 | + echo "Removing obsolete chat configuration ..." | |
26 | + sed -i "/.*$pattern.*/d" $apache_site | |
27 | 27 | fi |
28 | 28 | |
29 | 29 | echo 'Noosfero Apache configuration updated.' | ... | ... |
etc/init.d/noosfero
... | ... | @@ -86,6 +86,13 @@ do_setup() { |
86 | 86 | chmod 750 /var/tmp/noosfero |
87 | 87 | fi |
88 | 88 | |
89 | + # Noosfero cache directory | |
90 | + if [ ! -d /var/cache/noosfero ]; then | |
91 | + mkdir /var/cache/noosfero | |
92 | + chown $NOOSFERO_USER:root /var/cache/noosfero | |
93 | + chmod 755 /var/cache/noosfero | |
94 | + fi | |
95 | + | |
89 | 96 | # symlink the directories into Noosfero directory |
90 | 97 | if [ ! -e $NOOSFERO_DIR/tmp ]; then |
91 | 98 | ln -s /var/tmp/noosfero $NOOSFERO_DIR/tmp |
... | ... | @@ -96,6 +103,9 @@ do_setup() { |
96 | 103 | if [ ! -e $NOOSFERO_DIR/log ]; then |
97 | 104 | ln -s /var/log/noosfero $NOOSFERO_DIR/log |
98 | 105 | fi |
106 | + if [ ! -e $NOOSFERO_DIR/cache ]; then | |
107 | + ln -s /var/cache/noosfero $NOOSFERO_DIR/cache | |
108 | + fi | |
99 | 109 | } |
100 | 110 | |
101 | 111 | do_start() { | ... | ... |
features/admin_categories.feature
... | ... | @@ -45,7 +45,7 @@ Feature: manage categories |
45 | 45 | And I should see "Steak" |
46 | 46 | When I follow "Hide" |
47 | 47 | Then I should not see "Vegetarian" |
48 | - And "Steak" should not be visible within "div" | |
48 | + And I should not see "Steak" | |
49 | 49 | |
50 | 50 | @selenium |
51 | 51 | Scenario: the show link is available just for categories with category tree | ... | ... |
features/categories_block.feature
... | ... | @@ -44,6 +44,7 @@ Feature: categories_block |
44 | 44 | And I follow "Edit" within ".block-outer .categories-block" |
45 | 45 | And I check "Product" |
46 | 46 | And I press "Save" |
47 | + And I go to / | |
47 | 48 | Then I should see "Food" |
48 | 49 | And I should see "Book" |
49 | 50 | And "Vegetarian" should not be visible within "span#category-name" |
... | ... | @@ -62,6 +63,7 @@ Feature: categories_block |
62 | 63 | And I follow "Edit" within ".block-outer .categories-block" |
63 | 64 | And I check "Product" |
64 | 65 | And I press "Save" |
66 | + And I go to / | |
65 | 67 | Then I should see "Book" |
66 | 68 | And "Literature" should not be visible within "span#category-name" |
67 | 69 | When I follow "block_2_category_2" | ... | ... |
features/comment.feature
... | ... | @@ -96,4 +96,4 @@ Feature: comment |
96 | 96 | Scenario: hide post a comment button when clicked |
97 | 97 | Given I am on /booking/article-to-comment |
98 | 98 | And I follow "Post a comment" |
99 | - Then "Post a comment" should not be visible within "#article" | |
99 | + Then "Post comment" should not be visible within "#article" | ... | ... |
features/manage_categories.feature
... | ... | @@ -27,5 +27,7 @@ Feature: manage categories |
27 | 27 | Then I should not see "Beans" |
28 | 28 | And I should not see "Potatoes" |
29 | 29 | When I follow "Show" |
30 | + And I wait 0.5 seconds for Services show animation to finish | |
31 | + And I follow "Show" | |
30 | 32 | Then I should see "Beans" |
31 | 33 | And I should see "Potatoes" | ... | ... |
features/manage_users.feature
... | ... | @@ -15,7 +15,7 @@ Background: |
15 | 15 | Scenario: deactive user |
16 | 16 | Given I follow "Deactivate user" within "tr[title='Joao Silva']" |
17 | 17 | When I confirm the browser dialog |
18 | - Then the "tr[title='Joao Silva'] td.actions a.icon-activate-user" button should be enabled | |
18 | + Then the field "tr[title='Joao Silva'] td.actions a.icon-activate-user" should be enabled | |
19 | 19 | |
20 | 20 | @selenium |
21 | 21 | Scenario: activate user |
... | ... | @@ -23,7 +23,7 @@ Background: |
23 | 23 | And I confirm the browser dialog |
24 | 24 | And I follow "Activate user" within "tr[title='Paulo Santos']" |
25 | 25 | When I confirm the browser dialog |
26 | - Then the "tr[title='Paulo Santos'] td.actions a.icon-deactivate-user" button should be enabled | |
26 | + Then the field "tr[title='Paulo Santos'] td.actions a.icon-deactivate-user" should be enabled | |
27 | 27 | |
28 | 28 | @selenium |
29 | 29 | Scenario: remove user |
... | ... | @@ -36,7 +36,7 @@ Background: |
36 | 36 | Scenario: admin user |
37 | 37 | Given I follow "Set admin role" within "tr[title='Joao Silva']" |
38 | 38 | When I confirm the browser dialog |
39 | - Then the "tr[title='Joao Silva'] td.actions a.icon-reset-admin-role" button should be enabled | |
39 | + Then the field "tr[title='Joao Silva'] td.actions a.icon-reset-admin-role" should be enabled | |
40 | 40 | |
41 | 41 | @selenium |
42 | 42 | Scenario: unadmin user |
... | ... | @@ -44,4 +44,4 @@ Background: |
44 | 44 | And I confirm the browser dialog |
45 | 45 | And I follow "Reset admin role" within "tr[title='Paulo Santos']" |
46 | 46 | When I confirm the browser dialog |
47 | - Then the "tr[title='Paulo Santos'] td.actions a.icon-set-admin-role" button should be enabled | |
47 | + Then the field "tr[title='Paulo Santos'] td.actions a.icon-set-admin-role" should be enabled | ... | ... |
features/secret_community.feature
features/send_email_to_organization_members.feature
... | ... | @@ -31,7 +31,8 @@ Feature: send emails to organization members |
31 | 31 | Scenario: Send e-mail to members |
32 | 32 | Given I am logged in as "joaosilva" |
33 | 33 | And I go to Sample Community's members management |
34 | - And I follow "Send e-mail to members" | |
34 | + And I check "checkbox-manoel" | |
35 | + And I press "Send e-mail to members" | |
35 | 36 | And I fill in "Subject" with "Hello, member!" |
36 | 37 | And I fill in "Body" with "We have some news" |
37 | 38 | When I press "Send" |
... | ... | @@ -40,7 +41,8 @@ Feature: send emails to organization members |
40 | 41 | Scenario: Not send e-mail to members if subject is blank |
41 | 42 | Given I am logged in as "joaosilva" |
42 | 43 | And I go to Sample Community's members management |
43 | - And I follow "Send e-mail to members" | |
44 | + And I check "checkbox-manoel" | |
45 | + And I press "Send e-mail to members" | |
44 | 46 | And I fill in "Body" with "We have some news" |
45 | 47 | When I press "Send" |
46 | 48 | Then I should be on /profile/sample-community/send_mail |
... | ... | @@ -48,7 +50,8 @@ Feature: send emails to organization members |
48 | 50 | Scenario: Not send e-mail to members if body is blank |
49 | 51 | Given I am logged in as "joaosilva" |
50 | 52 | And I go to Sample Community's members management |
51 | - And I follow "Send e-mail to members" | |
53 | + And I check "checkbox-manoel" | |
54 | + And I press "Send e-mail to members" | |
52 | 55 | And I fill in "Subject" with "Hello, user!" |
53 | 56 | When I press "Send" |
54 | 57 | Then I should be on /profile/sample-community/send_mail |
... | ... | @@ -56,7 +59,8 @@ Feature: send emails to organization members |
56 | 59 | Scenario: Cancel creation of mailing |
57 | 60 | Given I am logged in as "joaosilva" |
58 | 61 | And I go to Sample Community's members management |
59 | - And I follow "Send e-mail to members" | |
62 | + And I check "checkbox-manoel" | |
63 | + And I press "Send e-mail to members" | |
60 | 64 | When I follow "Cancel e-mail" |
61 | 65 | Then I should be on Sample Community's members management |
62 | 66 | ... | ... |
features/step_definitions/custom_web_steps.rb
1 | 1 | Then /^"([^"]*)" should not be visible within "([^"]*)"$/ do |text, selector| |
2 | - if page.has_content?(text) | |
3 | - page.should have_no_css(selector, :text => text, :visible => false) | |
4 | - end | |
2 | + page.should have_no_css selector, text: text, visible: false | |
5 | 3 | end |
6 | 4 | |
7 | 5 | Then /^"([^"]*)" should be visible within "([^"]*)"$/ do |text, selector| |
8 | - if page.has_content?(text) | |
9 | - page.should have_css(selector, :text => text, :visible => false) | |
10 | - end | |
6 | + page.should have_css selector, text: text, visible: false | |
11 | 7 | end |
12 | 8 | |
13 | 9 | Then /^I should see "([^"]*)" link$/ do |text| |
... | ... | @@ -22,14 +18,14 @@ When /^I should see "([^\"]+)" linking to "([^\"]+)"$/ do |text, href| |
22 | 18 | page.should have_xpath("//a[@href='#{href}']") |
23 | 19 | end |
24 | 20 | |
25 | -Then /^the "([^"]*)" button should be disabled$/ do |selector| | |
26 | - field = find(selector) | |
27 | - field['disabled'].should be_truthy | |
28 | -end | |
21 | +Then /^the field "([^"]*)" should be (enabled|disabled)$/ do |selector, status| | |
22 | + field = page.find(:css, selector) | |
29 | 23 | |
30 | -Then /^the "([^"]*)" button should be enabled$/ do |selector| | |
31 | - field = find(selector) | |
32 | - field['disabled'].should_not be_truthy | |
24 | + if status == 'enabled' | |
25 | + field.disabled?.should_not be_truthy | |
26 | + else | |
27 | + field.disabled?.should be_truthy | |
28 | + end | |
33 | 29 | end |
34 | 30 | |
35 | 31 | When /^I reload and wait for the page$/ do | ... | ... |
features/step_definitions/web_steps.rb
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | |
8 | 8 | require 'uri' |
9 | 9 | require 'cgi' |
10 | -require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths")) | |
10 | +require_relative '../support/paths' | |
11 | 11 | |
12 | 12 | module WithinHelpers |
13 | 13 | def with_scope(locator) |
... | ... | @@ -39,37 +39,15 @@ end |
39 | 39 | |
40 | 40 | When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector| |
41 | 41 | with_scope(selector) do |
42 | - begin | |
43 | - click_link(link, :match => :prefer_exact) | |
44 | - rescue Selenium::WebDriver::Error::UnknownError => selenium_error | |
45 | - if selenium_error.message.start_with? 'Element is not clickable at point' | |
46 | - link = find_link(link) | |
47 | - href = link[:href] | |
48 | - onclick = link[:onClick] | |
49 | - | |
50 | - warn "#{selenium_error.message}\n\n"\ | |
51 | - "Trying to overcome this by:\n" | |
52 | - | |
53 | - onclick_return = true | |
54 | - | |
55 | - unless onclick.nil? | |
56 | - warn "\t* Running onClick JS:\n"\ | |
57 | - "\t\t'#{onclick}'\n" | |
58 | - onclick_return = page.execute_script onclick | |
59 | - end | |
60 | - | |
61 | - if onclick_return | |
62 | - warn "\t* Redirecting you to the link's href:\n"\ | |
63 | - "\t\t'#{href}'\n" | |
64 | - | |
65 | - visit href | |
66 | - end | |
67 | - | |
68 | - warn "\nGood luck and be careful that this may produce hidden links to work on tests!\n" | |
69 | - else | |
70 | - raise selenium_error | |
71 | - end | |
42 | + link = find :link_or_button, link, match: :prefer_exact | |
43 | + # If the link has child elements, then $(link).click() has no effect, | |
44 | + # so find the first child and click on it. | |
45 | + if Capybara.default_driver == :selenium | |
46 | + target = link.all('*').first || link | |
47 | + else | |
48 | + target = link | |
72 | 49 | end |
50 | + target.click | |
73 | 51 | end |
74 | 52 | end |
75 | 53 | ... | ... |
features/support/debug.rb
features/support/env.rb
... | ... | @@ -65,5 +65,13 @@ Before do |
65 | 65 | fixtures_folder = Rails.root.join('test', 'fixtures') |
66 | 66 | fixtures = ['environments', 'roles'] |
67 | 67 | ActiveRecord::Fixtures.create_fixtures(fixtures_folder, fixtures) |
68 | + | |
69 | + # The same browser session is used across tests, so expire caching | |
70 | + # can create changes from scenario to another. | |
71 | + e=Environment.default | |
72 | + e.home_cache_in_minutes = 0 | |
73 | + e.general_cache_in_minutes = 0 | |
74 | + e.profile_cache_in_minutes = 0 | |
75 | + e.save | |
68 | 76 | end |
69 | 77 | ... | ... |
gitignore.example
lib/file_presenter.rb
lib/noosfero/api/v1/articles.rb
... | ... | @@ -165,6 +165,37 @@ module Noosfero |
165 | 165 | end |
166 | 166 | end |
167 | 167 | |
168 | + desc "Returns the total followers for the article" do | |
169 | + detail 'Get the followers of a specific article by id' | |
170 | + failure [[403, 'Forbidden']] | |
171 | + named 'ArticleFollowers' | |
172 | + end | |
173 | + get ':id/followers' do | |
174 | + article = find_article(environment.articles, params[:id]) | |
175 | + total = article.person_followers.count | |
176 | + {:total_followers => total} | |
177 | + end | |
178 | + | |
179 | + desc "Add a follower for the article" do | |
180 | + detail 'Add the current user identified by private token, like a follower of a article' | |
181 | + params Noosfero::API::Entities::UserLogin.documentation | |
182 | + failure [[401, 'Unauthorized']] | |
183 | + named 'ArticleFollow' | |
184 | + end | |
185 | + post ':id/follow' do | |
186 | + authenticate! | |
187 | + article = find_article(environment.articles, params[:id]) | |
188 | + if article.article_followers.exists?(:person_id => current_person.id) | |
189 | + {:success => false, :already_follow => true} | |
190 | + else | |
191 | + article_follower = ArticleFollower.new | |
192 | + article_follower.article = article | |
193 | + article_follower.person = current_person | |
194 | + article_follower.save! | |
195 | + {:success => true} | |
196 | + end | |
197 | + end | |
198 | + | |
168 | 199 | desc 'Return the children of a article identified by id' do |
169 | 200 | detail 'Get all children articles of a specific article' |
170 | 201 | params Noosfero::API::Entities::Article.documentation | ... | ... |
lib/noosfero/version.rb
lib/noosfero/vote_ext.rb
... | ... | @@ -2,10 +2,10 @@ require_dependency 'models/vote' |
2 | 2 | |
3 | 3 | class Vote |
4 | 4 | |
5 | - validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id], :if => :allow_duplicated_vote? | |
5 | + validates_uniqueness_of :voteable_id, :scope => [:voteable_type, :voter_type, :voter_id], :unless => :allow_duplicate? | |
6 | 6 | |
7 | - def allow_duplicated_vote? | |
8 | - voter.present? | |
7 | + def allow_duplicate? | |
8 | + voter.blank? | |
9 | 9 | end |
10 | 10 | |
11 | 11 | validate :verify_target_archived | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +namespace :cache do | |
2 | + task :private_files => :environment do | |
3 | + require 'sdbm' | |
4 | + | |
5 | + hash = {} | |
6 | + UploadedFile.where(:published => false).find_each do |uploaded_file| | |
7 | + hash[uploaded_file.public_filename] = uploaded_file.full_path | |
8 | + end | |
9 | + | |
10 | + dbm = SDBM.open(UploadedFile::DBM_PRIVATE_FILE) | |
11 | + dbm.update(hash) | |
12 | + dbm.close | |
13 | + end | |
14 | +end | ... | ... |
plugins/oauth_client/lib/ext/profile.rb
1 | 1 | require_dependency 'profile' |
2 | 2 | |
3 | -Profile.descendants.each do |subclass| | |
4 | - subclass.class_eval do | |
3 | +class Profile | |
5 | 4 | |
6 | - has_many :oauth_auths, foreign_key: :profile_id, class_name: 'OauthClientPlugin::Auth', dependent: :destroy | |
7 | - has_many :oauth_providers, through: :oauth_auths, source: :provider | |
5 | + has_many :oauth_auths, foreign_key: :profile_id, class_name: 'OauthClientPlugin::Auth', dependent: :destroy | |
6 | + has_many :oauth_providers, through: :oauth_auths, source: :provider | |
8 | 7 | |
9 | - end | |
10 | 8 | end | ... | ... |
plugins/organization_ratings/features/rate_community.feature
... | ... | @@ -33,4 +33,4 @@ Feature: rate_community |
33 | 33 | Given I am on mycommunity's homepage |
34 | 34 | When I follow "Rate this Community" |
35 | 35 | Then I should see "Joao Silva" within ".star-profile-name" |
36 | - And I should see Joao Silva's profile image | |
37 | 36 | \ No newline at end of file |
37 | + And I should see Joao Silva's profile image | ... | ... |
plugins/organization_ratings/features/vote_once_disable_cooldown.feature
0 → 100644
... | ... | @@ -0,0 +1,23 @@ |
1 | +Feature: vote_once_disable_cooldown | |
2 | + As a admin | |
3 | + I want to disable the cooldown time when vote once is enabled | |
4 | + Making it clearly that there is no cooldown when vote once is enabled | |
5 | + | |
6 | + Background: | |
7 | + Given plugin "OrganizationRatings" is enabled on environment | |
8 | + And I am logged in as admin | |
9 | + And I go to /admin/plugins | |
10 | + And I check "Organization Ratings" | |
11 | + And I press "Save changes" | |
12 | + | |
13 | + @selenium | |
14 | + Scenario: disable or enable the cooldown field when vote on is checked or unchecked | |
15 | + Given I follow "Administration" | |
16 | + And I follow "Plugins" | |
17 | + And I follow "Configuration" | |
18 | + And the field "#organization_ratings_config_cooldown" should be enabled | |
19 | + And I check "Vote once" | |
20 | + And the field "#organization_ratings_config_cooldown" should be disabled | |
21 | + And I uncheck "Vote once" | |
22 | + Then the field "#organization_ratings_config_cooldown" should be enabled | |
23 | + | ... | ... |
plugins/organization_ratings/lib/organization_ratings_plugin.rb
plugins/organization_ratings/public/organization_rating_management.js
... | ... | @@ -9,8 +9,8 @@ |
9 | 9 | |
10 | 10 | |
11 | 11 | cacheDom: function() { |
12 | - this.$vote_once_checkbox = $("#environment_organization_ratings_vote_once"); | |
13 | - this.$hours_timer_input = $("#environment_organization_ratings_cooldown"); | |
12 | + this.$vote_once_checkbox = $("#organization_ratings_config_vote_once"); | |
13 | + this.$hours_timer_input = $("#organization_ratings_config_cooldown"); | |
14 | 14 | }, |
15 | 15 | |
16 | 16 | |
... | ... | @@ -21,10 +21,22 @@ |
21 | 21 | |
22 | 22 | verifyHoursTimerDisable: function() { |
23 | 23 | if (this.$vote_once_checkbox.is(":checked")) { |
24 | - this.$hours_timer_input.attr("disabled", "disabled"); | |
24 | + //this.$hours_timer_input.attr("disabled", "disabled"); | |
25 | + this.disableVoteOnce(); | |
25 | 26 | } else { |
26 | - this.$hours_timer_input.removeAttr("disabled"); | |
27 | + //this.$hours_timer_input.removeAttr("disabled"); | |
28 | + this.enableVoteOnce(); | |
27 | 29 | } |
30 | + }, | |
31 | + | |
32 | + | |
33 | + enableVoteOnce: function() { | |
34 | + this.$hours_timer_input.removeAttr("disabled"); | |
35 | + }, | |
36 | + | |
37 | + | |
38 | + disableVoteOnce: function() { | |
39 | + this.$hours_timer_input.attr("disabled", "disabled"); | |
28 | 40 | } |
29 | 41 | } |
30 | 42 | ... | ... |
plugins/organization_ratings/public/style.css
... | ... | @@ -14,11 +14,11 @@ |
14 | 14 | } |
15 | 15 | |
16 | 16 | .star-negative { |
17 | - background-image: url('public/images/star-negative.png'); | |
17 | + background-image: url('images/star-negative.png'); | |
18 | 18 | } |
19 | 19 | |
20 | 20 | .star-positive { |
21 | - background-image: url('public/images/star-positive.png'); | |
21 | + background-image: url('images/star-positive.png'); | |
22 | 22 | } |
23 | 23 | |
24 | 24 | .small-star-negative, .small-star-positive { |
... | ... | @@ -31,11 +31,11 @@ |
31 | 31 | } |
32 | 32 | |
33 | 33 | .small-star-negative { |
34 | - background-image: url('public/images/small-star-negative.png'); | |
34 | + background-image: url('images/small-star-negative.png'); | |
35 | 35 | } |
36 | 36 | |
37 | 37 | .small-star-positive { |
38 | - background-image: url('public/images/small-star-positive.png'); | |
38 | + background-image: url('images/small-star-positive.png'); | |
39 | 39 | } |
40 | 40 | |
41 | 41 | .medium-star-negative, .medium-star-positive { |
... | ... | @@ -48,11 +48,11 @@ |
48 | 48 | } |
49 | 49 | |
50 | 50 | .medium-star-positive { |
51 | - background-image: url('public/images/star-positive-medium.png'); | |
51 | + background-image: url('images/star-positive-medium.png'); | |
52 | 52 | } |
53 | 53 | |
54 | 54 | .medium-star-negative { |
55 | - background-image: url('public/images/star-negative-medium.png'); | |
55 | + background-image: url('images/star-negative-medium.png'); | |
56 | 56 | } |
57 | 57 | |
58 | 58 | .star-hide { | ... | ... |
plugins/people_block/lib/ext/person.rb
plugins/people_block/test/unit/members_block_test.rb
... | ... | @@ -280,6 +280,21 @@ class MembersBlockTest < ActionView::TestCase |
280 | 280 | assert_includes block.roles, Profile::Roles.moderator(owner.environment.id) |
281 | 281 | end |
282 | 282 | |
283 | + should 'count number of profiles by role' do | |
284 | + owner = fast_create(Community) | |
285 | + profile1 = fast_create(Person, {:public_profile => true}) | |
286 | + profile2 = fast_create(Person, {:public_profile => true}) | |
287 | + | |
288 | + owner.add_member profile2 | |
289 | + owner.add_moderator profile1 | |
290 | + | |
291 | + block = MembersBlock.new | |
292 | + block.visible_role = Profile::Roles.moderator(owner.environment.id).key | |
293 | + block.expects(:owner).returns(owner).at_least_once | |
294 | + | |
295 | + assert_equivalent [profile1], block.profile_list | |
296 | + end | |
297 | + | |
283 | 298 | protected |
284 | 299 | include NoosferoTestHelper |
285 | 300 | ... | ... |
plugins/pg_search/test/unit/pg_search_plugin_test.rb
... | ... | @@ -25,7 +25,8 @@ class PgSearchPluginTest < ActiveSupport::TestCase |
25 | 25 | profile1 = fast_create(Profile, :identifier => 'profile1', :name => 'debugger') |
26 | 26 | profile2 = fast_create(Profile, :identifier => 'profile2', :name => 'profile admin debugger') |
27 | 27 | profile3 = fast_create(Profile, :identifier => 'profile3', :name => 'admin debugger') |
28 | - assert_equal [profile2, profile3, profile1], search(Profile, 'profile admin deb') | |
28 | + profile4 = fast_create(Profile, :identifier => 'profile4', :name => 'simple user') | |
29 | + assert_equal [profile2, profile3, profile1, profile4], search(Profile, 'profile admin deb') | |
29 | 30 | end |
30 | 31 | |
31 | 32 | should 'locate profile escaping special characters' do | ... | ... |
plugins/site_tour/lib/ext/person.rb
plugins/stoa/test/functional/account_controller_test.rb
plugins/sub_organizations/views/sub_organizations_plugin_profile/_full_related_organizations.html.erb
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 | <%= profile_image_link organization, :big, 'div' %> |
11 | 11 | </div> |
12 | 12 | <div class="related-organizations-item-column-right"> |
13 | - <%= link_to_homepage(organization.name, organization.identifier, :class => "search-result-title") %> | |
13 | + <%= link_to_homepage(organization.name, organization, :class => "search-result-title") %> | |
14 | 14 | <div class="related-organizations-description"> |
15 | 15 | <% if organization.description %> |
16 | 16 | <% body_stripped = strip_tags(organization.description) %> | ... | ... |
plugins/video/lib/video_plugin.rb
... | ... | @@ -33,10 +33,14 @@ class VideoPlugin < Noosfero::Plugin |
33 | 33 | end |
34 | 34 | |
35 | 35 | def article_extra_toolbar_buttons(content) |
36 | - if content.kind_of?(VideoPlugin::VideoGallery) | |
37 | - url = url_for(:action => 'new', :type=>'VideoPlugin::Video', :controller=>'cms', :parent_id => content.id) | |
38 | - {:title => _('New Video'), :url => url, :icon => 'button with-text icon-new'} | |
39 | - end | |
36 | + return [] if !content.kind_of?(VideoPlugin::VideoGallery) | |
37 | + { | |
38 | + :id=>"new-video-btn", | |
39 | + :class=>"button with-text icon-new", | |
40 | + :url=> {:action => 'new', :type=>'VideoPlugin::Video', :controller=>'cms', :parent_id => content.id}, | |
41 | + :title=>_("New Video"), | |
42 | + :icon => :new | |
43 | + } | |
40 | 44 | end |
41 | 45 | |
42 | 46 | end | ... | ... |
plugins/video/views/content_viewer/video_plugin/_video_gallery.html.erb
public/designs/themes/noosfero/style.css
public/javascripts/comment_order.js
... | ... | @@ -10,10 +10,9 @@ function send_order(order, url) { |
10 | 10 | }); |
11 | 11 | } |
12 | 12 | |
13 | - | |
14 | 13 | jQuery(document).ready(function(){ |
15 | 14 | jQuery("#comment_order").change(function(){ |
16 | - var url = jQuery("#page_url").val(); | |
15 | + var url = window.location.href; | |
17 | 16 | send_order(this.value, url); |
18 | 17 | }); |
19 | -}); | |
20 | 18 | \ No newline at end of file |
19 | +}); | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +(function($) { | |
2 | + | |
3 | + //Autocomplete to list members | |
4 | + $('#filter-name-autocomplete').autocomplete({ | |
5 | + minLength:2, | |
6 | + source:function(request,response){ | |
7 | + $.ajax({ | |
8 | + url:document.location.pathname+'/search_members', | |
9 | + dataType:'json', | |
10 | + data:{ | |
11 | + filter_name:request.term | |
12 | + }, | |
13 | + success:response | |
14 | + }); | |
15 | + } | |
16 | + }); | |
17 | +})(jQuery); | |
18 | + | |
19 | + | |
20 | +function toggle(source) { | |
21 | + checkboxes = document.getElementsByName('members_filtered[]'); | |
22 | + for(var i=0, n=checkboxes.length;i<n;i++) { | |
23 | + checkboxes[i].checked = source.checked; | |
24 | + } | |
25 | +} | ... | ... |
public/stylesheets/profile-list.scss
... | ... | @@ -207,3 +207,23 @@ |
207 | 207 | height: auto; |
208 | 208 | font-size: 12px; |
209 | 209 | } |
210 | +.action-profile-members .profile_link{ | |
211 | + position: relative; | |
212 | +} | |
213 | +.action-profile-members .profile_link span.new-profile:last-child{ | |
214 | + position: absolute; | |
215 | + top: 3px; | |
216 | + right: 2px; | |
217 | + text-transform: uppercase; | |
218 | + color: #FFF; | |
219 | + font-size: 9px; | |
220 | + background: #66CC33; | |
221 | + padding: 2px; | |
222 | + display: block; | |
223 | + width: 35px; | |
224 | + font-weight: 700; | |
225 | +} | |
226 | +.action-profile-members .profile_link .fn{ | |
227 | + font-style: normal; | |
228 | + color: #000; | |
229 | +} | ... | ... |
script/apacheconf
... | ... | @@ -17,7 +17,6 @@ when 'virtualhosts' |
17 | 17 | puts " #{server_directive} #{domain.name}" |
18 | 18 | server_directive = 'ServerAlias' |
19 | 19 | end |
20 | - puts " Include /usr/share/noosfero/util/chat/apache/xmpp.conf" | |
21 | 20 | puts " Include /etc/noosfero/apache/virtualhost.conf" |
22 | 21 | puts "</VirtualHost>" |
23 | 22 | end | ... | ... |
script/development
... | ... | @@ -23,7 +23,7 @@ start() { |
23 | 23 | trap stop INT TERM EXIT |
24 | 24 | whenever --write-crontab --set 'environment=development' |
25 | 25 | mkdir -p log |
26 | - touch log/development.log | |
26 | + touch log/development.log log/development_api.log | |
27 | 27 | if [ -z "$RAILS_RELATIVE_URL_ROOT" ]; then |
28 | 28 | unicorn_rails --config-file lib/noosfero/unicorn.rb --daemonize $@ |
29 | 29 | else |
... | ... | @@ -32,7 +32,7 @@ start() { |
32 | 32 | --config-file lib/noosfero/unicorn.rb \ |
33 | 33 | --daemonize |
34 | 34 | fi |
35 | - tail -n 0 -f log/development.log || true | |
35 | + tail -n 0 -f log/development.log log/development_api.log || true | |
36 | 36 | } |
37 | 37 | |
38 | 38 | start $@ | ... | ... |
script/quick-start
test/fixtures/roles.yml
test/functional/cms_controller_test.rb
... | ... | @@ -1647,6 +1647,50 @@ class CmsControllerTest < ActionController::TestCase |
1647 | 1647 | assert_tag :tag => 'input', :attributes => {:name => 'article[accept_comments]', :value => 1, :type => 'checkbox'} |
1648 | 1648 | end |
1649 | 1649 | |
1650 | + should 'logged in user NOT be able to create topic on forum when topic creation is set to Me' do | |
1651 | + u = create_user('linux') | |
1652 | + login_as :linux | |
1653 | + profile.articles << f = Forum.new(:name => 'Forum for test', | |
1654 | + :topic_creation => 'self', | |
1655 | + :body => 'Forum Body') | |
1656 | + | |
1657 | + post :new, :profile => profile.identifier, :type => 'TinyMceArticle', | |
1658 | + :article => {:name => 'New Topic by linux', :body => 'Article Body', | |
1659 | + :parent_id => f.id} | |
1660 | + | |
1661 | + assert_template :access_denied | |
1662 | + assert_not_equal 'New Topic by linux', Article.last.name | |
1663 | + end | |
1664 | + | |
1665 | + should 'logged in user NOT be able to create topic on forum when topic creation is set to Friends/Members' do | |
1666 | + u = create_user('linux') | |
1667 | + login_as :linux | |
1668 | + profile.articles << f = Forum.new(:name => 'Forum for test', | |
1669 | + :topic_creation => 'related', | |
1670 | + :body => 'Forum Body') | |
1671 | + | |
1672 | + post :new, :profile => profile.identifier, :type => 'TinyMceArticle', | |
1673 | + :article => {:name => 'New Topic by linux', :body => 'Article Body', | |
1674 | + :parent_id => f.id} | |
1675 | + | |
1676 | + assert_template :access_denied | |
1677 | + assert_not_equal 'New Topic by linux', Article.last.name | |
1678 | + end | |
1679 | + | |
1680 | + should 'logged in user be able to create topic on forum when topic creation is set to Logged in users' do | |
1681 | + u = create_user('linux') | |
1682 | + login_as :linux | |
1683 | + profile.articles << f = Forum.new(:name => 'Forum for test', | |
1684 | + :topic_creation => 'users', | |
1685 | + :body => 'Forum Body') | |
1686 | + | |
1687 | + post :new, :profile => profile.identifier, :type => 'TinyMceArticle', | |
1688 | + :article => {:name => 'New Topic by linux', :body => 'Article Body', | |
1689 | + :parent_id => f.id} | |
1690 | + | |
1691 | + assert_equal 'New Topic by linux', Article.last.name | |
1692 | + end | |
1693 | + | |
1650 | 1694 | should 'display accept comments option when editing forum post with a different label' do |
1651 | 1695 | profile.articles << f = Forum.new(:name => 'Forum for test') |
1652 | 1696 | profile.articles << a = TinyMceArticle.new(:name => 'Forum post for test', :parent => f) | ... | ... |
test/functional/comment_controller_test.rb
... | ... | @@ -387,10 +387,26 @@ class CommentControllerTest < ActionController::TestCase |
387 | 387 | Article.record_timestamps = true |
388 | 388 | |
389 | 389 | login_as @profile.identifier |
390 | - xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => { :title => 'crap!', :body => 'I think that this article is crap' }, :confirm => 'true' | |
390 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:title => 'crap!', :body => 'I think that this article is crap' }, :confirm => 'true' | |
391 | 391 | assert_not_equal yesterday, page.reload.updated_at |
392 | 392 | end |
393 | 393 | |
394 | + should 'follow article when commenting' do | |
395 | + page = create(Article, :profile => profile, :name => 'myarticle', :body => 'the body of the text') | |
396 | + login_as @profile.identifier | |
397 | + | |
398 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:title => 'crap!', :body => 'I think that this article is crap', :follow_article => true}, :confirm => 'true' | |
399 | + assert_includes page.person_followers, @profile | |
400 | + end | |
401 | + | |
402 | + should 'not follow article when commenting' do | |
403 | + page = create(Article, :profile => profile, :name => 'myarticle', :body => 'the body of the text') | |
404 | + login_as @profile.identifier | |
405 | + | |
406 | + xhr :post, :create, :profile => profile.identifier, :id => page.id, :comment => {:title => 'crap!', :body => 'I think that this article is crap', :follow_article => false }, :confirm => 'true' | |
407 | + assert_not_includes page.person_followers, @profile | |
408 | + end | |
409 | + | |
394 | 410 | should 'be able to mark comments as spam' do |
395 | 411 | login_as profile.identifier |
396 | 412 | article = fast_create(Article, :profile_id => profile.id) | ... | ... |
test/functional/content_viewer_controller_test.rb
... | ... | @@ -51,27 +51,26 @@ class ContentViewerControllerTest < ActionController::TestCase |
51 | 51 | assert_response :missing |
52 | 52 | end |
53 | 53 | |
54 | - should 'produce a download-link when article is a uploaded file' do | |
54 | + should 'produce a download-link when view page is true' do | |
55 | 55 | profile = create_user('someone').person |
56 | 56 | html = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/500.html', 'text/html'), :profile => profile |
57 | 57 | html.save! |
58 | 58 | |
59 | - get :view_page, :profile => 'someone', :page => [ '500.html' ] | |
59 | + get :view_page, :profile => 'someone', :page => [ '500.html' ], :view => true | |
60 | 60 | |
61 | 61 | assert_response :success |
62 | - assert_match /#{html.public_filename}/, @response.body | |
62 | + assert_select "a[href=#{html.full_path}]" | |
63 | 63 | end |
64 | 64 | |
65 | - should 'download file when article is image' do | |
65 | + should 'download file when view page is blank' do | |
66 | 66 | profile = create_user('someone').person |
67 | 67 | image = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile |
68 | 68 | image.save! |
69 | 69 | |
70 | 70 | get :view_page, :profile => 'someone', :page => [ 'rails.png' ] |
71 | 71 | |
72 | - assert_response :success | |
73 | - assert_not_nil assigns(:page).data | |
74 | - assert_match /image\/png/, @response.headers['Content-Type'] | |
72 | + assert_response :redirect | |
73 | + assert_redirected_to image.public_filename | |
75 | 74 | end |
76 | 75 | |
77 | 76 | should 'display image on a page when article is image and has a view param' do |
... | ... | @@ -342,6 +341,27 @@ class ContentViewerControllerTest < ActionController::TestCase |
342 | 341 | assert_tag :content => /list my comment/ |
343 | 342 | end |
344 | 343 | |
344 | + should 'order comments according to comments ordering option' do | |
345 | + article = fast_create(Article, :profile_id => profile.id) | |
346 | + for n in 1..24 | |
347 | + article.comments.create!(:author => profile, :title => "some title #{n}", :body => "some body #{n}") | |
348 | + end | |
349 | + | |
350 | + get 'view_page', :profile => profile.identifier, :page => article.path.split('/') | |
351 | + | |
352 | + for i in 1..12 | |
353 | + assert_tag :tag => 'div', :attributes => { :class => 'comment-details' }, :descendant => { :tag => 'h4', :content => "some title #{i}" } | |
354 | + assert_no_tag :tag => 'div', :attributes => { :class => 'comment-details' }, :descendant => { :tag => 'h4', :content => "some title #{i + 12}" } | |
355 | + end | |
356 | + | |
357 | + xhr :get, :view_page, :profile => profile.identifier, :page => article.path.split('/'), :comment_page => 1, :comment_order => 'newest' | |
358 | + | |
359 | + for i in 1..12 | |
360 | + assert_no_tag :tag => 'div', :attributes => { :class => 'comment-details' }, :descendant => { :tag => 'h4', :content => "some title #{i}" } | |
361 | + assert_tag :tag => 'div', :attributes => { :class => 'comment-details' }, :descendant => { :tag => 'h4', :content => "some title #{i + 12}" } | |
362 | + end | |
363 | + end | |
364 | + | |
345 | 365 | should 'redirect to new article path under an old path' do |
346 | 366 | p = create_user('test_user').person |
347 | 367 | a = p.articles.create(:name => 'old-name') |
... | ... | @@ -1291,18 +1311,6 @@ class ContentViewerControllerTest < ActionController::TestCase |
1291 | 1311 | assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => 'This button is expired.', :class => 'button with-text icon-edit disabled' } } |
1292 | 1312 | end |
1293 | 1313 | |
1294 | - should 'remove email from article followers when unfollow' do | |
1295 | - profile = create_user('testuser').person | |
1296 | - follower_email = 'john@doe.br' | |
1297 | - article = profile.articles.create(:name => 'test') | |
1298 | - article.followers = [follower_email] | |
1299 | - article.save | |
1300 | - | |
1301 | - assert_includes Article.find(article.id).followers, follower_email | |
1302 | - post :view_page, :profile => profile.identifier, :page => [article.name], :unfollow => 'commit', :email => follower_email | |
1303 | - assert_not_includes Article.find(article.id).followers, follower_email | |
1304 | - end | |
1305 | - | |
1306 | 1314 | should 'not display comments marked as spam' do |
1307 | 1315 | article = fast_create(Article, :profile_id => profile.id) |
1308 | 1316 | ham = fast_create(Comment, :source_id => article.id, :source_type => 'Article', :title => 'some content') |
... | ... | @@ -1377,7 +1385,7 @@ class ContentViewerControllerTest < ActionController::TestCase |
1377 | 1385 | assert_equal 15, article.comments.count |
1378 | 1386 | |
1379 | 1387 | get 'view_page', :profile => profile.identifier, :page => article.path.split('/') |
1380 | - assert_tag :tag => 'a', :attributes => { :href => "/#{profile.identifier}/#{article.path}?comment_page=2", :rel => 'next' } | |
1388 | + assert_tag :tag => 'a', :attributes => { :href => "/#{profile.identifier}/#{article.path}?comment_order=oldest&comment_page=2", :rel => 'next' } | |
1381 | 1389 | end |
1382 | 1390 | |
1383 | 1391 | should 'not escape acceptable HTML in list of blog posts' do | ... | ... |
test/functional/profile_controller_test.rb
... | ... | @@ -18,6 +18,19 @@ class ProfileControllerTest < ActionController::TestCase |
18 | 18 | assert assigns(:friends) |
19 | 19 | end |
20 | 20 | |
21 | + should 'remove person from article followers when unfollow' do | |
22 | + profile = create_user('testuser').person | |
23 | + follower = create_user('follower').person | |
24 | + article = profile.articles.create(:name => 'test') | |
25 | + article.person_followers = [follower] | |
26 | + article.save | |
27 | + login_as('follower') | |
28 | + article.reload | |
29 | + assert_includes Article.find(article.id).person_followers, follower | |
30 | + post :unfollow_article, :article_id => article.id | |
31 | + assert_not_includes Article.find(article.id).person_followers, follower | |
32 | + end | |
33 | + | |
21 | 34 | should 'point to manage friends in user is seeing his own friends' do |
22 | 35 | login_as('testuser') |
23 | 36 | get :friends |
... | ... | @@ -1338,6 +1351,24 @@ class ProfileControllerTest < ActionController::TestCase |
1338 | 1351 | assert_equivalent [scrap,activity], assigns(:activities).map(&:activity) |
1339 | 1352 | end |
1340 | 1353 | |
1354 | + should "follow an article" do | |
1355 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') | |
1356 | + login_as(@profile.identifier) | |
1357 | + post :follow_article, :profile => profile.identifier, :article_id => article.id | |
1358 | + assert_includes article.person_followers, @profile | |
1359 | + end | |
1360 | + | |
1361 | + should "unfollow an article" do | |
1362 | + article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') | |
1363 | + article.person_followers << @profile | |
1364 | + article.save! | |
1365 | + assert_includes article.person_followers, @profile | |
1366 | + | |
1367 | + login_as(@profile.identifier) | |
1368 | + post :unfollow_article, :profile => profile.identifier, :article_id => article.id | |
1369 | + assert_not_includes article.person_followers, @profile | |
1370 | + end | |
1371 | + | |
1341 | 1372 | should "be logged in to leave comment on an activity" do |
1342 | 1373 | article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') |
1343 | 1374 | activity = ActionTracker::Record.last |
... | ... | @@ -1434,11 +1465,41 @@ class ProfileControllerTest < ActionController::TestCase |
1434 | 1465 | create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) |
1435 | 1466 | login_as('profile_moderator_user') |
1436 | 1467 | @controller.stubs(:locale).returns('pt') |
1468 | + | |
1437 | 1469 | assert_difference 'Delayed::Job.count', 1 do |
1438 | 1470 | post :send_mail, :profile => community.identifier, :mailing => {:subject => 'Hello', :body => 'We have some news'} |
1439 | 1471 | end |
1440 | 1472 | end |
1441 | 1473 | |
1474 | + should 'send to members_filtered if available' do | |
1475 | + community = fast_create(Community) | |
1476 | + create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) | |
1477 | + person = create_user('Any').person | |
1478 | + community.add_member(person) | |
1479 | + community.save! | |
1480 | + login_as('profile_moderator_user') | |
1481 | + | |
1482 | + post :send_mail, :profile => community.identifier, :mailing => {:subject => 'Hello', :body => 'We have some news'} | |
1483 | + assert_equivalent community.members, OrganizationMailing.last.recipients | |
1484 | + | |
1485 | + @request.session[:members_filtered] = [person.id] | |
1486 | + post :send_mail, :profile => community.identifier, :mailing => {:subject => 'RUN!!', :body => 'Run to the hills!!'} | |
1487 | + assert_equal [person], OrganizationMailing.last.recipients | |
1488 | + end | |
1489 | + | |
1490 | + should 'send email to all members if there is no valid member in members_filtered' do | |
1491 | + community = fast_create(Community) | |
1492 | + create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) | |
1493 | + person = create_user('Any').person | |
1494 | + community.add_member(person) | |
1495 | + community.save! | |
1496 | + login_as('profile_moderator_user') | |
1497 | + | |
1498 | + @request.session[:members_filtered] = [Profile.last.id+1] | |
1499 | + post :send_mail, :profile => community.identifier, :mailing => {:subject => 'RUN!!', :body => 'Run to the hills!!'} | |
1500 | + assert_empty OrganizationMailing.last.recipients | |
1501 | + end | |
1502 | + | |
1442 | 1503 | should 'save mailing' do |
1443 | 1504 | community = fast_create(Community) |
1444 | 1505 | create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) | ... | ... |
test/functional/profile_design_controller_test.rb
... | ... | @@ -311,6 +311,12 @@ class ProfileDesignControllerTest < ActionController::TestCase |
311 | 311 | assert_equal 999, @b1.article_id |
312 | 312 | end |
313 | 313 | |
314 | + should 'not be able to save a non editable block' do | |
315 | + Block.any_instance.expects(:editable?).returns(false) | |
316 | + post :save, :profile => 'designtestuser', :id => @b1.id, :block => { } | |
317 | + assert_response :forbidden | |
318 | + end | |
319 | + | |
314 | 320 | should 'be able to edit ProductsBlock' do |
315 | 321 | block = ProductsBlock.new |
316 | 322 | ... | ... |
test/functional/profile_members_controller_test.rb
... | ... | @@ -31,6 +31,31 @@ class ProfileMembersControllerTest < ActionController::TestCase |
31 | 31 | assert_template 'index' |
32 | 32 | end |
33 | 33 | |
34 | + should 'access index and filter members by name and roles' do | |
35 | + | |
36 | + ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'test enterprise') | |
37 | + roles = { | |
38 | + :admin => Profile::Roles.admin(Environment.default), | |
39 | + :member => Profile::Roles.member(Environment.default) | |
40 | + } | |
41 | + | |
42 | + member = create_user('test_member', :email => 'testmember@test.com.br').person | |
43 | + member.add_role(roles[:member], ent) | |
44 | + | |
45 | + admin = create_user('test_admin').person | |
46 | + admin.add_role roles[:admin], ent | |
47 | + | |
48 | + user = create_user_with_permission('test_user', 'manage_memberships', ent) | |
49 | + login_as :test_user | |
50 | + | |
51 | + post :index, :profile => 'test_enterprise' , :filters => {:name => 'testmember@test.com.br', :roles => [roles[:member].id]} | |
52 | + | |
53 | + assert_response :success | |
54 | + assert_template 'index' | |
55 | + | |
56 | + assert_includes assigns(:data)[:members], member | |
57 | + end | |
58 | + | |
34 | 59 | should 'show form to change role' do |
35 | 60 | ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'test enterprise') |
36 | 61 | role = Profile::Roles.member(Environment.default) |
... | ... | @@ -171,7 +196,7 @@ class ProfileMembersControllerTest < ActionController::TestCase |
171 | 196 | login_as :test_user |
172 | 197 | |
173 | 198 | get :index, :profile => community.identifier |
174 | - assert_tag :tag => 'a', :attributes => {:href => /send_mail/} | |
199 | + assert_tag :tag => 'input', :attributes => {:value => 'Send e-mail to members'} | |
175 | 200 | end |
176 | 201 | |
177 | 202 | should 'not display send email to members if doesn\'t have the permission' do | ... | ... |
test/integration/enable_disable_features_test.rb
... | ... | @@ -13,17 +13,15 @@ class EnableDisableFeaturesTest < ActionDispatch::IntegrationTest |
13 | 13 | assert_tag :tag => 'input', :attributes => { :name => 'environment[enabled_features][]', :value => 'feature2' } |
14 | 14 | assert_tag :tag => 'input', :attributes => { :name => 'environment[enabled_features][]', :value => 'feature3' } |
15 | 15 | |
16 | - post '/admin/features/update' | |
17 | - assert_response :redirect | |
16 | + post_via_redirect '/admin/features/update' | |
17 | + assert_response :success | |
18 | 18 | |
19 | - follow_redirect! | |
20 | 19 | assert_response :success |
21 | 20 | assert_equal '/admin/features', path |
22 | 21 | |
23 | - post '/admin/features/update', :environments => { :enabled_features => [ 'feature1' ], :organization_approval_method => 'region' } | |
24 | - assert_response :redirect | |
22 | + post_via_redirect '/admin/features/update', :environments => { :enabled_features => [ 'feature1' ], :organization_approval_method => 'region' } | |
23 | + assert_response :success | |
25 | 24 | |
26 | - follow_redirect! | |
27 | 25 | assert_equal '/admin/features', path |
28 | 26 | |
29 | 27 | end | ... | ... |
test/integration/enterprise_registration_test.rb
... | ... | @@ -61,10 +61,9 @@ class EnterpriseRegistrationTest < ActionDispatch::IntegrationTest |
61 | 61 | assert_response :success |
62 | 62 | assert_tag :form, :attributes => { :action => "/myprofile/myorg/enterprise_validation/approve/#{code}" } |
63 | 63 | |
64 | - post "/myprofile/myorg/enterprise_validation/approve/#{code}" | |
65 | - assert_response :redirect | |
64 | + post_via_redirect "/myprofile/myorg/enterprise_validation/approve/#{code}" | |
65 | + assert_response :success | |
66 | 66 | |
67 | - follow_redirect! | |
68 | 67 | assert_equal "/myprofile/myorg/enterprise_validation/view_processed/#{code}", path |
69 | 68 | assert_tag :span, :attributes => { :class => 'validation_approved' } |
70 | 69 | end | ... | ... |
test/integration/manage_documents_test.rb
... | ... | @@ -24,11 +24,10 @@ class ManageDocumentsTest < ActionDispatch::IntegrationTest |
24 | 24 | assert_tag :tag => 'form', :attributes => { :action => '/myprofile/myuser/cms/new', :method => /post/i } |
25 | 25 | |
26 | 26 | assert_difference 'Article.count' do |
27 | - post '/myprofile/myuser/cms/new', :type => 'TinyMceArticle', :article => { :name => 'my article', :body => 'this is the body of ther article'} | |
27 | + post_via_redirect '/myprofile/myuser/cms/new', :type => 'TinyMceArticle', :article => { :name => 'my article', :body => 'this is the body of ther article'} | |
28 | 28 | end |
29 | 29 | |
30 | - assert_response :redirect | |
31 | - follow_redirect! | |
30 | + assert_response :success | |
32 | 31 | a = Article.find_by_path('my-article') |
33 | 32 | assert_equal "/myuser/#{a.slug}", path |
34 | 33 | end |
... | ... | @@ -55,14 +54,13 @@ class ManageDocumentsTest < ActionDispatch::IntegrationTest |
55 | 54 | assert_tag :tag => 'form', :attributes => { :action => "/myprofile/myuser/cms/edit/#{article.id}", :method => /post/i } |
56 | 55 | |
57 | 56 | assert_no_difference 'Article.count' do |
58 | - post "/myprofile/myuser/cms/edit/#{article.id}", :article => { :name => 'my article', :body => 'this is the body of the article'} | |
57 | + post_via_redirect "/myprofile/myuser/cms/edit/#{article.id}", :article => { :name => 'my article', :body => 'this is the body of the article'} | |
59 | 58 | end |
60 | 59 | |
61 | 60 | article.reload |
62 | 61 | assert_equal 'this is the body of the article', article.body |
63 | 62 | |
64 | - assert_response :redirect | |
65 | - follow_redirect! | |
63 | + assert_response :success | |
66 | 64 | a = Article.find_by_path('my-article') |
67 | 65 | assert_equal "/myuser/#{a.slug}", path |
68 | 66 | end |
... | ... | @@ -84,10 +82,9 @@ class ManageDocumentsTest < ActionDispatch::IntegrationTest |
84 | 82 | assert_response :success |
85 | 83 | |
86 | 84 | assert_tag tag: 'a', attributes: { href: "/myprofile/myuser/cms/destroy/#{article.id}", 'data-confirm' => /Are you sure/ } |
87 | - post "/myprofile/myuser/cms/destroy/#{article.id}" | |
85 | + post_via_redirect "/myprofile/myuser/cms/destroy/#{article.id}" | |
88 | 86 | |
89 | - assert_response :redirect | |
90 | - follow_redirect! | |
87 | + assert_response :success | |
91 | 88 | assert_equal "/myuser", path |
92 | 89 | |
93 | 90 | # the article was actually deleted | ... | ... |
test/integration/manage_friendships_test.rb
... | ... | @@ -24,11 +24,10 @@ class ManageFriendshipsTest < ActionDispatch::IntegrationTest |
24 | 24 | get "/myprofile/#{@person.identifier}/friends/remove/#{@friend.id}" |
25 | 25 | assert_response :success |
26 | 26 | |
27 | - post "/myprofile/#{@person.identifier}/friends/remove/#{@friend.id}", | |
27 | + post_via_redirect "/myprofile/#{@person.identifier}/friends/remove/#{@friend.id}", | |
28 | 28 | :confirmation => '1' |
29 | - assert_response :redirect | |
29 | + assert_response :success | |
30 | 30 | |
31 | - follow_redirect! | |
32 | 31 | |
33 | 32 | assert assigns(:friends).empty? |
34 | 33 | refute @person.is_a_friend?(@friend) | ... | ... |
test/support/integration_test.rb
... | ... | @@ -14,9 +14,8 @@ class ActionDispatch::IntegrationTest |
14 | 14 | def login(username, password) |
15 | 15 | ActionDispatch::Integration::Session.any_instance.stubs(:https?).returns(true) |
16 | 16 | |
17 | - post '/account/login', :user => { :login => username, :password => password } | |
18 | - assert_response :redirect | |
19 | - follow_redirect! | |
17 | + post_via_redirect '/account/login', :user => { :login => username, :password => password } | |
18 | + assert_response :success | |
20 | 19 | assert_not_equal '/account/login', path |
21 | 20 | end |
22 | 21 | ... | ... |
... | ... | @@ -0,0 +1,34 @@ |
1 | + | |
2 | +require_relative "../test_helper" | |
3 | + | |
4 | +class AccessControlTest < ActiveSupport::TestCase | |
5 | + | |
6 | + include ActsAsAccessor | |
7 | + | |
8 | + should 'raise exception if parameter is not a profile' do | |
9 | + assert_raises(TypeError) { member_relation_of(nil) } | |
10 | + end | |
11 | + | |
12 | + should 'Verify relation among member and community' do | |
13 | + person = fast_create(Person) | |
14 | + community = fast_create(Community) | |
15 | + assert_difference 'person.member_relation_of(community).count', 2 do | |
16 | + community.add_member(person) | |
17 | + end | |
18 | + end | |
19 | + | |
20 | + should 'Member does not belong to community' do | |
21 | + person = fast_create(Person) | |
22 | + community = fast_create(Community) | |
23 | + assert_nil person.member_since_date(community) | |
24 | + end | |
25 | + | |
26 | + should 'Verify if enter date of member in community is available' do | |
27 | + person = fast_create(Person) | |
28 | + community = fast_create(Community) | |
29 | + community.add_member(person) | |
30 | + | |
31 | + assert_instance_of Date, person.member_since_date(community) | |
32 | + end | |
33 | + | |
34 | +end | ... | ... |
test/unit/action_tracker_notification_test.rb
... | ... | @@ -89,7 +89,8 @@ class ActionTrackerNotificationTest < ActiveSupport::TestCase |
89 | 89 | end |
90 | 90 | |
91 | 91 | should "have comments through article action_tracker" do |
92 | - person = create_user.person | |
92 | + user = User.current = create_user | |
93 | + person = user.person | |
93 | 94 | article = create(TextileArticle, :profile_id => person.id) |
94 | 95 | process_delayed_job_queue |
95 | 96 | notification = ActionTrackerNotification.last | ... | ... |
test/unit/api/articles_test.rb
... | ... | @@ -39,6 +39,41 @@ class ArticlesTest < ActiveSupport::TestCase |
39 | 39 | assert_equal 403, last_response.status |
40 | 40 | end |
41 | 41 | |
42 | + should 'follow a article identified by id' do | |
43 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
44 | + post "/api/v1/articles/#{article.id}/follow?#{params.to_query}" | |
45 | + json = JSON.parse(last_response.body) | |
46 | + | |
47 | + assert_not_equal 401, last_response.status | |
48 | + assert_equal true, json['success'] | |
49 | + end | |
50 | + | |
51 | + should 'return the followers count of an article' do | |
52 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
53 | + article.person_followers << @person | |
54 | + | |
55 | + get "/api/v1/articles/#{article.id}?#{params.to_query}" | |
56 | + json = JSON.parse(last_response.body) | |
57 | + | |
58 | + assert_equal 200, last_response.status | |
59 | + assert_equal 1, json['article']['followers_count'] | |
60 | + end | |
61 | + | |
62 | + should 'return the followers of a article identified by id' do | |
63 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
64 | + | |
65 | + article_follower = ArticleFollower.new | |
66 | + article_follower.article = article | |
67 | + article_follower.person = @person | |
68 | + article_follower.save! | |
69 | + | |
70 | + get "/api/v1/articles/#{article.id}/followers?#{params.to_query}" | |
71 | + json = JSON.parse(last_response.body) | |
72 | + | |
73 | + assert_equal 200, last_response.status | |
74 | + assert_equal 1, json['total_followers'] | |
75 | + end | |
76 | + | |
42 | 77 | should 'list article children' do |
43 | 78 | article = create(Article, :profile_id => user.person.id, :name => "Parent") |
44 | 79 | child1 = create(Article, :parent_id => article.id, :profile_id => user.person.id, :name => "Some Child") | ... | ... |
test/unit/application_helper_test.rb
... | ... | @@ -1043,6 +1043,31 @@ class ApplicationHelperTest < ActionView::TestCase |
1043 | 1043 | assert_equal c.top_url, top_url |
1044 | 1044 | end |
1045 | 1045 | |
1046 | + should "Extra info with hash" do | |
1047 | + @plugins = mock | |
1048 | + @plugins.stubs(:dispatch_first).returns(false) | |
1049 | + env = Environment.default | |
1050 | + stubs(:environment).returns(env) | |
1051 | + stubs(:profile).returns(profile) | |
1052 | + profile = fast_create(Person, :environment_id => env.id) | |
1053 | + info = {:value =>_('New'), :class => 'new-profile'} | |
1054 | + html = profile_image_link(profile, size=:portrait, tag='li', extra_info = info) | |
1055 | + assert_tag_in_string html, :tag => 'span', :attributes => { :class => 'profile-image new-profile' } | |
1056 | + assert_tag_in_string html, :tag => 'span', :attributes => { :class => 'extra_info new-profile' }, :content => 'New' | |
1057 | + end | |
1058 | + | |
1059 | + should "Extra info without hash" do | |
1060 | + @plugins = mock | |
1061 | + @plugins.stubs(:dispatch_first).returns(false) | |
1062 | + env = Environment.default | |
1063 | + stubs(:environment).returns(env) | |
1064 | + stubs(:profile).returns(profile) | |
1065 | + profile = fast_create(Person, :environment_id => env.id) | |
1066 | + info = 'new' | |
1067 | + html = profile_image_link(profile, size=:portrait, tag='li', extra_info = info) | |
1068 | + assert_tag_in_string html, :tag => 'span', :attributes => { :class => 'extra_info' }, :content => 'new' | |
1069 | + end | |
1070 | + | |
1046 | 1071 | protected |
1047 | 1072 | include NoosferoTestHelper |
1048 | 1073 | ... | ... |
test/unit/article_block_test.rb
... | ... | @@ -140,6 +140,8 @@ class ArticleBlockTest < ActiveSupport::TestCase |
140 | 140 | block.article = file |
141 | 141 | block.save! |
142 | 142 | |
143 | + UploadedFile.any_instance.stubs(:url).returns('myhost.mydomain/path/to/file') | |
144 | + | |
143 | 145 | assert_tag_in_string instance_eval(&block.content), :tag => 'a', :content => _('Download') |
144 | 146 | end |
145 | 147 | ... | ... |
test/unit/article_test.rb
... | ... | @@ -7,7 +7,8 @@ class ArticleTest < ActiveSupport::TestCase |
7 | 7 | |
8 | 8 | def setup |
9 | 9 | ActiveSupport::TestCase::setup |
10 | - @profile = create_user('testing').person | |
10 | + user = User.current = create_user 'testing' | |
11 | + @profile = user.person | |
11 | 12 | end |
12 | 13 | attr_reader :profile |
13 | 14 | |
... | ... | @@ -21,6 +22,21 @@ class ArticleTest < ActiveSupport::TestCase |
21 | 22 | refute a.errors[:profile_id.to_s].present? |
22 | 23 | end |
23 | 24 | |
25 | + should 'keep unique users in list of followers' do | |
26 | + person1 = create_user('article_owner').person | |
27 | + person2 = create_user('article_follower').person | |
28 | + | |
29 | + article = fast_create(Article, :profile_id => person1.id) | |
30 | + | |
31 | + article.person_followers=[person2] | |
32 | + article.save | |
33 | + article.reload | |
34 | + article.person_followers=[person2] | |
35 | + article.save | |
36 | + | |
37 | + assert_equal 1, article.reload.person_followers.size | |
38 | + end | |
39 | + | |
24 | 40 | should 'require value for name' do |
25 | 41 | a = Article.new |
26 | 42 | a.valid? |
... | ... | @@ -468,14 +484,12 @@ class ArticleTest < ActiveSupport::TestCase |
468 | 484 | end |
469 | 485 | |
470 | 486 | should 'say that logged off user cannot see private article' do |
471 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
472 | 487 | article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) |
473 | 488 | |
474 | 489 | refute article.display_to?(nil) |
475 | 490 | end |
476 | 491 | |
477 | 492 | should 'say that not member of profile cannot see private article' do |
478 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
479 | 493 | article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) |
480 | 494 | person = create_user('test_user').person |
481 | 495 | |
... | ... | @@ -483,7 +497,6 @@ class ArticleTest < ActiveSupport::TestCase |
483 | 497 | end |
484 | 498 | |
485 | 499 | should 'say that member user can not see private article' do |
486 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
487 | 500 | article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false, :show_to_followers => false) |
488 | 501 | person = create_user('test_user').person |
489 | 502 | profile.affiliate(person, Profile::Roles.member(profile.environment.id)) |
... | ... | @@ -492,25 +505,23 @@ class ArticleTest < ActiveSupport::TestCase |
492 | 505 | end |
493 | 506 | |
494 | 507 | should 'say that profile admin can see private article' do |
495 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
508 | + org = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
496 | 509 | article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) |
497 | - person = create_user('test_user').person | |
498 | - profile.affiliate(person, Profile::Roles.admin(profile.environment.id)) | |
510 | + org.affiliate(profile, Profile::Roles.admin(org.environment.id)) | |
499 | 511 | |
500 | - assert article.display_to?(person) | |
512 | + assert article.display_to?(profile) | |
501 | 513 | end |
502 | 514 | |
503 | 515 | should 'say that profile moderator can see private article' do |
504 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
505 | - article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) | |
506 | - person = create_user('test_user').person | |
507 | - profile.affiliate(person, Profile::Roles.moderator(profile.environment.id)) | |
516 | + org = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
517 | + article = fast_create(Article, :name => 'test article', :profile_id => org.id, :published => false) | |
518 | + org.affiliate(profile, Profile::Roles.moderator(org.environment.id)) | |
508 | 519 | |
509 | - assert article.display_to?(person) | |
520 | + assert article.display_to?(profile) | |
510 | 521 | end |
511 | 522 | |
512 | 523 | should 'show article to non member if article public but profile private' do |
513 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile', :public_profile => false) | |
524 | + profile.update public_profile: false | |
514 | 525 | article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => true) |
515 | 526 | person1 = create_user('test_user1').person |
516 | 527 | profile.affiliate(person1, Profile::Roles.member(profile.environment.id)) |
... | ... | @@ -522,7 +533,6 @@ class ArticleTest < ActiveSupport::TestCase |
522 | 533 | end |
523 | 534 | |
524 | 535 | should 'make new article private if created inside a private folder' do |
525 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
526 | 536 | folder = fast_create(Folder, :name => 'my_intranet', :profile_id => profile.id, :published => false) |
527 | 537 | article = fast_create(Article, :name => 'my private article', :profile_id => profile.id, :parent_id => folder.id) |
528 | 538 | |
... | ... | @@ -530,7 +540,6 @@ class ArticleTest < ActiveSupport::TestCase |
530 | 540 | end |
531 | 541 | |
532 | 542 | should 'save as private' do |
533 | - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile') | |
534 | 543 | folder = fast_create(Folder, :name => 'my_intranet', :profile_id => profile.id, :published => false) |
535 | 544 | article = fast_create(Article, :name => 'my private article') |
536 | 545 | article.profile = profile |
... | ... | @@ -1012,13 +1021,13 @@ class ArticleTest < ActiveSupport::TestCase |
1012 | 1021 | |
1013 | 1022 | should 'not notify activity by default on create' do |
1014 | 1023 | ActionTracker::Record.delete_all |
1015 | - create Article, :name => 'test', :profile_id => fast_create(Profile).id, :published => true | |
1024 | + create Article, :name => 'test', :profile_id => profile.id, :published => true | |
1016 | 1025 | assert_equal 0, ActionTracker::Record.count |
1017 | 1026 | end |
1018 | 1027 | |
1019 | 1028 | should 'not notify activity by default on update' do |
1020 | 1029 | ActionTracker::Record.delete_all |
1021 | - a = create Article, :name => 'bar', :profile_id => fast_create(Profile).id, :published => true | |
1030 | + a = create Article, :name => 'bar', :profile_id => profile.id, :published => true | |
1022 | 1031 | a.name = 'foo' |
1023 | 1032 | a.save! |
1024 | 1033 | assert_equal 0, ActionTracker::Record.count |
... | ... | @@ -1026,13 +1035,13 @@ class ArticleTest < ActiveSupport::TestCase |
1026 | 1035 | |
1027 | 1036 | should 'not notify activity by default on destroy' do |
1028 | 1037 | ActionTracker::Record.delete_all |
1029 | - a = create Article, :name => 'bar', :profile_id => fast_create(Profile).id, :published => true | |
1038 | + a = create Article, :name => 'bar', :profile_id => profile.id, :published => true | |
1030 | 1039 | a.destroy |
1031 | 1040 | assert_equal 0, ActionTracker::Record.count |
1032 | 1041 | end |
1033 | 1042 | |
1034 | 1043 | should 'create activity' do |
1035 | - a = create TextileArticle, :name => 'bar', :profile_id => fast_create(Profile).id, :published => true | |
1044 | + a = create TextileArticle, :name => 'bar', :profile_id => profile.id, :published => true | |
1036 | 1045 | a.activity.destroy |
1037 | 1046 | assert_nil a.activity |
1038 | 1047 | |
... | ... | @@ -1212,10 +1221,9 @@ class ArticleTest < ActiveSupport::TestCase |
1212 | 1221 | end |
1213 | 1222 | |
1214 | 1223 | should 'get article galleries' do |
1215 | - p = fast_create(Profile) | |
1216 | - a = fast_create(Article, :profile_id => p.id) | |
1217 | - g = fast_create(Gallery, :profile_id => p.id) | |
1218 | - assert_equal [g], p.articles.galleries | |
1224 | + a = fast_create(Article, :profile_id => profile.id) | |
1225 | + g = fast_create(Gallery, :profile_id => profile.id) | |
1226 | + assert_equal [g], profile.articles.galleries | |
1219 | 1227 | end |
1220 | 1228 | |
1221 | 1229 | should 'has many translations' do |
... | ... | @@ -1236,7 +1244,7 @@ class ArticleTest < ActiveSupport::TestCase |
1236 | 1244 | end |
1237 | 1245 | |
1238 | 1246 | should 'validate inclusion of language' do |
1239 | - a = build(Article, :profile_id => fast_create(Profile).id) | |
1247 | + a = build(Article, :profile_id => profile.id) | |
1240 | 1248 | a.language = '12' |
1241 | 1249 | a.valid? |
1242 | 1250 | assert a.errors[:language.to_s].present? |
... | ... | @@ -1268,7 +1276,7 @@ class ArticleTest < ActiveSupport::TestCase |
1268 | 1276 | end |
1269 | 1277 | |
1270 | 1278 | should 'list possible translations' do |
1271 | - native_article = fast_create(Article, :language => 'pt', :profile_id => fast_create(Profile).id ) | |
1279 | + native_article = fast_create(Article, :language => 'pt', :profile_id => profile.id ) | |
1272 | 1280 | article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id) |
1273 | 1281 | possible_translations = native_article.possible_translations |
1274 | 1282 | refute possible_translations.include?('en') |
... | ... | @@ -1278,7 +1286,7 @@ class ArticleTest < ActiveSupport::TestCase |
1278 | 1286 | should 'verify if translation is already in use' do |
1279 | 1287 | native_article = fast_create(Article, :language => 'pt') |
1280 | 1288 | article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id) |
1281 | - a = build(Article, :profile => fast_create(Profile)) | |
1289 | + a = build(Article, :profile => profile) | |
1282 | 1290 | a.language = 'en' |
1283 | 1291 | a.translation_of = native_article |
1284 | 1292 | a.valid? |
... | ... | @@ -1290,7 +1298,7 @@ class ArticleTest < ActiveSupport::TestCase |
1290 | 1298 | |
1291 | 1299 | should 'verify if native translation is already in use' do |
1292 | 1300 | native_article = fast_create(Article, :language => 'pt') |
1293 | - a = build(Article, :profile => fast_create(Profile)) | |
1301 | + a = build(Article, :profile => profile) | |
1294 | 1302 | a.language = 'pt' |
1295 | 1303 | a.translation_of = native_article |
1296 | 1304 | a.valid? |
... | ... | @@ -1302,7 +1310,7 @@ class ArticleTest < ActiveSupport::TestCase |
1302 | 1310 | |
1303 | 1311 | should 'translation have a language' do |
1304 | 1312 | native_article = fast_create(Article, :language => 'pt') |
1305 | - a = build(Article, :profile_id => fast_create(Profile).id) | |
1313 | + a = build(Article, :profile_id => profile.id) | |
1306 | 1314 | a.translation_of = native_article |
1307 | 1315 | a.valid? |
1308 | 1316 | assert a.errors[:language.to_s].present? |
... | ... | @@ -1312,8 +1320,8 @@ class ArticleTest < ActiveSupport::TestCase |
1312 | 1320 | end |
1313 | 1321 | |
1314 | 1322 | should 'native translation have a language' do |
1315 | - native_article = fast_create(Article, :profile_id => fast_create(Profile).id ) | |
1316 | - a = build(Article, :profile_id => fast_create(Profile).id) | |
1323 | + native_article = fast_create(Article, :profile_id => profile.id ) | |
1324 | + a = build(Article, :profile_id => profile.id) | |
1317 | 1325 | a.language = 'en' |
1318 | 1326 | a.translation_of = native_article |
1319 | 1327 | a.valid? |
... | ... | @@ -1378,22 +1386,22 @@ class ArticleTest < ActiveSupport::TestCase |
1378 | 1386 | end |
1379 | 1387 | |
1380 | 1388 | should 'get only non translated articles' do |
1381 | - p = fast_create(Profile) | |
1382 | - native = fast_create(Article, :language => 'pt', :profile_id => p.id) | |
1383 | - translation = fast_create(Article, :language => 'en', :translation_of_id => native.id, :profile_id => p.id) | |
1384 | - assert_equal [native], p.articles.native_translations | |
1389 | + profile.articles.delete_all | |
1390 | + native = fast_create(Article, :language => 'pt', :profile_id => profile.id) | |
1391 | + translation = fast_create(Article, :language => 'en', :translation_of_id => native.id, :profile_id => profile.id) | |
1392 | + assert_equal [native], profile.articles.native_translations | |
1385 | 1393 | end |
1386 | 1394 | |
1387 | 1395 | should 'not list own language as a possible translation if language has changed' do |
1388 | - a = build(Article, :language => 'pt', :profile_id => fast_create(Profile).id) | |
1396 | + a = build(Article, :language => 'pt', :profile_id => profile.id) | |
1389 | 1397 | refute a.possible_translations.include?('pt') |
1390 | - a = fast_create(Article, :language => 'pt', :profile_id => fast_create(Profile).id ) | |
1398 | + a = fast_create(Article, :language => 'pt', :profile_id => profile.id ) | |
1391 | 1399 | a.language = 'en' |
1392 | 1400 | refute a.possible_translations.include?('en') |
1393 | 1401 | end |
1394 | 1402 | |
1395 | 1403 | should 'list own language as a possible translation if language has not changed' do |
1396 | - a = fast_create(Article, :language => 'pt', :profile_id => fast_create(Profile).id) | |
1404 | + a = fast_create(Article, :language => 'pt', :profile_id => profile.id) | |
1397 | 1405 | assert a.possible_translations.include?('pt') |
1398 | 1406 | end |
1399 | 1407 | |
... | ... | @@ -1435,7 +1443,6 @@ class ArticleTest < ActiveSupport::TestCase |
1435 | 1443 | should 'return only folders' do |
1436 | 1444 | not_folders = [RssFeed, TinyMceArticle, Event, TextileArticle] |
1437 | 1445 | folders = [Folder, Blog, Gallery, Forum] |
1438 | - profile = fast_create(Profile) | |
1439 | 1446 | |
1440 | 1447 | not_folders.each do |klass| |
1441 | 1448 | item = fast_create(klass) |
... | ... | @@ -1451,7 +1458,6 @@ class ArticleTest < ActiveSupport::TestCase |
1451 | 1458 | should 'return no folders' do |
1452 | 1459 | not_folders = [RssFeed, TinyMceArticle, Event, TextileArticle] |
1453 | 1460 | folders = [Folder, Blog, Gallery, Forum] |
1454 | - profile = fast_create(Profile) | |
1455 | 1461 | |
1456 | 1462 | not_folders.each do |klass| |
1457 | 1463 | item = fast_create(klass) |
... | ... | @@ -1611,18 +1617,16 @@ class ArticleTest < ActiveSupport::TestCase |
1611 | 1617 | end |
1612 | 1618 | |
1613 | 1619 | should 'delegate region info to profile' do |
1614 | - profile = fast_create(Profile) | |
1615 | - Profile.any_instance.expects(:region) | |
1616 | - Profile.any_instance.expects(:region_id) | |
1620 | + Person.any_instance.expects(:region) | |
1621 | + Person.any_instance.expects(:region_id) | |
1617 | 1622 | article = fast_create(Article, :profile_id => profile.id) |
1618 | 1623 | article.region |
1619 | 1624 | article.region_id |
1620 | 1625 | end |
1621 | 1626 | |
1622 | 1627 | should 'delegate environment info to profile' do |
1623 | - profile = fast_create(Profile) | |
1624 | - Profile.any_instance.expects(:environment) | |
1625 | - Profile.any_instance.expects(:environment_id) | |
1628 | + Person.any_instance.expects(:environment) | |
1629 | + Person.any_instance.expects(:environment_id) | |
1626 | 1630 | article = fast_create(Article, :profile_id => profile.id) |
1627 | 1631 | article.environment |
1628 | 1632 | article.environment_id |
... | ... | @@ -1711,7 +1715,7 @@ class ArticleTest < ActiveSupport::TestCase |
1711 | 1715 | |
1712 | 1716 | should 'has a empty list of followers by default' do |
1713 | 1717 | a = Article.new |
1714 | - assert_equal [], a.followers | |
1718 | + assert_equal [], a.person_followers | |
1715 | 1719 | end |
1716 | 1720 | |
1717 | 1721 | should 'get first image from lead' do |
... | ... | @@ -2229,6 +2233,14 @@ class ArticleTest < ActiveSupport::TestCase |
2229 | 2233 | end |
2230 | 2234 | end |
2231 | 2235 | |
2236 | + should 'be able to vote in an article without a user' do | |
2237 | + article = create(Article, :name => 'Test', :profile => profile, :last_changed_by => nil) | |
2238 | + assert_difference 'article.votes_for', 2 do | |
2239 | + Vote.create!(:voteable => article, :vote => 1) | |
2240 | + Vote.create!(:voteable => article, :vote => 1) | |
2241 | + end | |
2242 | + end | |
2243 | + | |
2232 | 2244 | should 'have can_display_media_panel with default false' do |
2233 | 2245 | a = Article.new |
2234 | 2246 | assert !a.can_display_media_panel? |
... | ... | @@ -2278,4 +2290,15 @@ class ArticleTest < ActiveSupport::TestCase |
2278 | 2290 | assert_match 'Parent folder is archived', err.message |
2279 | 2291 | end |
2280 | 2292 | |
2293 | + should 'return full_path' do | |
2294 | + p1 = fast_create(Profile) | |
2295 | + p2 = fast_create(Profile) | |
2296 | + p2.domains << Domain.create!(:name => 'p2.domain') | |
2297 | + a1 = fast_create(Article, :profile_id => p1.id) | |
2298 | + a2 = fast_create(Article, :profile_id => p2.id) | |
2299 | + | |
2300 | + assert_equal "/#{p1.identifier}/#{a1.path}", a1.full_path | |
2301 | + assert_equal "/#{a2.path}", a2.full_path | |
2302 | + end | |
2303 | + | |
2281 | 2304 | end | ... | ... |
test/unit/blog_helper_test.rb
... | ... | @@ -101,11 +101,9 @@ class BlogHelperTest < ActionView::TestCase |
101 | 101 | |
102 | 102 | should 'display link to file if post is an uploaded_file' do |
103 | 103 | file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true, :parent => blog) |
104 | - | |
105 | 104 | result = display_post(file) |
106 | - assert_tag_in_string result, :tag => 'a', | |
107 | - :attributes => { :href => file.public_filename }, | |
108 | - :content => _('Download') | |
105 | + | |
106 | + assert_tag_in_string result, :tag => 'a', :content => _('Download') | |
109 | 107 | end |
110 | 108 | |
111 | 109 | should 'display image if post is an image' do | ... | ... |
test/unit/boxes_helper_test.rb
... | ... | @@ -187,6 +187,7 @@ class BoxesHelperTest < ActionView::TestCase |
187 | 187 | block = Block.create!(:box => box) |
188 | 188 | block.stubs(:embedable?).returns(true) |
189 | 189 | stubs(:url_for).returns('') |
190 | + @controller.stubs(:user).returns(box.owner) | |
190 | 191 | assert_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '} |
191 | 192 | end |
192 | 193 | |
... | ... | @@ -195,6 +196,7 @@ class BoxesHelperTest < ActionView::TestCase |
195 | 196 | block = Block.create!(:box => box) |
196 | 197 | block.stubs(:embedable?).returns(false) |
197 | 198 | stubs(:url_for).returns('') |
199 | + @controller.stubs(:user).returns(box.owner) | |
198 | 200 | assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '} |
199 | 201 | end |
200 | 202 | ... | ... |
test/unit/comment_notifier_test.rb
... | ... | @@ -60,7 +60,7 @@ class CommentNotifierTest < ActiveSupport::TestCase |
60 | 60 | should "deliver mail to followers" do |
61 | 61 | author = create_user('follower_author').person |
62 | 62 | follower = create_user('follower').person |
63 | - @article.followers += [follower.email] | |
63 | + @article.person_followers += [follower] | |
64 | 64 | @article.save! |
65 | 65 | create_comment_and_notify(:source => @article, :author => author, :title => 'comment title', :body => 'comment body') |
66 | 66 | assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email | ... | ... |
test/unit/comment_test.rb
... | ... | @@ -339,34 +339,27 @@ class CommentTest < ActiveSupport::TestCase |
339 | 339 | assert c.rejected? |
340 | 340 | end |
341 | 341 | |
342 | - should 'subscribe user as follower of an article on new comment' do | |
342 | + should 'not subscribe user as follower of an article automatically on new comment' do | |
343 | 343 | owner = create_user('owner_of_article').person |
344 | 344 | person = create_user('follower').person |
345 | 345 | article = fast_create(Article, :profile_id => owner.id) |
346 | - assert_not_includes article.followers, person.email | |
346 | + assert_not_includes article.person_followers, person | |
347 | 347 | create(Comment, :source => article, :author => person, :title => 'new comment', :body => 'new comment') |
348 | - assert_includes article.reload.followers, person.email | |
348 | + assert_not_includes article.reload.person_followers, person | |
349 | 349 | end |
350 | 350 | |
351 | - should 'subscribe guest user as follower of an article on new comment' do | |
351 | + should 'not subscribe guest user as follower of an article on new comment' do | |
352 | 352 | article = fast_create(Article, :profile_id => create_user('article_owner').person.id) |
353 | - assert_not_includes article.followers, 'follower@example.com' | |
353 | + old_num_followers = article.reload.person_followers.size | |
354 | 354 | create(Comment, :source => article, :name => 'follower', :email => 'follower@example.com', :title => 'new comment', :body => 'new comment') |
355 | - assert_includes article.reload.followers, 'follower@example.com' | |
356 | - end | |
357 | - | |
358 | - should 'keep unique emails in list of followers' do | |
359 | - article = fast_create(Article, :profile_id => create_user('article_owner').person.id) | |
360 | - create(Comment, :source => article, :name => 'follower one', :email => 'follower@example.com', :title => 'new comment', :body => 'new comment') | |
361 | - create(Comment, :source => article, :name => 'follower two', :email => 'follower@example.com', :title => 'another comment', :body => 'new comment') | |
362 | - assert_equal 1, article.reload.followers.select{|v| v == 'follower@example.com'}.count | |
355 | + assert_equal old_num_followers, article.reload.person_followers.size | |
363 | 356 | end |
364 | 357 | |
365 | 358 | should 'not subscribe owner as follower of an article on new comment' do |
366 | 359 | owner = create_user('owner_of_article').person |
367 | 360 | article = fast_create(Article, :profile_id => owner.id) |
368 | 361 | create(Comment, :source => article, :author => owner, :title => 'new comment', :body => 'new comment') |
369 | - assert_not_includes article.reload.followers, owner.email | |
362 | + assert_not_includes article.reload.person_followers, owner | |
370 | 363 | end |
371 | 364 | |
372 | 365 | should 'not subscribe admins as follower of an article on new comment' do |
... | ... | @@ -377,8 +370,13 @@ class CommentTest < ActiveSupport::TestCase |
377 | 370 | article = fast_create(Article, :profile_id => owner.id) |
378 | 371 | create(Comment, :source => article, :author => follower, :title => 'new comment', :body => 'new comment') |
379 | 372 | create(Comment, :source => article, :author => admin, :title => 'new comment', :body => 'new comment') |
380 | - assert_not_includes article.reload.followers, admin.email | |
381 | - assert_includes article.followers, follower.email | |
373 | + | |
374 | + article.person_followers += [follower] | |
375 | + article.save! | |
376 | + article.reload | |
377 | + | |
378 | + assert_not_includes article.reload.person_followers, admin | |
379 | + assert_includes article.reload.person_followers, follower | |
382 | 380 | end |
383 | 381 | |
384 | 382 | should 'update article activity when add a comment' do | ... | ... |
test/unit/highlights_block_test.rb
... | ... | @@ -54,7 +54,19 @@ class HighlightsBlockTest < ActiveSupport::TestCase |
54 | 54 | should 'remove images with blank fields' do |
55 | 55 | h = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => '', :position => '', :title => ''}]) |
56 | 56 | h.save! |
57 | - assert_equal [{:image_id => 1, :address => '/address', :position => 1, :title => 'address', :image_src => nil}], h.images | |
57 | + assert_equal [{:image_id => 1, :address => '/address', :position => 1, :title => 'address', :new_window => false, :image_src => nil}], h.images | |
58 | + end | |
59 | + | |
60 | + should 'replace 1 and 0 by true and false in new_window attribute' do | |
61 | + image1 = {:image_id => 1, :address => '/address-1', :position => 1, :title => 'address-1', :new_window => '0'} | |
62 | + image2 = {:image_id => 2, :address => '/address-2', :position => 2, :title => 'address-2', :new_window => '1'} | |
63 | + h = HighlightsBlock.new(:images => [image1, image2]) | |
64 | + h.save! | |
65 | + image1[:new_window] = false | |
66 | + image1[:image_src] = nil | |
67 | + image2[:new_window] = true | |
68 | + image2[:image_src] = nil | |
69 | + assert_equivalent [image1, image2], h.images | |
58 | 70 | end |
59 | 71 | |
60 | 72 | should 'be able to update display setting' do |
... | ... | @@ -84,7 +96,7 @@ class HighlightsBlockTest < ActiveSupport::TestCase |
84 | 96 | block.save! |
85 | 97 | block.reload |
86 | 98 | assert_equal 2, block.images.count |
87 | - assert_equal [{:image_id => 1, :address => '/address', :position => 1, :title => 'address', :image_src => 'address'}], block.featured_images | |
99 | + assert_equal [{:image_id => 1, :address => '/address', :position => 1, :title => 'address', :new_window => false, :image_src => 'address'}], block.featured_images | |
88 | 100 | end |
89 | 101 | |
90 | 102 | should 'list images in order' do | ... | ... |
test/unit/noosfero_test.rb
... | ... | @@ -21,6 +21,7 @@ class NoosferoTest < ActiveSupport::TestCase |
21 | 21 | should 'support setting default locale' do |
22 | 22 | Noosfero.default_locale = 'pt_BR' |
23 | 23 | assert_equal 'pt_BR', Noosfero.default_locale |
24 | + Noosfero.default_locale = nil | |
24 | 25 | end |
25 | 26 | |
26 | 27 | should 'identifier format' do | ... | ... |
test/unit/organization_mailing_test.rb
... | ... | @@ -98,6 +98,11 @@ class OrganizationMailingTest < ActiveSupport::TestCase |
98 | 98 | assert_equal [Person['user_one'], Person['user_two']], mailing.recipients |
99 | 99 | end |
100 | 100 | |
101 | + should 'return recipients previously filtered' do | |
102 | + mailing = create(OrganizationMailing, :source => community, :subject => 'Hello', :body => 'We have some news', :person => person, :data => {:members_filtered => [Person['user_one'].id,Person['user_two'].id]}) | |
103 | + assert_equivalent [Person['user_one'], Person['user_two']], mailing.recipients | |
104 | + end | |
105 | + | |
101 | 106 | should 'return recipients according to limit' do |
102 | 107 | mailing = create(OrganizationMailing, :source => community, :subject => 'Hello', :body => 'We have some news', :person => person) |
103 | 108 | assert_equal [Person['user_one']], mailing.recipients(0, 1) | ... | ... |
test/unit/person_notifier_test.rb
... | ... | @@ -49,7 +49,8 @@ class PersonNotifierTest < ActiveSupport::TestCase |
49 | 49 | should 'display author name in delivered mail' do |
50 | 50 | @community.add_member(@member) |
51 | 51 | User.current = @admin.user |
52 | - Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article) | |
52 | + comment = Comment.create!(:author => @admin, :title => 'test comment', :body => 'body!', :source => @article) | |
53 | + comment.save! | |
53 | 54 | process_delayed_job_queue |
54 | 55 | notify |
55 | 56 | sent = ActionMailer::Base.deliveries.last | ... | ... |
test/unit/person_test.rb
... | ... | @@ -1845,4 +1845,100 @@ class PersonTest < ActiveSupport::TestCase |
1845 | 1845 | assert_equivalent [c1,c3], p1.comments |
1846 | 1846 | end |
1847 | 1847 | |
1848 | + should 'get people of one community by moderator role' do | |
1849 | + community = fast_create(Community) | |
1850 | + p1 = fast_create(Person) | |
1851 | + p2 = fast_create(Person) | |
1852 | + | |
1853 | + community.add_member p1 | |
1854 | + community.add_moderator p2 | |
1855 | + | |
1856 | + assert_equivalent [p2], Person.with_role(Profile::Roles.moderator(community.environment.id).id) | |
1857 | + end | |
1858 | + | |
1859 | + should 'get people of one community by admin role' do | |
1860 | + community = fast_create(Community) | |
1861 | + p1 = fast_create(Person) | |
1862 | + p2 = fast_create(Person) | |
1863 | + | |
1864 | + community.add_admin p1 | |
1865 | + community.add_member p2 | |
1866 | + | |
1867 | + assert_equivalent [p1], Person.with_role(Profile::Roles.admin(community.environment.id).id) | |
1868 | + end | |
1869 | + | |
1870 | + should 'get people with admin role of any community' do | |
1871 | + c1 = fast_create(Community) | |
1872 | + p1 = fast_create(Person) | |
1873 | + p2 = fast_create(Person) | |
1874 | + c1.add_admin p1 | |
1875 | + c1.add_member p2 | |
1876 | + | |
1877 | + c2 = fast_create(Community) | |
1878 | + p3 = fast_create(Person) | |
1879 | + p4 = fast_create(Person) | |
1880 | + | |
1881 | + c2.add_admin p4 | |
1882 | + c2.add_member p3 | |
1883 | + | |
1884 | + assert_equivalent [p1, p4], Person.with_role(Profile::Roles.admin(c1.environment.id).id) | |
1885 | + end | |
1886 | + | |
1887 | + should 'get distinct people with moderator role of any community' do | |
1888 | + c1 = fast_create(Community) | |
1889 | + p1 = fast_create(Person) | |
1890 | + p2 = fast_create(Person) | |
1891 | + c1.add_member p1 | |
1892 | + c1.add_moderator p2 | |
1893 | + | |
1894 | + c2 = fast_create(Community) | |
1895 | + p3 = fast_create(Person) | |
1896 | + p4 = fast_create(Person) | |
1897 | + | |
1898 | + c2.add_member p4 | |
1899 | + c2.add_moderator p3 | |
1900 | + c2.add_moderator p2 | |
1901 | + | |
1902 | + assert_equivalent [p2, p3], Person.with_role(Profile::Roles.moderator(c1.environment.id).id) | |
1903 | + end | |
1904 | + | |
1905 | + should 'count members of a community collected by moderator' do | |
1906 | + c1 = fast_create(Community) | |
1907 | + p1 = fast_create(Person) | |
1908 | + p2 = fast_create(Person) | |
1909 | + p3 = fast_create(Person) | |
1910 | + c1.add_member p1 | |
1911 | + c1.add_moderator p2 | |
1912 | + c1.add_member p3 | |
1913 | + | |
1914 | + assert_equal 1, c1.members.with_role(Profile::Roles.moderator(c1.environment.id).id).count | |
1915 | + end | |
1916 | + | |
1917 | + should 'count people of any community collected by moderator' do | |
1918 | + c1 = fast_create(Community) | |
1919 | + p1 = fast_create(Person) | |
1920 | + p2 = fast_create(Person) | |
1921 | + c1.add_member p1 | |
1922 | + c1.add_moderator p2 | |
1923 | + | |
1924 | + c2 = fast_create(Community) | |
1925 | + p3 = fast_create(Person) | |
1926 | + p4 = fast_create(Person) | |
1927 | + | |
1928 | + c2.add_member p4 | |
1929 | + c2.add_moderator p3 | |
1930 | + c2.add_moderator p2 | |
1931 | + | |
1932 | + assert_equal 2, Person.with_role(Profile::Roles.moderator(c1.environment.id).id).count | |
1933 | + end | |
1934 | + | |
1935 | + should 'check if a person is added like a member of a community today' do | |
1936 | + person = create_user('person').person | |
1937 | + community = fast_create(Community) | |
1938 | + | |
1939 | + community.add_member person | |
1940 | + | |
1941 | + assert !person.member_relation_of(community).empty?, "Person '#{person.identifier}' is not a member of Community '#{community.identifier}'" | |
1942 | + assert person.member_since_date(community) == Date.today,"Person '#{person.identifier}' is not added like a member of Community '#{community.identifier}' today" | |
1943 | + end | |
1848 | 1944 | end | ... | ... |
test/unit/profile_test.rb
... | ... | @@ -1816,6 +1816,21 @@ class ProfileTest < ActiveSupport::TestCase |
1816 | 1816 | assert_equal [person], community.members |
1817 | 1817 | end |
1818 | 1818 | |
1819 | + should 'return a list members by email of a community' do | |
1820 | + someone = create_user('Someone', email:'someone@test.com.br') | |
1821 | + someperson = create_user('Someperson',email:'someperson@test.com.br') | |
1822 | + | |
1823 | + community = fast_create(Community) | |
1824 | + community.add_member(someone.person) | |
1825 | + community.add_member(someperson.person) | |
1826 | + | |
1827 | + result = community.members_like 'email', '@test.com.br' | |
1828 | + | |
1829 | + assert_includes result, someone.person | |
1830 | + assert_includes result, someperson.person | |
1831 | + | |
1832 | + end | |
1833 | + | |
1819 | 1834 | should 'count unique members of a community' do |
1820 | 1835 | person = fast_create(Person) |
1821 | 1836 | community = fast_create(Community) | ... | ... |
test/unit/raw_html_block_test.rb
... | ... | @@ -22,4 +22,20 @@ class RawHTMLBlockTest < ActiveSupport::TestCase |
22 | 22 | assert_match(/HTML$/, block.content) |
23 | 23 | end |
24 | 24 | |
25 | + should 'not be editable for users without permission' do | |
26 | + environment = Environment.default | |
27 | + box = Box.new(:owner => environment) | |
28 | + block = RawHTMLBlock.new(:html => "HTML", :box => box) | |
29 | + user = create_user('testuser').person | |
30 | + assert !block.editable?(user) | |
31 | + end | |
32 | + | |
33 | + should 'be editable for users with permission' do | |
34 | + environment = Environment.default | |
35 | + box = Box.new(:owner => environment) | |
36 | + block = RawHTMLBlock.new(:html => "HTML", :box => box) | |
37 | + user = create_user_with_permission('testuser', 'edit_raw_html_block', environment) | |
38 | + assert block.editable?(user) | |
39 | + end | |
40 | + | |
25 | 41 | end | ... | ... |
test/unit/uploaded_file_test.rb
... | ... | @@ -357,4 +357,25 @@ class UploadedFileTest < ActiveSupport::TestCase |
357 | 357 | assert_instance_of Fixnum, UploadedFile.max_size |
358 | 358 | end |
359 | 359 | |
360 | + should 'add file to dbm if it becomes private' do | |
361 | + require 'sdbm' | |
362 | + public_file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true) | |
363 | + private_file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile, :published => false) | |
364 | + | |
365 | + dbm = SDBM.open(UploadedFile::DBM_PRIVATE_FILE) | |
366 | + assert !dbm.has_key?(public_file.public_filename) | |
367 | + assert dbm.has_key?(private_file.public_filename) | |
368 | + dbm.close | |
369 | + | |
370 | + public_file.published = false | |
371 | + public_file.save! | |
372 | + private_file.published = true | |
373 | + private_file.save! | |
374 | + | |
375 | + dbm = SDBM.open(UploadedFile::DBM_PRIVATE_FILE) | |
376 | + assert dbm.has_key?(public_file.public_filename) | |
377 | + assert !dbm.has_key?(private_file.public_filename) | |
378 | + dbm.close | |
379 | + end | |
380 | + | |
360 | 381 | end | ... | ... |
util/chat/apache/xmpp.conf
... | ... | @@ -1,11 +0,0 @@ |
1 | -# If your XMPP XMPP/BOSH isn't in localhost, change the config below to correct | |
2 | -# point to address | |
3 | - | |
4 | - RewriteEngine On | |
5 | - RewriteRule /http-bind http://localhost:5280/http-bind [P,QSA,L] | |
6 | - <Proxy http://localhost:5280/http-bind> | |
7 | - Order Allow,Deny | |
8 | - Allow from All | |
9 | - </Proxy> | |
10 | - | |
11 | -# vim: ft=apache |
vendor/plugins/access_control/lib/acts_as_accessible.rb
... | ... | @@ -19,9 +19,9 @@ module ActsAsAccessible |
19 | 19 | nil |
20 | 20 | end |
21 | 21 | |
22 | - def affiliate(accessor, roles) | |
22 | + def affiliate(accessor, roles, attributes = {}) | |
23 | 23 | roles = Array(roles) |
24 | - roles.map {|role| accessor.add_role(role, self)}.any? | |
24 | + roles.map {|role| accessor.add_role(role, self, attributes)}.any? | |
25 | 25 | end |
26 | 26 | |
27 | 27 | def disaffiliate(accessor, roles) | ... | ... |
vendor/plugins/access_control/lib/acts_as_accessor.rb
... | ... | @@ -21,9 +21,9 @@ module ActsAsAccessor |
21 | 21 | (actual_roles - roles).each {|r| remove_role(r, resource)} |
22 | 22 | end |
23 | 23 | |
24 | - def add_role(role, resource) | |
25 | - attributes = role_attributes(role, resource) | |
26 | - if RoleAssignment.where(attributes).empty? | |
24 | + def add_role(role, resource, attributes = {}) | |
25 | + attributes = role_attributes(role, resource).merge attributes | |
26 | + if RoleAssignment.find(:all, :conditions => attributes).empty? | |
27 | 27 | ra = RoleAssignment.new(attributes) |
28 | 28 | role_assignments << ra |
29 | 29 | resource.role_assignments << ra |
... | ... | @@ -44,6 +44,19 @@ module ActsAsAccessor |
44 | 44 | RoleAssignment.where(role_attributes nil, res) |
45 | 45 | end |
46 | 46 | |
47 | + def member_relation_of(profile) | |
48 | + raise TypeError, "Expected instance of 'Profile' class, but '#{profile.class.name}' was founded" unless profile.is_a? Profile | |
49 | + | |
50 | + role_assignments.where(resource_id: profile.id) | |
51 | + end | |
52 | + | |
53 | + def member_since_date(profile) | |
54 | + result = member_relation_of(profile).to_a | |
55 | + unless result.empty? | |
56 | + result.last.created_at ? result.last.created_at.to_date : Date.yesterday | |
57 | + end | |
58 | + end | |
59 | + | |
47 | 60 | protected |
48 | 61 | def role_attributes(role, resource) |
49 | 62 | attributes = {:accessor_id => self.id, :accessor_type => self.class.base_class.name} | ... | ... |
vendor/plugins/access_control/lib/role_assignment.rb
1 | 1 | class RoleAssignment < ActiveRecord::Base |
2 | 2 | |
3 | - attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type | |
3 | + attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type, :created_at | |
4 | 4 | |
5 | 5 | belongs_to :role |
6 | 6 | belongs_to :accessor, :polymorphic => true | ... | ... |