Commit 4d9daa44dbf61490640b32a8fb9f6f49f0f8b152

Authored by Rodrigo Souto
2 parents 1fe6b276 4b00dad4
Exists in staging and in 1 other branch production

Merge branch 'master' into staging

Showing 136 changed files with 1279 additions and 399 deletions   Show diff stats
@@ -37,7 +37,7 @@ before_install: @@ -37,7 +37,7 @@ before_install:
37 cache: bundler 37 cache: bundler
38 38
39 before_script: 39 before_script:
40 - - mkdir -p tmp/{pids,cache} log 40 + - mkdir -p tmp/{pids,cache} log cache
41 - script/noosfero-plugins disableall 41 - script/noosfero-plugins disableall
42 #- bundle exec rake makemo &>/dev/null 42 #- bundle exec rake makemo &>/dev/null
43 # database 43 # database
@@ -3,37 +3,30 @@ Noosfero release tasks @@ -3,37 +3,30 @@ Noosfero release tasks
3 3
4 This file documents release-related activities. 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 Releasing noosfero 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 To prepare a release of noosfero, you must follow the steps below: 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 * Make sure all tests pass 19 * Make sure all tests pass
25 -* Write release notes at the version's wiki topic  
26 * Generate packages with `rake noosfero:release[(stable|test)]`. This task will: 20 * Generate packages with `rake noosfero:release[(stable|test)]`. This task will:
27 * Update the version in lib/noosfero.rb and debian/changelog. 21 * Update the version in lib/noosfero.rb and debian/changelog.
28 * Create the tarbal and the deb pkg under pkg/ directory. 22 * Create the tarbal and the deb pkg under pkg/ directory.
29 * Create a git tag and push it. 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 * Test that the tarball and deb package are ok 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 * Update an eventual demonstration version that you run. 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,12 +83,9 @@ class BoxOrganizerController < ApplicationController
83 83
84 def save 84 def save
85 @block = boxes_holder.blocks.find(params[:id]) 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 end 89 end
93 90
94 def boxes_editor? 91 def boxes_editor?
app/controllers/my_profile/cms_controller.rb
@@ -32,7 +32,8 @@ class CmsController < MyProfileController @@ -32,7 +32,8 @@ class CmsController < MyProfileController
32 end 32 end
33 33
34 protect_if :only => [:new, :upload_files] do |c, user, profile| 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 user && user.can_post_content?(profile, parent) 37 user && user.can_post_content?(profile, parent)
37 end 38 end
38 39
app/controllers/my_profile/profile_members_controller.rb
@@ -2,8 +2,27 @@ class ProfileMembersController < MyProfileController @@ -2,8 +2,27 @@ class ProfileMembersController < MyProfileController
2 protect 'manage_memberships', :profile 2 protect 'manage_memberships', :profile
3 3
4 def index 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 end 26 end
8 27
9 def update_roles 28 def update_roles
@@ -156,4 +175,13 @@ class ProfileMembersController < MyProfileController @@ -156,4 +175,13 @@ class ProfileMembersController < MyProfileController
156 end 175 end
157 end 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 end 187 end
app/controllers/public/account_controller.rb
@@ -198,7 +198,7 @@ class AccountController &lt; ApplicationController @@ -198,7 +198,7 @@ class AccountController &lt; ApplicationController
198 if request.post? 198 if request.post?
199 begin 199 begin
200 unless verify_recaptcha 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 return false 202 return false
203 end 203 end
204 204
app/controllers/public/content_viewer_controller.rb
@@ -68,11 +68,7 @@ class ContentViewerController &lt; ApplicationController @@ -68,11 +68,7 @@ class ContentViewerController &lt; ApplicationController
68 process_comments(params) 68 process_comments(params)
69 69
70 if request.xhr? and params[:comment_order] 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 end 72 end
77 73
78 if params[:slideshow] 74 if params[:slideshow]
@@ -209,8 +205,6 @@ class ContentViewerController &lt; ApplicationController @@ -209,8 +205,6 @@ class ContentViewerController &lt; ApplicationController
209 205
210 def rendered_file_download(view = nil) 206 def rendered_file_download(view = nil)
211 if @page.download? view 207 if @page.download? view
212 - headers['Content-Type'] = @page.mime_type  
213 - headers.merge! @page.download_headers  
214 data = @page.data 208 data = @page.data
215 209
216 # TODO test the condition 210 # TODO test the condition
@@ -218,7 +212,12 @@ class ContentViewerController &lt; ApplicationController @@ -218,7 +212,12 @@ class ContentViewerController &lt; ApplicationController
218 raise "No data for file" 212 raise "No data for file"
219 end 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 return true 221 return true
223 end 222 end
224 223
@@ -244,8 +243,12 @@ class ContentViewerController &lt; ApplicationController @@ -244,8 +243,12 @@ class ContentViewerController &lt; ApplicationController
244 243
245 def get_posts(year = nil, month = nil) 244 def get_posts(year = nil, month = nil)
246 if year && month 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 else 252 else
250 return @page.posts 253 return @page.posts
251 end 254 end
@@ -276,8 +279,12 @@ class ContentViewerController &lt; ApplicationController @@ -276,8 +279,12 @@ class ContentViewerController &lt; ApplicationController
276 @comments = @page.comments.without_spam 279 @comments = @page.comments.without_spam
277 @comments = @plugins.filter(:unavailable_comments, @comments) 280 @comments = @plugins.filter(:unavailable_comments, @comments)
278 @comments_count = @comments.count 281 @comments_count = @comments.count
279 - @comments = @comments.without_reply.paginate(:per_page => per_page, :page => params[:comment_page] )  
280 @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order] 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 end 288 end
282 289
283 private 290 private
app/controllers/public/profile_controller.rb
@@ -155,6 +155,18 @@ class ProfileController &lt; PublicController @@ -155,6 +155,18 @@ class ProfileController &lt; PublicController
155 end 155 end
156 end 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 def unblock 170 def unblock
159 if current_user.person.is_admin?(profile.environment) 171 if current_user.person.is_admin?(profile.environment)
160 profile.unblock 172 profile.unblock
@@ -362,6 +374,7 @@ class ProfileController &lt; PublicController @@ -362,6 +374,7 @@ class ProfileController &lt; PublicController
362 def send_mail 374 def send_mail
363 @mailing = profile.mailings.build(params[:mailing]) 375 @mailing = profile.mailings.build(params[:mailing])
364 @email_templates = profile.email_templates.find_all_by_template_type(:organization_members) 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 if request.post? 378 if request.post?
366 @mailing.locale = locale 379 @mailing.locale = locale
367 @mailing.person = user 380 @mailing.person = user
app/helpers/application_helper.rb
@@ -150,14 +150,8 @@ module ApplicationHelper @@ -150,14 +150,8 @@ module ApplicationHelper
150 link_to text, profile_path(:profile => profile) , options 150 link_to text, profile_path(:profile => profile) , options
151 end 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 end 155 end
162 156
163 def link_if_permitted(link, permission = nil, target = nil) 157 def link_if_permitted(link, permission = nil, target = nil)
@@ -556,14 +550,25 @@ module ApplicationHelper @@ -556,14 +550,25 @@ module ApplicationHelper
556 trigger_class = 'enterprise-trigger' 550 trigger_class = 'enterprise-trigger'
557 end 551 end
558 end 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 links = links_for_balloon(profile) 564 links = links_for_balloon(profile)
561 content_tag('div', content_tag(tag, 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 link_to( 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 content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + 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 profile.url, 572 profile.url,
568 :class => 'profile_link url', 573 :class => 'profile_link url',
569 :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, 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,7 +716,7 @@ module ApplicationHelper
711 class NoosferoFormBuilder < ActionView::Helpers::FormBuilder 716 class NoosferoFormBuilder < ActionView::Helpers::FormBuilder
712 extend ActionView::Helpers::TagHelper 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 # try to guess an id if none given 720 # try to guess an id if none given
716 if field_id.nil? 721 if field_id.nil?
717 field_html =~ /id=['"]([^'"]*)['"]/ 722 field_html =~ /id=['"]([^'"]*)['"]/
@@ -1040,10 +1045,11 @@ module ApplicationHelper @@ -1040,10 +1045,11 @@ module ApplicationHelper
1040 end 1045 end
1041 1046
1042 def search_contents_menu 1047 def search_contents_menu
  1048 + host = environment.default_hostname
1043 links = [ 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 if logged_in? 1054 if logged_in?
1049 links.push(_('New content') => modal_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})})) 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,10 +1061,11 @@ module ApplicationHelper
1055 alias :browse_contents_menu :search_contents_menu 1061 alias :browse_contents_menu :search_contents_menu
1056 1062
1057 def search_people_menu 1063 def search_people_menu
  1064 + host = environment.default_hostname
1058 links = [ 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 if logged_in? 1070 if logged_in?
1064 links.push(_('My friends') => {:href => url_for({:profile => current_user.login, :controller => 'friends'})}) 1071 links.push(_('My friends') => {:href => url_for({:profile => current_user.login, :controller => 'friends'})})
@@ -1071,10 +1078,11 @@ module ApplicationHelper @@ -1071,10 +1078,11 @@ module ApplicationHelper
1071 alias :browse_people_menu :search_people_menu 1078 alias :browse_people_menu :search_people_menu
1072 1079
1073 def search_communities_menu 1080 def search_communities_menu
  1081 + host = environment.default_hostname
1074 links = [ 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 if logged_in? 1087 if logged_in?
1080 links.push(_('My communities') => {:href => url_for({:profile => current_user.login, :controller => 'memberships'})}) 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,4 +169,30 @@ module ArticleHelper
169 _('Edit') 169 _('Edit')
170 end 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 end 198 end
app/helpers/block_helper.rb
@@ -14,6 +14,7 @@ module BlockHelper @@ -14,6 +14,7 @@ module BlockHelper
14 </td> 14 </td>
15 <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td> 15 <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td>
16 <td>#{text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 1}</td> 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 </tr><tr class=\"image-title\" data-row-number='#{row_number}'> 18 </tr><tr class=\"image-title\" data-row-number='#{row_number}'>
18 <td colspan=\"3\"><label>#{ 19 <td colspan=\"3\"><label>#{
19 content_tag('span', _('Title')) + 20 content_tag('span', _('Title')) +
app/helpers/boxes_helper.rb
@@ -250,7 +250,7 @@ module BoxesHelper @@ -250,7 +250,7 @@ module BoxesHelper
250 end 250 end
251 end 251 end
252 252
253 - if editable?(block) 253 + if editable?(block, user)
254 buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id }) 254 buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
255 end 255 end
256 256
@@ -296,7 +296,7 @@ module BoxesHelper @@ -296,7 +296,7 @@ module BoxesHelper
296 return block.movable? || user.is_admin? 296 return block.movable? || user.is_admin?
297 end 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 end 301 end
302 end 302 end
app/helpers/forms_helper.rb
@@ -7,9 +7,10 @@ module FormsHelper @@ -7,9 +7,10 @@ module FormsHelper
7 7
8 def labelled_check_box( human_name, name, value = "1", checked = false, options = {} ) 8 def labelled_check_box( human_name, name, value = "1", checked = false, options = {} )
9 options[:id] ||= 'checkbox-' + FormsHelper.next_id_number 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 end 14 end
14 15
15 def labelled_text_field( human_name, name, value=nil, options={} ) 16 def labelled_text_field( human_name, name, value=nil, options={} )
app/mailers/mailing.rb
@@ -2,7 +2,10 @@ require_dependency &#39;mailing_job&#39; @@ -2,7 +2,10 @@ require_dependency &#39;mailing_job&#39;
2 2
3 class Mailing < ActiveRecord::Base 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 validates_presence_of :source_id, :subject, :body 9 validates_presence_of :source_id, :subject, :body
7 belongs_to :source, :foreign_key => :source_id, :polymorphic => true 10 belongs_to :source, :foreign_key => :source_id, :polymorphic => true
8 belongs_to :person 11 belongs_to :person
app/mailers/organization_mailing.rb
@@ -5,9 +5,17 @@ class OrganizationMailing &lt; Mailing @@ -5,9 +5,17 @@ class OrganizationMailing &lt; Mailing
5 end 5 end
6 6
7 def recipients(offset=0, limit=100) 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 .where("m.person_id" => nil) 16 .where("m.person_id" => nil)
  17 + end
  18 + result
11 end 19 end
12 20
13 def each_recipient 21 def each_recipient
app/models/article.rb
@@ -8,8 +8,9 @@ class Article &lt; ActiveRecord::Base @@ -8,8 +8,9 @@ class Article &lt; ActiveRecord::Base
8 :accept_comments, :feed, :published, :source, :source_name, 8 :accept_comments, :feed, :published, :source, :source_name,
9 :highlighted, :notify_comments, :display_hits, :slug, 9 :highlighted, :notify_comments, :display_hits, :slug,
10 :external_feed_builder, :display_versions, :external_link, 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 acts_as_having_image 15 acts_as_having_image
15 16
@@ -83,6 +84,10 @@ class Article &lt; ActiveRecord::Base @@ -83,6 +84,10 @@ class Article &lt; ActiveRecord::Base
83 84
84 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc' 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 has_many :article_categorizations, -> { where 'articles_categories.virtual = ?', false } 91 has_many :article_categorizations, -> { where 'articles_categories.virtual = ?', false }
87 has_many :categories, :through => :article_categorizations 92 has_many :categories, :through => :article_categorizations
88 93
@@ -95,7 +100,6 @@ class Article &lt; ActiveRecord::Base @@ -95,7 +100,6 @@ class Article &lt; ActiveRecord::Base
95 settings_items :author_name, :type => :string, :default => "" 100 settings_items :author_name, :type => :string, :default => ""
96 settings_items :allow_members_to_edit, :type => :boolean, :default => false 101 settings_items :allow_members_to_edit, :type => :boolean, :default => false
97 settings_items :moderate_comments, :type => :boolean, :default => false 102 settings_items :moderate_comments, :type => :boolean, :default => false
98 - settings_items :followers, :type => Array, :default => []  
99 has_and_belongs_to_many :article_privacy_exceptions, :class_name => 'Person', :join_table => 'article_privacy_exceptions' 103 has_and_belongs_to_many :article_privacy_exceptions, :class_name => 'Person', :join_table => 'article_privacy_exceptions'
100 104
101 belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id' 105 belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id'
@@ -173,7 +177,6 @@ class Article &lt; ActiveRecord::Base @@ -173,7 +177,6 @@ class Article &lt; ActiveRecord::Base
173 end 177 end
174 end 178 end
175 179
176 -  
177 def is_trackable? 180 def is_trackable?
178 self.published? && self.notifiable? && self.advertise? && self.profile.public_profile 181 self.published? && self.notifiable? && self.advertise? && self.profile.public_profile
179 end 182 end
@@ -374,6 +377,10 @@ class Article &lt; ActiveRecord::Base @@ -374,6 +377,10 @@ class Article &lt; ActiveRecord::Base
374 self.parent and self.parent.forum? 377 self.parent and self.parent.forum?
375 end 378 end
376 379
  380 + def person_followers_email_list
  381 + person_followers_emails.map{|p|p.email}
  382 + end
  383 +
377 def info_from_last_update 384 def info_from_last_update
378 last_comment = comments.last 385 last_comment = comments.last
379 if last_comment 386 if last_comment
@@ -383,6 +390,10 @@ class Article &lt; ActiveRecord::Base @@ -383,6 +390,10 @@ class Article &lt; ActiveRecord::Base
383 end 390 end
384 end 391 end
385 392
  393 + def full_path
  394 + profile.hostname.blank? ? "/#{profile.identifier}/#{path}" : "/#{path}"
  395 + end
  396 +
386 def url 397 def url
387 @url ||= self.profile.url.merge(:page => path.split('/')) 398 @url ||= self.profile.url.merge(:page => path.split('/'))
388 end 399 end
@@ -408,13 +419,19 @@ class Article &lt; ActiveRecord::Base @@ -408,13 +419,19 @@ class Article &lt; ActiveRecord::Base
408 end 419 end
409 420
410 def download? view = nil 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 end 431 end
415 432
416 def download_headers 433 def download_headers
417 - {} 434 + { :filename => filename, :type => mime_type, :disposition => download_disposition}
418 end 435 end
419 436
420 def alternate_languages 437 def alternate_languages
app/models/block.rb
@@ -195,8 +195,8 @@ class Block &lt; ActiveRecord::Base @@ -195,8 +195,8 @@ class Block &lt; ActiveRecord::Base
195 nil 195 nil
196 end 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 self.edit_modes == "all" 200 self.edit_modes == "all"
201 end 201 end
202 202
app/models/comment.rb
@@ -6,13 +6,14 @@ class Comment &lt; ActiveRecord::Base @@ -6,13 +6,14 @@ class Comment &lt; ActiveRecord::Base
6 :body => {:label => _('Content'), :weight => 2}, 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 validates_presence_of :body 11 validates_presence_of :body
12 12
13 belongs_to :source, :counter_cache => true, :polymorphic => true 13 belongs_to :source, :counter_cache => true, :polymorphic => true
14 alias :article :source 14 alias :article :source
15 alias :article= :source= 15 alias :article= :source=
  16 + attr_accessor :follow_article
16 17
17 belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' 18 belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id'
18 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy 19 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
@@ -102,10 +103,9 @@ class Comment &lt; ActiveRecord::Base @@ -102,10 +103,9 @@ class Comment &lt; ActiveRecord::Base
102 103
103 after_create :new_follower 104 after_create :new_follower
104 def new_follower 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 article.save 109 article.save
110 end 110 end
111 end 111 end
@@ -147,7 +147,7 @@ class Comment &lt; ActiveRecord::Base @@ -147,7 +147,7 @@ class Comment &lt; ActiveRecord::Base
147 if !notification_emails.empty? 147 if !notification_emails.empty?
148 CommentNotifier.notification(self).deliver 148 CommentNotifier.notification(self).deliver
149 end 149 end
150 - emails = article.followers - [author_email] 150 + emails = article.person_followers_email_list - [author_email]
151 if !emails.empty? 151 if !emails.empty?
152 CommentNotifier.mail_to_followers(self, emails).deliver 152 CommentNotifier.mail_to_followers(self, emails).deliver
153 end 153 end
app/models/disabled_enterprise_message_block.rb
@@ -19,7 +19,7 @@ class DisabledEnterpriseMessageBlock &lt; Block @@ -19,7 +19,7 @@ class DisabledEnterpriseMessageBlock &lt; Block
19 end 19 end
20 end 20 end
21 21
22 - def editable? 22 + def editable?(user=nil)
23 false 23 false
24 end 24 end
25 25
app/models/environment.rb
@@ -56,6 +56,7 @@ class Environment &lt; ActiveRecord::Base @@ -56,6 +56,7 @@ class Environment &lt; ActiveRecord::Base
56 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'), 56 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'),
57 'edit_appearance' => N_('Edit appearance'), 57 'edit_appearance' => N_('Edit appearance'),
58 'manage_email_templates' => N_('Manage Email Templates'), 58 'manage_email_templates' => N_('Manage Email Templates'),
  59 + 'edit_raw_html_block' => N_('Edit Raw HTML block'),
59 } 60 }
60 61
61 module Roles 62 module Roles
app/models/highlights_block.rb
@@ -15,6 +15,8 @@ class HighlightsBlock &lt; Block @@ -15,6 +15,8 @@ class HighlightsBlock &lt; Block
15 if !Noosfero.root.nil? and !i[:address].start_with?(Noosfero.root + '/') 15 if !Noosfero.root.nil? and !i[:address].start_with?(Noosfero.root + '/')
16 i[:address] = Noosfero.root + i[:address] 16 i[:address] = Noosfero.root + i[:address]
17 end 17 end
  18 + i[:new_window] = i[:new_window] == '1' ? true : false
  19 +
18 begin 20 begin
19 file = UploadedFile.find(i[:image_id]) 21 file = UploadedFile.find(i[:image_id])
20 i[:image_src] = file.public_filename 22 i[:image_src] = file.public_filename
app/models/person.rb
1 # A person is the profile of an user holding all relationships with the rest of the system 1 # A person is the profile of an user holding all relationships with the rest of the system
2 class Person < Profile 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 SEARCH_FILTERS = { 6 SEARCH_FILTERS = {
10 :order => %w[more_recent more_popular more_active], 7 :order => %w[more_recent more_popular more_active],
@@ -19,26 +16,29 @@ class Person &lt; Profile @@ -19,26 +16,29 @@ class Person &lt; Profile
19 acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)} 16 acts_as_trackable :after_add => Proc.new {|p,t| notify_activity(t)}
20 acts_as_accessor 17 acts_as_accessor
21 18
22 - scope :members_of, -> resources { 19 + scope :members_of, lambda { |resources, field = ''|
23 resources = Array(resources) 20 resources = Array(resources)
  21 + joins = [:role_assignments]
  22 + joins << :user if User.attribute_names.include? field
  23 +
24 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') 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 scope :not_members_of, -> resources { 28 scope :not_members_of, -> resources {
29 resources = Array(resources) 29 resources = Array(resources)
30 conditions = resources.map {|resource| "role_assignments.resource_type = '#{resource.class.base_class.name}' AND role_assignments.resource_id = #{resource.id || -1}"}.join(' OR ') 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 scope :by_role, -> roles { 34 scope :by_role, -> roles {
35 roles = Array(roles) 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 scope :not_friends_of, -> resources { 39 scope :not_friends_of, -> resources {
40 resources = Array(resources) 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 scope :visible_for_person, lambda { |person| 44 scope :visible_for_person, lambda { |person|
@@ -51,8 +51,7 @@ class Person &lt; Profile @@ -51,8 +51,7 @@ class Person &lt; Profile
51 ['( roles.key = ? AND role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR ( 51 ['( roles.key = ? AND role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR (
52 ( ( friendships.person_id = ? ) OR (profiles.public_profile = ?)) AND (profiles.visible = ?) )', 'environment_administrator', Profile.name, person.id, person.id, true, true] 52 ( ( friendships.person_id = ? ) OR (profiles.public_profile = ?)) AND (profiles.visible = ?) )', 'environment_administrator', Profile.name, person.id, person.id, true, true]
53 ).uniq 53 ).uniq
54 - }  
55 - 54 + }
56 55
57 def has_permission_with_admin?(permission, resource) 56 def has_permission_with_admin?(permission, resource)
58 return true if resource.blank? || resource.admins.include?(self) 57 return true if resource.blank? || resource.admins.include?(self)
@@ -90,7 +89,8 @@ class Person &lt; Profile @@ -90,7 +89,8 @@ class Person &lt; Profile
90 has_many :article_followers, :dependent => :destroy 89 has_many :article_followers, :dependent => :destroy
91 has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article 90 has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article
92 has_many :comments, :foreign_key => :author_id 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 has_many :friendships, :dependent => :destroy 94 has_many :friendships, :dependent => :destroy
95 has_many :friends, :class_name => 'Person', :through => :friendships 95 has_many :friends, :class_name => 'Person', :through => :friendships
96 96
@@ -123,10 +123,10 @@ class Person &lt; Profile @@ -123,10 +123,10 @@ class Person &lt; Profile
123 scope :more_popular, -> { order 'friends_count DESC' } 123 scope :more_popular, -> { order 'friends_count DESC' }
124 124
125 scope :abusers, -> { 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 scope :non_abusers, -> { 128 scope :non_abusers, -> {
129 - select("DISTINCT profiles.*"). 129 + distinct.select("profiles.*").
130 joins("LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'"). 130 joins("LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'").
131 where("tasks.status != 3 OR tasks.id is NULL") 131 where("tasks.status != 3 OR tasks.id is NULL")
132 } 132 }
@@ -135,6 +135,11 @@ class Person &lt; Profile @@ -135,6 +135,11 @@ class Person &lt; Profile
135 scope :activated, -> { joins(:user).where('users.activation_code IS NULL AND users.activated_at IS NOT NULL') } 135 scope :activated, -> { joins(:user).where('users.activation_code IS NULL AND users.activated_at IS NOT NULL') }
136 scope :deactivated, -> { joins(:user).where('NOT (users.activation_code IS NULL AND users.activated_at IS NOT NULL)') } 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 after_destroy do |person| 143 after_destroy do |person|
139 Friendship.where(friend_id: person.id).each{ |friendship| friendship.destroy } 144 Friendship.where(friend_id: person.id).each{ |friendship| friendship.destroy }
140 end 145 end
app/models/profile.rb
@@ -78,6 +78,9 @@ class Profile &lt; ActiveRecord::Base @@ -78,6 +78,9 @@ class Profile &lt; ActiveRecord::Base
78 def self.organization_member_roles(env_id) 78 def self.organization_member_roles(env_id)
79 all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? || !r.profile_id.nil?} 79 all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? || !r.profile_id.nil?}
80 end 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 def self.all_roles(env_id) 84 def self.all_roles(env_id)
82 Role.where(environment_id: env_id) 85 Role.where(environment_id: env_id)
83 end 86 end
@@ -119,7 +122,7 @@ class Profile &lt; ActiveRecord::Base @@ -119,7 +122,7 @@ class Profile &lt; ActiveRecord::Base
119 include Noosfero::Plugin::HotSpot 122 include Noosfero::Plugin::HotSpot
120 123
121 scope :memberships_of, -> person { 124 scope :memberships_of, -> person {
122 - select('DISTINCT profiles.*'). 125 + distinct.select('profiles.*').
123 joins(:role_assignments). 126 joins(:role_assignments).
124 where('role_assignments.accessor_type = ? AND role_assignments.accessor_id = ?', person.class.base_class.name, person.id) 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 &lt; ActiveRecord::Base @@ -185,15 +188,23 @@ class Profile &lt; ActiveRecord::Base
185 188
186 include TimeScopes 189 include TimeScopes
187 190
188 - def members 191 + def members(by_field = '')
189 scopes = plugins.dispatch_scopes(:organization_members, self) 192 scopes = plugins.dispatch_scopes(:organization_members, self)
190 - scopes << Person.members_of(self) 193 + scopes << Person.members_of(self,by_field)
191 return scopes.first if scopes.size == 1 194 return scopes.first if scopes.size == 1
192 ScopeTool.union *scopes 195 ScopeTool.union *scopes
193 end 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 end 208 end
198 209
199 class << self 210 class << self
@@ -781,13 +792,13 @@ private :generate_url, :url_options @@ -781,13 +792,13 @@ private :generate_url, :url_options
781 end 792 end
782 793
783 # Adds a person as member of this Profile. 794 # Adds a person as member of this Profile.
784 - def add_member(person) 795 + def add_member(person, attributes={})
785 if self.has_members? 796 if self.has_members?
786 if self.closed? && members.count > 0 797 if self.closed? && members.count > 0
787 AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person) 798 AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person)
788 else 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 end 802 end
792 person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } 803 person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel }
793 remove_from_suggestion_list person 804 remove_from_suggestion_list person
@@ -1164,6 +1175,10 @@ private :generate_url, :url_options @@ -1164,6 +1175,10 @@ private :generate_url, :url_options
1164 end 1175 end
1165 end 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 validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true 1182 validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true
1168 def preferred_login_redirection 1183 def preferred_login_redirection
1169 redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login 1184 redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login
app/models/raw_html_block.rb
@@ -19,4 +19,9 @@ class RawHTMLBlock &lt; Block @@ -19,4 +19,9 @@ class RawHTMLBlock &lt; Block
19 def has_macro? 19 def has_macro?
20 true 20 true
21 end 21 end
  22 +
  23 + def editable?(user)
  24 + user.has_permission?('edit_raw_html_block', environment)
  25 + end
  26 +
22 end 27 end
app/models/rss_feed.rb
@@ -65,6 +65,10 @@ class RssFeed &lt; Article @@ -65,6 +65,10 @@ class RssFeed &lt; Article
65 'text/xml' 65 'text/xml'
66 end 66 end
67 67
  68 + def download?(view = nil)
  69 + true
  70 + end
  71 +
68 include Rails.application.routes.url_helpers 72 include Rails.application.routes.url_helpers
69 def fetch_articles 73 def fetch_articles
70 if parent && parent.has_posts? 74 if parent && parent.has_posts?
app/models/uploaded_file.rb
@@ -2,6 +2,9 @@ @@ -2,6 +2,9 @@
2 # 2 #
3 # Limitation: only file metadata are versioned. Only the latest version 3 # Limitation: only file metadata are versioned. Only the latest version
4 # of the file itself is kept. (FIXME?) 4 # of the file itself is kept. (FIXME?)
  5 +
  6 +require 'sdbm'
  7 +
5 class UploadedFile < Article 8 class UploadedFile < Article
6 9
7 attr_accessible :uploaded_data, :title 10 attr_accessible :uploaded_data, :title
@@ -10,6 +13,19 @@ class UploadedFile &lt; Article @@ -10,6 +13,19 @@ class UploadedFile &lt; Article
10 _('File') 13 _('File')
11 end 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 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 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 def title 31 def title
@@ -106,10 +122,13 @@ class UploadedFile &lt; Article @@ -106,10 +122,13 @@ class UploadedFile &lt; Article
106 self.name ||= self.filename 122 self.name ||= self.filename
107 end 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 end 132 end
114 133
115 def data 134 def data
app/views/account/forgot_password.html.erb
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 <%= form_tag({:action => 'forgot_password'}, :method => 'post', :id => 'forgot-password-form') do %> 5 <%= form_tag({:action => 'forgot_password'}, :method => 'post', :id => 'forgot-password-form') do %>
6 <%= labelled_form_field fields_label, text_field_tag(:value) %> 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 <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> 9 <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %>
10 10
11 <div> 11 <div>
app/views/account/index.html.erb
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 </p> 11 </p>
12 12
13 <p> 13 <p>
14 -<%= link_to_homepage(_('My home page.')) %> 14 +<%= link_to_homepage(_('My home page.'), user) %>
15 <%= _('See your homepage.') %> 15 <%= _('See your homepage.') %>
16 </p> 16 </p>
17 17
app/views/blocks/highlights.html.erb
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <div class='highlights-border'> 3 <div class='highlights-border'>
4 <div class='highlights-container'> 4 <div class='highlights-container'>
5 <% block.featured_images.each do |img| %> 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 <%= image_tag [Noosfero.root, img[:image_src]].join, alt: img[:title] %> 7 <%= image_tag [Noosfero.root, img[:image_src]].join, alt: img[:title] %>
8 <p class="highlights-label"><%= img[:title] %></p> 8 <p class="highlights-label"><%= img[:title] %></p>
9 </a> 9 </a>
app/views/box_organizer/_highlights_block.html.erb
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 <strong><%= _('Highlights') %></strong> 3 <strong><%= _('Highlights') %></strong>
4 4
5 <table class="noborder"><tbody id="highlights-data-table"> 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 <% @block.images.each_with_index do |image, index| %> 7 <% @block.images.each_with_index do |image, index| %>
8 <%= highlights_block_config_image_fields @block, image, index %> 8 <%= highlights_block_config_image_fields @block, image, index %>
9 <% end %> 9 <% end %>
app/views/cms/_drag_and_drop_note.html.erb
1 <p> 1 <p>
2 <em> 2 <em>
3 - <%= _('Drag images to add them to the text.') %>  
4 - <%= _('Click on file names to add links to the text.') %> 3 + <%= _('Drag images to add them to the text or click on file names to add links to the text.') %>
5 </em> 4 </em>
6 </p> 5 </p>
app/views/cms/_text_editor_sidebar.html.erb
@@ -17,8 +17,8 @@ @@ -17,8 +17,8 @@
17 :parent_id, profile, default_folder, {}, {}, 17 :parent_id, profile, default_folder, {}, {},
18 "type='Folder' or type='Gallery'" 18 "type='Folder' or type='Gallery'"
19 ) %> 19 ) %>
  20 + <%= button(:newfolder, _('New folder'), '#', :id => 'new-folder-button') %>
20 </div> 21 </div>
21 - <%= button(:newfolder, _('New folder'), '#', :id => 'new-folder-button') %>  
22 <p><%= file_field_tag('file', :multiple => true) %></p> 22 <p><%= file_field_tag('file', :multiple => true) %></p>
23 <% end %> 23 <% end %>
24 </div> 24 </div>
@@ -31,7 +31,7 @@ @@ -31,7 +31,7 @@
31 <div id='published-media' class='text-editor-sidebar-box' data-url='<%= url_for({:controller => 'cms', :action => 'published_media_items', :profile => profile.identifier}) %>'> 31 <div id='published-media' class='text-editor-sidebar-box' data-url='<%= url_for({:controller => 'cms', :action => 'published_media_items', :profile => profile.identifier}) %>'>
32 <%= select_profile_folder(nil, :parent_id, profile, 'recent-media', {}, {}, 32 <%= select_profile_folder(nil, :parent_id, profile, 'recent-media', {}, {},
33 "type='Folder' or type='Gallery'", {:root_label => _('Recent media')}) %> 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 <%= render :partial => 'drag_and_drop_note' %> 35 <%= render :partial => 'drag_and_drop_note' %>
36 <div class='items'> 36 <div class='items'>
37 <%= render :partial => 'published_media_items' %> 37 <%= render :partial => 'published_media_items' %>
app/views/comment/_comment_form.html.erb
@@ -77,6 +77,10 @@ function check_captcha(button, confirm_action) { @@ -77,6 +77,10 @@ function check_captcha(button, confirm_action) {
77 <%= labelled_form_field(_('Title'), f.text_field(:title)) %> 77 <%= labelled_form_field(_('Title'), f.text_field(:title)) %>
78 <%= required labelled_form_field(_('Enter your comment'), f.text_area(:body, :rows => 5)) %> 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 <%= hidden_field_tag(:confirm, 'false') %> 84 <%= hidden_field_tag(:confirm, 'false') %>
81 <%= hidden_field_tag(:view, params[:view])%> 85 <%= hidden_field_tag(:view, params[:view])%>
82 <%= f.hidden_field(:reply_of_id) %> 86 <%= f.hidden_field(:reply_of_id) %>
app/views/comment/_comments_with_pagination.html.erb 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +<% if @comments.present? %>
  2 + <%= render :partial => 'comment/comment', :collection => @comments %>
  3 + <%= pagination_links @comments, :param_name => 'comment_page', :params => { :comment_order => @comment_order } %>
  4 +<% end %>
app/views/content_viewer/_article_toolbar.html.erb
@@ -57,6 +57,8 @@ @@ -57,6 +57,8 @@
57 <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url], plugin_button[:html_options] %> 57 <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url], plugin_button[:html_options] %>
58 <% end %> 58 <% end %>
59 59
  60 + <%= following_button @page, user %>
  61 +
60 <%= report_abuse(profile, :link, @page) %> 62 <%= report_abuse(profile, :link, @page) %>
61 63
62 </div> 64 </div>
app/views/content_viewer/_publishing_info.html.erb
@@ -10,6 +10,24 @@ @@ -10,6 +10,24 @@
10 <%= (" - %s") % link_to_comments(@page)%> 10 <%= (" - %s") % link_to_comments(@page)%>
11 </span> 11 </span>
12 <% end %> 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 </span> 31 </span>
14 32
15 <% if @page.display_hits? || @page.license.present? %> 33 <% if @page.display_hits? || @page.license.present? %>
app/views/content_viewer/view_page.html.erb
@@ -81,7 +81,7 @@ @@ -81,7 +81,7 @@
81 <ul class="article-comments-list"> 81 <ul class="article-comments-list">
82 <% if @comments.present? %> 82 <% if @comments.present? %>
83 <%= render :partial => 'comment/comment', :collection => @comments %> 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 <% end %> 85 <% end %>
86 </ul> 86 </ul>
87 87
app/views/file_presenter/_generic.html.erb
@@ -2,4 +2,4 @@ @@ -2,4 +2,4 @@
2 <%= generic.abstract %> 2 <%= generic.abstract %>
3 </div> 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,7 +9,8 @@
9 </div> 9 </div>
10 <ul class="profile-list-<%= role %>" > 10 <ul class="profile-list-<%= role %>" >
11 <% users.each do |u| %> 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 <% end %> 14 <% end %>
14 </ul> 15 </ul>
15 16
app/views/profile/members.html.erb
@@ -19,7 +19,6 @@ @@ -19,7 +19,6 @@
19 :id => "members-tab", 19 :id => "members-tab",
20 :content => div_members 20 :content => div_members
21 } %> 21 } %>
22 -  
23 <% div_admins = content_tag :div, :class => "profile-admins" do 22 <% div_admins = content_tag :div, :class => "profile-admins" do
24 render :partial => 'profile_members_list', 23 render :partial => 'profile_members_list',
25 :locals => { 24 :locals => {
app/views/profile/send_mail.html.erb
@@ -10,6 +10,9 @@ @@ -10,6 +10,9 @@
10 </div> 10 </div>
11 <% end %> 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 <%= form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %> 16 <%= form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %>
14 17
15 <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %> 18 <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %>
app/views/profile_members/_index_buttons.html.erb
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 <%= button :person, _('Invite people to join'), :controller => 'invite', :action => 'invite_friends' %> 5 <%= button :person, _('Invite people to join'), :controller => 'invite', :action => 'invite_friends' %>
6 <% end %> 6 <% end %>
7 <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %> 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 <% end %> 9 <% end %>
10 <% @plugins.dispatch(:manage_members_extra_buttons).each do |plugin_button| %> 10 <% @plugins.dispatch(:manage_members_extra_buttons).each do |plugin_button| %>
11 <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %> 11 <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %>
app/views/profile_members/_members_filter.erb 0 → 100644
@@ -0,0 +1,18 @@ @@ -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 \ No newline at end of file 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 <% title = @title ? @title : _('Current members') %> 3 <% title = @title ? @title : _('Current members') %>
3 <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %> 4 <% remove_action = @remove_action ? @remove_action : {:action => 'unassociate'} %>
  5 +<%= javascript_include_tag params[:controller] %>
4 6
5 <h3><%= title %></h3> 7 <h3><%= title %></h3>
6 8
7 <table> 9 <table>
  10 + <col width="1">
8 <tr> 11 <tr>
  12 + <th><%= check_box_tag 'checkbox-all', 1, false, :onClick => "toggle(this)" %></th>
9 <th><%= _('Member') %></th> 13 <th><%= _('Member') %></th>
10 <th><%= _('Actions') %></th> 14 <th><%= _('Actions') %></th>
11 </tr> 15 </tr>
  16 +
12 <% collection.each do |m| %> 17 <% collection.each do |m| %>
13 <tr title="<%= m.name %>"> 18 <tr title="<%= m.name %>">
  19 + <td><%= labelled_check_box('', 'members_filtered[]', m.id.to_s, false, :id => 'checkbox-'+m.identifier) %></td>
14 <td><%= link_to_profile m.short_name, m.identifier, :title => m.name %> </td> 20 <td><%= link_to_profile m.short_name, m.identifier, :title => m.name %> </td>
15 <td> 21 <td>
16 <div class="members-buttons-cell"> 22 <div class="members-buttons-cell">
@@ -27,3 +33,8 @@ @@ -27,3 +33,8 @@
27 </tr> 33 </tr>
28 <% end %> 34 <% end %>
29 </table> 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 <h1><%= h profile.short_name(50) %></h1> 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,7 +5,7 @@
5 <ul> 5 <ul>
6 <% for validator in @region.validators %> 6 <% for validator in @region.validators %>
7 <li> 7 <li>
8 - <%= link_to_homepage validator.name, validator.identifier %> 8 + <%= link_to_homepage validator.name, validator %>
9 <%= link_to _('Remove validation rights'), { :action => 'remove', :id => @region.id, :validator_id => validator }, :method => 'post' %> 9 <%= link_to _('Remove validation rights'), { :action => 'remove', :id => @region.id, :validator_id => validator }, :method => 'post' %>
10 </li> 10 </li>
11 <% end %> 11 <% end %>
app/views/search/_full_enterprise.html.erb
@@ -5,7 +5,7 @@ @@ -5,7 +5,7 @@
5 @order == 'more_recent' ? enterprise.send(@order + '_label') + show_date(enterprise.created_at) : enterprise.send(@order + '_label') %> 5 @order == 'more_recent' ? enterprise.send(@order + '_label') + show_date(enterprise.created_at) : enterprise.send(@order + '_label') %>
6 </div> 6 </div>
7 <div class="search-enterprise-item-column-right"> 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 <div class="search-enterprise-description"> 9 <div class="search-enterprise-description">
10 <% if enterprise.description %> 10 <% if enterprise.description %>
11 <% body_stripped = strip_tags(enterprise.description) %> 11 <% body_stripped = strip_tags(enterprise.description) %>
app/views/search/_full_product.html.erb
@@ -44,7 +44,7 @@ @@ -44,7 +44,7 @@
44 <div class="search-product-item-second-column"> 44 <div class="search-product-item-second-column">
45 <%= link_to_product product, :class => 'search-result-title' %> 45 <%= link_to_product product, :class => 'search-result-title' %>
46 <div class="search-product-supplier"> 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 </div> 48 </div>
49 <div class="search-product-description"> 49 <div class="search-product-description">
50 <% if product.description %> 50 <% if product.description %>
app/views/search/_image.html.erb
@@ -26,7 +26,7 @@ @@ -26,7 +26,7 @@
26 <% end %> 26 <% end %>
27 <% elsif image.is_a? Gallery %> 27 <% elsif image.is_a? Gallery %>
28 <div class="search-gallery-items"> 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 <% if r.length > 0 %> 30 <% if r.length > 0 %>
31 <% r.each_index do |i| img = r[i] %> 31 <% r.each_index do |i| img = r[i] %>
32 <%= link_to '', img.view_url, :class => "search-image-pic pic-num#{i+1}", 32 <%= link_to '', img.view_url, :class => "search-image-pic pic-num#{i+1}",
@@ -47,6 +47,8 @@ @@ -47,6 +47,8 @@
47 <% else %> 47 <% else %>
48 <div class="search-no-image"><span><%= _('No image') %></span></div> 48 <div class="search-no-image"><span><%= _('No image') %></span></div>
49 <% end %> 49 <% end %>
  50 + <% elsif image.first_image.present? %>
  51 + <img src="<%= image.first_image %>" class="automatic-abstract-thumb search-image-pic">
50 <% else %> 52 <% else %>
51 <div class="search-content-type-icon icon-content-<%=image.class.to_s.underscore.dasherize%>"></div> 53 <div class="search-content-type-icon icon-content-<%=image.class.to_s.underscore.dasherize%>"></div>
52 <% end %> 54 <% end %>
app/views/user_mailer/activation_code.text.erb
1 <%= _('Hi, %{recipient}!') % { :recipient => @recipient } %> 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 <%= _("Greetings,") %> 5 <%= _("Greetings,") %>
6 6
7 -- 7 --
8 <%= _('%s team.') % @environment.name %> 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 @@ @@ -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
db/migrate/20151105175041_create_article_followers.rb 0 → 100644
@@ -0,0 +1,13 @@ @@ -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 @@ @@ -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
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +class AddTimestampsToRoleAssignments < ActiveRecord::Migration
  2 + def change
  3 + add_timestamps :role_assignments
  4 + end
  5 +end
db/migrate/20160224132937_add_data_to_mailing.rb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +class AddDataToMailing < ActiveRecord::Migration
  2 + def change
  3 + add_column :mailings, :data, :text
  4 + end
  5 +end
@@ -11,7 +11,7 @@ @@ -11,7 +11,7 @@
11 # 11 #
12 # It's strongly recommended that you check this file into your version control system. 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 # These are extensions that must be enabled in order to support this database 16 # These are extensions that must be enabled in order to support this database
17 enable_extension "plpgsql" 17 enable_extension "plpgsql"
@@ -88,9 +88,9 @@ ActiveRecord::Schema.define(version: 20151221105330) do @@ -88,9 +88,9 @@ ActiveRecord::Schema.define(version: 20151221105330) do
88 t.integer "profile_id" 88 t.integer "profile_id"
89 end 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 t.datetime "since" 94 t.datetime "since"
95 t.datetime "created_at" 95 t.datetime "created_at"
96 t.datetime "updated_at" 96 t.datetime "updated_at"
@@ -699,6 +699,7 @@ ActiveRecord::Schema.define(version: 20151221105330) do @@ -699,6 +699,7 @@ ActiveRecord::Schema.define(version: 20151221105330) do
699 t.string "locale" 699 t.string "locale"
700 t.datetime "created_at" 700 t.datetime "created_at"
701 t.datetime "updated_at" 701 t.datetime "updated_at"
  702 + t.text "data"
702 end 703 end
703 704
704 create_table "mark_comment_as_read_plugin", force: :cascade do |t| 705 create_table "mark_comment_as_read_plugin", force: :cascade do |t|
@@ -1071,12 +1072,14 @@ ActiveRecord::Schema.define(version: 20151221105330) do @@ -1071,12 +1072,14 @@ ActiveRecord::Schema.define(version: 20151221105330) do
1071 end 1072 end
1072 1073
1073 create_table "role_assignments", force: :cascade do |t| 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 end 1083 end
1081 1084
1082 create_table "roles", force: :cascade do |t| 1085 create_table "roles", force: :cascade do |t|
debian/apache2/virtualhost.conf
@@ -8,6 +8,19 @@ DocumentRoot &quot;/usr/share/noosfero/public&quot; @@ -8,6 +8,19 @@ DocumentRoot &quot;/usr/share/noosfero/public&quot;
8 8
9 RewriteEngine On 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 # Rewrite index to check for static index.html 24 # Rewrite index to check for static index.html
12 RewriteRule ^/$ /index.html [QSA] 25 RewriteRule ^/$ /index.html [QSA]
13 26
debian/changelog
  1 +noosfero (1.4) jessie-test; urgency=medium
  2 +
  3 + * Noosfero 1.4
  4 +
  5 + -- Antonio Terceiro <terceiro@colivre.coop.br> Thu, 18 Feb 2016 16:20:23 -0200
  6 +
1 noosfero (1.4~rc3) jessie-test; urgency=medium 7 noosfero (1.4~rc3) jessie-test; urgency=medium
2 8
3 * Noosfero 1.4 RC3 9 * Noosfero 1.4 RC3
debian/dbinstall
@@ -5,8 +5,6 @@ set -e @@ -5,8 +5,6 @@ set -e
5 # dbconfig-common uses "pgsql", but we want "postgresql" 5 # dbconfig-common uses "pgsql", but we want "postgresql"
6 sed -i -e 's/adapter: pgsql/adapter: postgresql/' /etc/noosfero/database.yml 6 sed -i -e 's/adapter: pgsql/adapter: postgresql/' /etc/noosfero/database.yml
7 7
8 -/etc/init.d/noosfero setup  
9 -  
10 cd /usr/share/noosfero && su noosfero -c "rake db:schema:load RAILS_ENV=production" 8 cd /usr/share/noosfero && su noosfero -c "rake db:schema:load RAILS_ENV=production"
11 cd /usr/share/noosfero && su noosfero -c "rake db:migrate RAILS_ENV=production SCHEMA=/dev/null" 9 cd /usr/share/noosfero && su noosfero -c "rake db:migrate RAILS_ENV=production SCHEMA=/dev/null"
12 cd /usr/share/noosfero && su noosfero -c "rake db:data:minimal RAILS_ENV=production" 10 cd /usr/share/noosfero && su noosfero -c "rake db:data:minimal RAILS_ENV=production"
debian/dbupgrade
@@ -2,7 +2,5 @@ @@ -2,7 +2,5 @@
2 2
3 set -e 3 set -e
4 4
5 -/etc/init.d/noosfero setup  
6 -  
7 cd /usr/share/noosfero && su noosfero -c "rake db:migrate RAILS_ENV=production SCHEMA=/dev/null" 5 cd /usr/share/noosfero && su noosfero -c "rake db:migrate RAILS_ENV=production SCHEMA=/dev/null"
8 6
debian/noosfero.links
1 var/tmp/noosfero usr/share/noosfero/tmp 1 var/tmp/noosfero usr/share/noosfero/tmp
2 var/log/noosfero usr/share/noosfero/log 2 var/log/noosfero usr/share/noosfero/log
  3 +var/cache/noosfero usr/share/noosfero/cache
3 etc/noosfero/database.yml usr/share/noosfero/config/database.yml 4 etc/noosfero/database.yml usr/share/noosfero/config/database.yml
4 etc/noosfero/unicorn.rb usr/share/noosfero/config/unicorn.rb 5 etc/noosfero/unicorn.rb usr/share/noosfero/config/unicorn.rb
5 etc/noosfero/plugins usr/share/noosfero/config/plugins 6 etc/noosfero/plugins usr/share/noosfero/config/plugins
debian/noosfero.postinst
@@ -68,10 +68,17 @@ if [ ! -z &quot;$RET&quot; ]; then @@ -68,10 +68,17 @@ if [ ! -z &quot;$RET&quot; ]; then
68 export NOOSFERO_DOMAIN="$RET" 68 export NOOSFERO_DOMAIN="$RET"
69 fi 69 fi
70 70
  71 +/etc/init.d/noosfero setup
  72 +
71 # dbconfig-common magic 73 # dbconfig-common magic
72 . /usr/share/dbconfig-common/dpkg/postinst 74 . /usr/share/dbconfig-common/dpkg/postinst
73 dbc_go noosfero $@ 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 # stop debconf to avoid the problem with infinite hanging, cfe 82 # stop debconf to avoid the problem with infinite hanging, cfe
76 # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=295477 83 # http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=295477
77 db_stop 84 db_stop
debian/update-noosfero-apache
@@ -17,13 +17,13 @@ if test -x /usr/share/noosfero/script/apacheconf; then @@ -17,13 +17,13 @@ if test -x /usr/share/noosfero/script/apacheconf; then
17 if ! test -e "$apache_site"; then 17 if ! test -e "$apache_site"; then
18 echo "Generating apache virtual host ..." 18 echo "Generating apache virtual host ..."
19 cd /usr/share/noosfero && su noosfero -c "RAILS_ENV=production ./script/apacheconf virtualhosts" > "$apache_site" 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 fi 27 fi
28 28
29 echo 'Noosfero Apache configuration updated.' 29 echo 'Noosfero Apache configuration updated.'
etc/init.d/noosfero
@@ -86,6 +86,13 @@ do_setup() { @@ -86,6 +86,13 @@ do_setup() {
86 chmod 750 /var/tmp/noosfero 86 chmod 750 /var/tmp/noosfero
87 fi 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 # symlink the directories into Noosfero directory 96 # symlink the directories into Noosfero directory
90 if [ ! -e $NOOSFERO_DIR/tmp ]; then 97 if [ ! -e $NOOSFERO_DIR/tmp ]; then
91 ln -s /var/tmp/noosfero $NOOSFERO_DIR/tmp 98 ln -s /var/tmp/noosfero $NOOSFERO_DIR/tmp
@@ -96,6 +103,9 @@ do_setup() { @@ -96,6 +103,9 @@ do_setup() {
96 if [ ! -e $NOOSFERO_DIR/log ]; then 103 if [ ! -e $NOOSFERO_DIR/log ]; then
97 ln -s /var/log/noosfero $NOOSFERO_DIR/log 104 ln -s /var/log/noosfero $NOOSFERO_DIR/log
98 fi 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 do_start() { 111 do_start() {
features/admin_categories.feature
@@ -45,7 +45,7 @@ Feature: manage categories @@ -45,7 +45,7 @@ Feature: manage categories
45 And I should see "Steak" 45 And I should see "Steak"
46 When I follow "Hide" 46 When I follow "Hide"
47 Then I should not see "Vegetarian" 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 @selenium 50 @selenium
51 Scenario: the show link is available just for categories with category tree 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,6 +44,7 @@ Feature: categories_block
44 And I follow "Edit" within ".block-outer .categories-block" 44 And I follow "Edit" within ".block-outer .categories-block"
45 And I check "Product" 45 And I check "Product"
46 And I press "Save" 46 And I press "Save"
  47 + And I go to /
47 Then I should see "Food" 48 Then I should see "Food"
48 And I should see "Book" 49 And I should see "Book"
49 And "Vegetarian" should not be visible within "span#category-name" 50 And "Vegetarian" should not be visible within "span#category-name"
@@ -62,6 +63,7 @@ Feature: categories_block @@ -62,6 +63,7 @@ Feature: categories_block
62 And I follow "Edit" within ".block-outer .categories-block" 63 And I follow "Edit" within ".block-outer .categories-block"
63 And I check "Product" 64 And I check "Product"
64 And I press "Save" 65 And I press "Save"
  66 + And I go to /
65 Then I should see "Book" 67 Then I should see "Book"
66 And "Literature" should not be visible within "span#category-name" 68 And "Literature" should not be visible within "span#category-name"
67 When I follow "block_2_category_2" 69 When I follow "block_2_category_2"
features/comment.feature
@@ -96,4 +96,4 @@ Feature: comment @@ -96,4 +96,4 @@ Feature: comment
96 Scenario: hide post a comment button when clicked 96 Scenario: hide post a comment button when clicked
97 Given I am on /booking/article-to-comment 97 Given I am on /booking/article-to-comment
98 And I follow "Post a comment" 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,5 +27,7 @@ Feature: manage categories
27 Then I should not see "Beans" 27 Then I should not see "Beans"
28 And I should not see "Potatoes" 28 And I should not see "Potatoes"
29 When I follow "Show" 29 When I follow "Show"
  30 + And I wait 0.5 seconds for Services show animation to finish
  31 + And I follow "Show"
30 Then I should see "Beans" 32 Then I should see "Beans"
31 And I should see "Potatoes" 33 And I should see "Potatoes"
features/manage_users.feature
@@ -15,7 +15,7 @@ Background: @@ -15,7 +15,7 @@ Background:
15 Scenario: deactive user 15 Scenario: deactive user
16 Given I follow "Deactivate user" within "tr[title='Joao Silva']" 16 Given I follow "Deactivate user" within "tr[title='Joao Silva']"
17 When I confirm the browser dialog 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 @selenium 20 @selenium
21 Scenario: activate user 21 Scenario: activate user
@@ -23,7 +23,7 @@ Background: @@ -23,7 +23,7 @@ Background:
23 And I confirm the browser dialog 23 And I confirm the browser dialog
24 And I follow "Activate user" within "tr[title='Paulo Santos']" 24 And I follow "Activate user" within "tr[title='Paulo Santos']"
25 When I confirm the browser dialog 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 @selenium 28 @selenium
29 Scenario: remove user 29 Scenario: remove user
@@ -36,7 +36,7 @@ Background: @@ -36,7 +36,7 @@ Background:
36 Scenario: admin user 36 Scenario: admin user
37 Given I follow "Set admin role" within "tr[title='Joao Silva']" 37 Given I follow "Set admin role" within "tr[title='Joao Silva']"
38 When I confirm the browser dialog 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 @selenium 41 @selenium
42 Scenario: unadmin user 42 Scenario: unadmin user
@@ -44,4 +44,4 @@ Background: @@ -44,4 +44,4 @@ Background:
44 And I confirm the browser dialog 44 And I confirm the browser dialog
45 And I follow "Reset admin role" within "tr[title='Paulo Santos']" 45 And I follow "Reset admin role" within "tr[title='Paulo Santos']"
46 When I confirm the browser dialog 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
@@ -17,6 +17,7 @@ Feature: Use a secret community @@ -17,6 +17,7 @@ Feature: Use a secret community
17 And I check "Secret" 17 And I check "Secret"
18 And I press "Save" 18 And I press "Save"
19 And I follow "Logout" 19 And I follow "Logout"
  20 + And I go to /account/login
20 21
21 @selenium 22 @selenium
22 Scenario: Hide privacity options when secret is checked 23 Scenario: Hide privacity options when secret is checked
features/send_email_to_organization_members.feature
@@ -31,7 +31,8 @@ Feature: send emails to organization members @@ -31,7 +31,8 @@ Feature: send emails to organization members
31 Scenario: Send e-mail to members 31 Scenario: Send e-mail to members
32 Given I am logged in as "joaosilva" 32 Given I am logged in as "joaosilva"
33 And I go to Sample Community's members management 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 And I fill in "Subject" with "Hello, member!" 36 And I fill in "Subject" with "Hello, member!"
36 And I fill in "Body" with "We have some news" 37 And I fill in "Body" with "We have some news"
37 When I press "Send" 38 When I press "Send"
@@ -40,7 +41,8 @@ Feature: send emails to organization members @@ -40,7 +41,8 @@ Feature: send emails to organization members
40 Scenario: Not send e-mail to members if subject is blank 41 Scenario: Not send e-mail to members if subject is blank
41 Given I am logged in as "joaosilva" 42 Given I am logged in as "joaosilva"
42 And I go to Sample Community's members management 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 And I fill in "Body" with "We have some news" 46 And I fill in "Body" with "We have some news"
45 When I press "Send" 47 When I press "Send"
46 Then I should be on /profile/sample-community/send_mail 48 Then I should be on /profile/sample-community/send_mail
@@ -48,7 +50,8 @@ Feature: send emails to organization members @@ -48,7 +50,8 @@ Feature: send emails to organization members
48 Scenario: Not send e-mail to members if body is blank 50 Scenario: Not send e-mail to members if body is blank
49 Given I am logged in as "joaosilva" 51 Given I am logged in as "joaosilva"
50 And I go to Sample Community's members management 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 And I fill in "Subject" with "Hello, user!" 55 And I fill in "Subject" with "Hello, user!"
53 When I press "Send" 56 When I press "Send"
54 Then I should be on /profile/sample-community/send_mail 57 Then I should be on /profile/sample-community/send_mail
@@ -56,7 +59,8 @@ Feature: send emails to organization members @@ -56,7 +59,8 @@ Feature: send emails to organization members
56 Scenario: Cancel creation of mailing 59 Scenario: Cancel creation of mailing
57 Given I am logged in as "joaosilva" 60 Given I am logged in as "joaosilva"
58 And I go to Sample Community's members management 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 When I follow "Cancel e-mail" 64 When I follow "Cancel e-mail"
61 Then I should be on Sample Community's members management 65 Then I should be on Sample Community's members management
62 66
features/step_definitions/custom_web_steps.rb
1 Then /^"([^"]*)" should not be visible within "([^"]*)"$/ do |text, selector| 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 end 3 end
6 4
7 Then /^"([^"]*)" should be visible within "([^"]*)"$/ do |text, selector| 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 end 7 end
12 8
13 Then /^I should see "([^"]*)" link$/ do |text| 9 Then /^I should see "([^"]*)" link$/ do |text|
@@ -22,14 +18,14 @@ When /^I should see &quot;([^\&quot;]+)&quot; linking to &quot;([^\&quot;]+)&quot;$/ do |text, href| @@ -22,14 +18,14 @@ When /^I should see &quot;([^\&quot;]+)&quot; linking to &quot;([^\&quot;]+)&quot;$/ do |text, href|
22 page.should have_xpath("//a[@href='#{href}']") 18 page.should have_xpath("//a[@href='#{href}']")
23 end 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 end 29 end
34 30
35 When /^I reload and wait for the page$/ do 31 When /^I reload and wait for the page$/ do
features/step_definitions/web_steps.rb
@@ -7,7 +7,7 @@ @@ -7,7 +7,7 @@
7 7
8 require 'uri' 8 require 'uri'
9 require 'cgi' 9 require 'cgi'
10 -require File.expand_path(File.join(File.dirname(__FILE__), "..", "support", "paths")) 10 +require_relative '../support/paths'
11 11
12 module WithinHelpers 12 module WithinHelpers
13 def with_scope(locator) 13 def with_scope(locator)
@@ -39,37 +39,15 @@ end @@ -39,37 +39,15 @@ end
39 39
40 When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector| 40 When /^(?:|I )follow "([^"]*)"(?: within "([^"]*)")?$/ do |link, selector|
41 with_scope(selector) do 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 end 49 end
  50 + target.click
73 end 51 end
74 end 52 end
75 53
features/support/debug.rb
@@ -21,3 +21,8 @@ Before do |scenario| @@ -21,3 +21,8 @@ Before do |scenario|
21 puts "Can't find debugger or pry to debug" 21 puts "Can't find debugger or pry to debug"
22 end 22 end
23 end 23 end
  24 +
  25 +Then /^I open pry$/ do
  26 + require'pry';binding.pry
  27 +end
  28 +
features/support/env.rb
@@ -65,5 +65,13 @@ Before do @@ -65,5 +65,13 @@ Before do
65 fixtures_folder = Rails.root.join('test', 'fixtures') 65 fixtures_folder = Rails.root.join('test', 'fixtures')
66 fixtures = ['environments', 'roles'] 66 fixtures = ['environments', 'roles']
67 ActiveRecord::Fixtures.create_fixtures(fixtures_folder, fixtures) 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 end 76 end
69 77
gitignore.example
@@ -22,6 +22,7 @@ public/thumbnails @@ -22,6 +22,7 @@ public/thumbnails
22 public/user_themes 22 public/user_themes
23 public/designs/themes/default 23 public/designs/themes/default
24 public/designs/icons/default 24 public/designs/icons/default
  25 +cache
25 26
26 public/assets 27 public/assets
27 .sass-cache 28 .sass-cache
lib/file_presenter.rb
@@ -52,8 +52,8 @@ class FilePresenter @@ -52,8 +52,8 @@ class FilePresenter
52 nil 52 nil
53 end 53 end
54 54
55 - def download?(view=nil)  
56 - false 55 + def download? view = nil
  56 + view.blank?
57 end 57 end
58 58
59 def short_description 59 def short_description
lib/noosfero/api/v1/articles.rb
@@ -165,6 +165,37 @@ module Noosfero @@ -165,6 +165,37 @@ module Noosfero
165 end 165 end
166 end 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 desc 'Return the children of a article identified by id' do 199 desc 'Return the children of a article identified by id' do
169 detail 'Get all children articles of a specific article' 200 detail 'Get all children articles of a specific article'
170 params Noosfero::API::Entities::Article.documentation 201 params Noosfero::API::Entities::Article.documentation
lib/noosfero/version.rb
1 module Noosfero 1 module Noosfero
2 PROJECT = 'noosfero' 2 PROJECT = 'noosfero'
3 - VERSION = '1.4~rc3' 3 + VERSION = '1.4'
4 end 4 end
5 5
6 root = File.expand_path(File.dirname(__FILE__) + '/../..') 6 root = File.expand_path(File.dirname(__FILE__) + '/../..')
lib/noosfero/vote_ext.rb
@@ -2,10 +2,10 @@ require_dependency &#39;models/vote&#39; @@ -2,10 +2,10 @@ require_dependency &#39;models/vote&#39;
2 2
3 class Vote 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 end 9 end
10 10
11 validate :verify_target_archived 11 validate :verify_target_archived
lib/tasks/cache.rake 0 → 100644
@@ -0,0 +1,14 @@ @@ -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 require_dependency 'profile' 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 end 8 end
plugins/organization_ratings/features/rate_community.feature
@@ -33,4 +33,4 @@ Feature: rate_community @@ -33,4 +33,4 @@ Feature: rate_community
33 Given I am on mycommunity's homepage 33 Given I am on mycommunity's homepage
34 When I follow "Rate this Community" 34 When I follow "Rate this Community"
35 Then I should see "Joao Silva" within ".star-profile-name" 35 Then I should see "Joao Silva" within ".star-profile-name"
36 - And I should see Joao Silva's profile image  
37 \ No newline at end of file 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 @@ @@ -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
@@ -73,8 +73,8 @@ class OrganizationRatingsPlugin &lt; Noosfero::Plugin @@ -73,8 +73,8 @@ class OrganizationRatingsPlugin &lt; Noosfero::Plugin
73 73
74 def js_files 74 def js_files
75 %w( 75 %w(
76 - public/rate.js  
77 - public/organization_rating_management.js 76 + rate.js
  77 + organization_rating_management.js
78 ) 78 )
79 end 79 end
80 80
plugins/organization_ratings/public/organization_rating_management.js
@@ -9,8 +9,8 @@ @@ -9,8 +9,8 @@
9 9
10 10
11 cacheDom: function() { 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,10 +21,22 @@
21 21
22 verifyHoursTimerDisable: function() { 22 verifyHoursTimerDisable: function() {
23 if (this.$vote_once_checkbox.is(":checked")) { 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 } else { 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,11 +14,11 @@
14 } 14 }
15 15
16 .star-negative { 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 .star-positive { 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 .small-star-negative, .small-star-positive { 24 .small-star-negative, .small-star-positive {
@@ -31,11 +31,11 @@ @@ -31,11 +31,11 @@
31 } 31 }
32 32
33 .small-star-negative { 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 .small-star-positive { 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 .medium-star-negative, .medium-star-positive { 41 .medium-star-negative, .medium-star-positive {
@@ -48,11 +48,11 @@ @@ -48,11 +48,11 @@
48 } 48 }
49 49
50 .medium-star-positive { 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 .medium-star-negative { 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 .star-hide { 58 .star-hide {
plugins/people_block/lib/ext/person.rb
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -require_dependency 'person'  
2 -  
3 -class Person  
4 -  
5 - scope :with_role, -> role_id {  
6 - joins(:role_assignments).  
7 - where("role_assignments.role_id = #{role_id}")  
8 - }  
9 -  
10 -end  
plugins/people_block/test/unit/members_block_test.rb
@@ -280,6 +280,21 @@ class MembersBlockTest &lt; ActionView::TestCase @@ -280,6 +280,21 @@ class MembersBlockTest &lt; ActionView::TestCase
280 assert_includes block.roles, Profile::Roles.moderator(owner.environment.id) 280 assert_includes block.roles, Profile::Roles.moderator(owner.environment.id)
281 end 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 protected 298 protected
284 include NoosferoTestHelper 299 include NoosferoTestHelper
285 300
plugins/pg_search/test/unit/pg_search_plugin_test.rb
@@ -25,7 +25,8 @@ class PgSearchPluginTest &lt; ActiveSupport::TestCase @@ -25,7 +25,8 @@ class PgSearchPluginTest &lt; ActiveSupport::TestCase
25 profile1 = fast_create(Profile, :identifier => 'profile1', :name => 'debugger') 25 profile1 = fast_create(Profile, :identifier => 'profile1', :name => 'debugger')
26 profile2 = fast_create(Profile, :identifier => 'profile2', :name => 'profile admin debugger') 26 profile2 = fast_create(Profile, :identifier => 'profile2', :name => 'profile admin debugger')
27 profile3 = fast_create(Profile, :identifier => 'profile3', :name => 'admin debugger') 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 end 30 end
30 31
31 should 'locate profile escaping special characters' do 32 should 'locate profile escaping special characters' do
plugins/site_tour/lib/ext/person.rb
1 -class Person 1 +require_dependency 'person'
2 2
  3 +class Person
3 settings_items :site_tour_plugin_actions, :type => Array, :default => [] 4 settings_items :site_tour_plugin_actions, :type => Array, :default => []
4 -  
5 end 5 end
plugins/stoa/test/functional/account_controller_test.rb
@@ -15,6 +15,7 @@ class AccountControllerTest &lt; ActionController::TestCase @@ -15,6 +15,7 @@ class AccountControllerTest &lt; ActionController::TestCase
15 t.date "dtanas" 15 t.date "dtanas"
16 end 16 end
17 ActiveRecord::Base.establish_connection(:test) 17 ActiveRecord::Base.establish_connection(:test)
  18 + StoaPlugin::UspUser.reset_column_information
18 19
19 def setup 20 def setup
20 @controller = AccountController.new 21 @controller = AccountController.new
plugins/sub_organizations/views/sub_organizations_plugin_profile/_full_related_organizations.html.erb
@@ -10,7 +10,7 @@ @@ -10,7 +10,7 @@
10 <%= profile_image_link organization, :big, 'div' %> 10 <%= profile_image_link organization, :big, 'div' %>
11 </div> 11 </div>
12 <div class="related-organizations-item-column-right"> 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 <div class="related-organizations-description"> 14 <div class="related-organizations-description">
15 <% if organization.description %> 15 <% if organization.description %>
16 <% body_stripped = strip_tags(organization.description) %> 16 <% body_stripped = strip_tags(organization.description) %>
plugins/video/lib/video_plugin.rb
@@ -33,10 +33,14 @@ class VideoPlugin &lt; Noosfero::Plugin @@ -33,10 +33,14 @@ class VideoPlugin &lt; Noosfero::Plugin
33 end 33 end
34 34
35 def article_extra_toolbar_buttons(content) 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 end 44 end
41 45
42 end 46 end
plugins/video/views/content_viewer/video_plugin/_video_gallery.html.erb
@@ -11,4 +11,4 @@ @@ -11,4 +11,4 @@
11 <em><%= _('(empty video gallery)') %></em> 11 <em><%= _('(empty video gallery)') %></em>
12 <% else %> 12 <% else %>
13 <%= list_videos(:contents=>video_gallery.children) %> 13 <%= list_videos(:contents=>video_gallery.children) %>
14 -<% end %>  
15 \ No newline at end of file 14 \ No newline at end of file
  15 +<% end %>
public/designs/themes/noosfero/style.css
@@ -48,3 +48,9 @@ @@ -48,3 +48,9 @@
48 width: 80px; 48 width: 80px;
49 } 49 }
50 50
  51 +.action-profile-send_mail .send-mail-recipients {
  52 + color: #888888;
  53 + padding: 10px;
  54 + width: 475px;
  55 + line-height: 15px;
  56 +}
public/javascripts/comment_order.js
@@ -10,10 +10,9 @@ function send_order(order, url) { @@ -10,10 +10,9 @@ function send_order(order, url) {
10 }); 10 });
11 } 11 }
12 12
13 -  
14 jQuery(document).ready(function(){ 13 jQuery(document).ready(function(){
15 jQuery("#comment_order").change(function(){ 14 jQuery("#comment_order").change(function(){
16 - var url = jQuery("#page_url").val(); 15 + var url = window.location.href;
17 send_order(this.value, url); 16 send_order(this.value, url);
18 }); 17 });
19 -});  
20 \ No newline at end of file 18 \ No newline at end of file
  19 +});
public/javascripts/profile_members.js 0 → 100644
@@ -0,0 +1,25 @@ @@ -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,3 +207,23 @@
207 height: auto; 207 height: auto;
208 font-size: 12px; 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 &#39;virtualhosts&#39; @@ -17,7 +17,6 @@ when &#39;virtualhosts&#39;
17 puts " #{server_directive} #{domain.name}" 17 puts " #{server_directive} #{domain.name}"
18 server_directive = 'ServerAlias' 18 server_directive = 'ServerAlias'
19 end 19 end
20 - puts " Include /usr/share/noosfero/util/chat/apache/xmpp.conf"  
21 puts " Include /etc/noosfero/apache/virtualhost.conf" 20 puts " Include /etc/noosfero/apache/virtualhost.conf"
22 puts "</VirtualHost>" 21 puts "</VirtualHost>"
23 end 22 end
script/development
@@ -23,7 +23,7 @@ start() { @@ -23,7 +23,7 @@ start() {
23 trap stop INT TERM EXIT 23 trap stop INT TERM EXIT
24 whenever --write-crontab --set 'environment=development' 24 whenever --write-crontab --set 'environment=development'
25 mkdir -p log 25 mkdir -p log
26 - touch log/development.log 26 + touch log/development.log log/development_api.log
27 if [ -z "$RAILS_RELATIVE_URL_ROOT" ]; then 27 if [ -z "$RAILS_RELATIVE_URL_ROOT" ]; then
28 unicorn_rails --config-file lib/noosfero/unicorn.rb --daemonize $@ 28 unicorn_rails --config-file lib/noosfero/unicorn.rb --daemonize $@
29 else 29 else
@@ -32,7 +32,7 @@ start() { @@ -32,7 +32,7 @@ start() {
32 --config-file lib/noosfero/unicorn.rb \ 32 --config-file lib/noosfero/unicorn.rb \
33 --daemonize 33 --daemonize
34 fi 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 start $@ 38 start $@
script/quick-start
@@ -130,6 +130,7 @@ fi @@ -130,6 +130,7 @@ fi
130 # create needed directory 130 # create needed directory
131 mkdir -p tmp/pids 131 mkdir -p tmp/pids
132 mkdir -p tmp/cache 132 mkdir -p tmp/cache
  133 +mkdir cache
133 134
134 # use default gitignore rules 135 # use default gitignore rules
135 if [ ! -f .gitignore ]; then 136 if [ ! -f .gitignore ]; then
test/fixtures/roles.yml
@@ -103,3 +103,4 @@ environment_administrator: @@ -103,3 +103,4 @@ environment_administrator:
103 - manage_environment_templates 103 - manage_environment_templates
104 - manage_environment_licenses 104 - manage_environment_licenses
105 - manage_email_templates 105 - manage_email_templates
  106 + - edit_raw_html_block
test/functional/cms_controller_test.rb
@@ -1647,6 +1647,50 @@ class CmsControllerTest &lt; ActionController::TestCase @@ -1647,6 +1647,50 @@ class CmsControllerTest &lt; ActionController::TestCase
1647 assert_tag :tag => 'input', :attributes => {:name => 'article[accept_comments]', :value => 1, :type => 'checkbox'} 1647 assert_tag :tag => 'input', :attributes => {:name => 'article[accept_comments]', :value => 1, :type => 'checkbox'}
1648 end 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 should 'display accept comments option when editing forum post with a different label' do 1694 should 'display accept comments option when editing forum post with a different label' do
1651 profile.articles << f = Forum.new(:name => 'Forum for test') 1695 profile.articles << f = Forum.new(:name => 'Forum for test')
1652 profile.articles << a = TinyMceArticle.new(:name => 'Forum post for test', :parent => f) 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 &lt; ActionController::TestCase @@ -387,10 +387,26 @@ class CommentControllerTest &lt; ActionController::TestCase
387 Article.record_timestamps = true 387 Article.record_timestamps = true
388 388
389 login_as @profile.identifier 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 assert_not_equal yesterday, page.reload.updated_at 391 assert_not_equal yesterday, page.reload.updated_at
392 end 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 should 'be able to mark comments as spam' do 410 should 'be able to mark comments as spam' do
395 login_as profile.identifier 411 login_as profile.identifier
396 article = fast_create(Article, :profile_id => profile.id) 412 article = fast_create(Article, :profile_id => profile.id)
test/functional/content_viewer_controller_test.rb
@@ -51,27 +51,26 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -51,27 +51,26 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
51 assert_response :missing 51 assert_response :missing
52 end 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 profile = create_user('someone').person 55 profile = create_user('someone').person
56 html = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/500.html', 'text/html'), :profile => profile 56 html = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/500.html', 'text/html'), :profile => profile
57 html.save! 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 assert_response :success 61 assert_response :success
62 - assert_match /#{html.public_filename}/, @response.body 62 + assert_select "a[href=#{html.full_path}]"
63 end 63 end
64 64
65 - should 'download file when article is image' do 65 + should 'download file when view page is blank' do
66 profile = create_user('someone').person 66 profile = create_user('someone').person
67 image = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile 67 image = UploadedFile.create! :uploaded_data => fixture_file_upload('/files/rails.png', 'image/png'), :profile => profile
68 image.save! 68 image.save!
69 69
70 get :view_page, :profile => 'someone', :page => [ 'rails.png' ] 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 end 74 end
76 75
77 should 'display image on a page when article is image and has a view param' do 76 should 'display image on a page when article is image and has a view param' do
@@ -342,6 +341,27 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -342,6 +341,27 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
342 assert_tag :content => /list my comment/ 341 assert_tag :content => /list my comment/
343 end 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 should 'redirect to new article path under an old path' do 365 should 'redirect to new article path under an old path' do
346 p = create_user('test_user').person 366 p = create_user('test_user').person
347 a = p.articles.create(:name => 'old-name') 367 a = p.articles.create(:name => 'old-name')
@@ -1291,18 +1311,6 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -1291,18 +1311,6 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1291 assert_tag :tag => 'div', :attributes => { :id => 'article-actions' }, :descendant => { :tag => 'a', :attributes => { :title => 'This button is expired.', :class => 'button with-text icon-edit disabled' } } 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 end 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 should 'not display comments marked as spam' do 1314 should 'not display comments marked as spam' do
1307 article = fast_create(Article, :profile_id => profile.id) 1315 article = fast_create(Article, :profile_id => profile.id)
1308 ham = fast_create(Comment, :source_id => article.id, :source_type => 'Article', :title => 'some content') 1316 ham = fast_create(Comment, :source_id => article.id, :source_type => 'Article', :title => 'some content')
@@ -1377,7 +1385,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -1377,7 +1385,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
1377 assert_equal 15, article.comments.count 1385 assert_equal 15, article.comments.count
1378 1386
1379 get 'view_page', :profile => profile.identifier, :page => article.path.split('/') 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&amp;comment_page=2", :rel => 'next' }
1381 end 1389 end
1382 1390
1383 should 'not escape acceptable HTML in list of blog posts' do 1391 should 'not escape acceptable HTML in list of blog posts' do
test/functional/profile_controller_test.rb
@@ -18,6 +18,19 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -18,6 +18,19 @@ class ProfileControllerTest &lt; ActionController::TestCase
18 assert assigns(:friends) 18 assert assigns(:friends)
19 end 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 should 'point to manage friends in user is seeing his own friends' do 34 should 'point to manage friends in user is seeing his own friends' do
22 login_as('testuser') 35 login_as('testuser')
23 get :friends 36 get :friends
@@ -1338,6 +1351,24 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1338,6 +1351,24 @@ class ProfileControllerTest &lt; ActionController::TestCase
1338 assert_equivalent [scrap,activity], assigns(:activities).map(&:activity) 1351 assert_equivalent [scrap,activity], assigns(:activities).map(&:activity)
1339 end 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 should "be logged in to leave comment on an activity" do 1372 should "be logged in to leave comment on an activity" do
1342 article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software') 1373 article = TinyMceArticle.create!(:profile => profile, :name => 'An article about free software')
1343 activity = ActionTracker::Record.last 1374 activity = ActionTracker::Record.last
@@ -1434,11 +1465,41 @@ class ProfileControllerTest &lt; ActionController::TestCase @@ -1434,11 +1465,41 @@ class ProfileControllerTest &lt; ActionController::TestCase
1434 create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) 1465 create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community)
1435 login_as('profile_moderator_user') 1466 login_as('profile_moderator_user')
1436 @controller.stubs(:locale).returns('pt') 1467 @controller.stubs(:locale).returns('pt')
  1468 +
1437 assert_difference 'Delayed::Job.count', 1 do 1469 assert_difference 'Delayed::Job.count', 1 do
1438 post :send_mail, :profile => community.identifier, :mailing => {:subject => 'Hello', :body => 'We have some news'} 1470 post :send_mail, :profile => community.identifier, :mailing => {:subject => 'Hello', :body => 'We have some news'}
1439 end 1471 end
1440 end 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 should 'save mailing' do 1503 should 'save mailing' do
1443 community = fast_create(Community) 1504 community = fast_create(Community)
1444 create_user_with_permission('profile_moderator_user', 'send_mail_to_members', community) 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 &lt; ActionController::TestCase @@ -311,6 +311,12 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
311 assert_equal 999, @b1.article_id 311 assert_equal 999, @b1.article_id
312 end 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 should 'be able to edit ProductsBlock' do 320 should 'be able to edit ProductsBlock' do
315 block = ProductsBlock.new 321 block = ProductsBlock.new
316 322
test/functional/profile_members_controller_test.rb
@@ -31,6 +31,31 @@ class ProfileMembersControllerTest &lt; ActionController::TestCase @@ -31,6 +31,31 @@ class ProfileMembersControllerTest &lt; ActionController::TestCase
31 assert_template 'index' 31 assert_template 'index'
32 end 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 should 'show form to change role' do 59 should 'show form to change role' do
35 ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'test enterprise') 60 ent = fast_create(Enterprise, :identifier => 'test_enterprise', :name => 'test enterprise')
36 role = Profile::Roles.member(Environment.default) 61 role = Profile::Roles.member(Environment.default)
@@ -171,7 +196,7 @@ class ProfileMembersControllerTest &lt; ActionController::TestCase @@ -171,7 +196,7 @@ class ProfileMembersControllerTest &lt; ActionController::TestCase
171 login_as :test_user 196 login_as :test_user
172 197
173 get :index, :profile => community.identifier 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 end 200 end
176 201
177 should 'not display send email to members if doesn\'t have the permission' do 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 &lt; ActionDispatch::IntegrationTest @@ -13,17 +13,15 @@ class EnableDisableFeaturesTest &lt; ActionDispatch::IntegrationTest
13 assert_tag :tag => 'input', :attributes => { :name => 'environment[enabled_features][]', :value => 'feature2' } 13 assert_tag :tag => 'input', :attributes => { :name => 'environment[enabled_features][]', :value => 'feature2' }
14 assert_tag :tag => 'input', :attributes => { :name => 'environment[enabled_features][]', :value => 'feature3' } 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 assert_response :success 19 assert_response :success
21 assert_equal '/admin/features', path 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 assert_equal '/admin/features', path 25 assert_equal '/admin/features', path
28 26
29 end 27 end
test/integration/enterprise_registration_test.rb
@@ -61,10 +61,9 @@ class EnterpriseRegistrationTest &lt; ActionDispatch::IntegrationTest @@ -61,10 +61,9 @@ class EnterpriseRegistrationTest &lt; ActionDispatch::IntegrationTest
61 assert_response :success 61 assert_response :success
62 assert_tag :form, :attributes => { :action => "/myprofile/myorg/enterprise_validation/approve/#{code}" } 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 assert_equal "/myprofile/myorg/enterprise_validation/view_processed/#{code}", path 67 assert_equal "/myprofile/myorg/enterprise_validation/view_processed/#{code}", path
69 assert_tag :span, :attributes => { :class => 'validation_approved' } 68 assert_tag :span, :attributes => { :class => 'validation_approved' }
70 end 69 end
test/integration/manage_documents_test.rb
@@ -24,11 +24,10 @@ class ManageDocumentsTest &lt; ActionDispatch::IntegrationTest @@ -24,11 +24,10 @@ class ManageDocumentsTest &lt; ActionDispatch::IntegrationTest
24 assert_tag :tag => 'form', :attributes => { :action => '/myprofile/myuser/cms/new', :method => /post/i } 24 assert_tag :tag => 'form', :attributes => { :action => '/myprofile/myuser/cms/new', :method => /post/i }
25 25
26 assert_difference 'Article.count' do 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 end 28 end
29 29
30 - assert_response :redirect  
31 - follow_redirect! 30 + assert_response :success
32 a = Article.find_by_path('my-article') 31 a = Article.find_by_path('my-article')
33 assert_equal "/myuser/#{a.slug}", path 32 assert_equal "/myuser/#{a.slug}", path
34 end 33 end
@@ -55,14 +54,13 @@ class ManageDocumentsTest &lt; ActionDispatch::IntegrationTest @@ -55,14 +54,13 @@ class ManageDocumentsTest &lt; ActionDispatch::IntegrationTest
55 assert_tag :tag => 'form', :attributes => { :action => "/myprofile/myuser/cms/edit/#{article.id}", :method => /post/i } 54 assert_tag :tag => 'form', :attributes => { :action => "/myprofile/myuser/cms/edit/#{article.id}", :method => /post/i }
56 55
57 assert_no_difference 'Article.count' do 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 end 58 end
60 59
61 article.reload 60 article.reload
62 assert_equal 'this is the body of the article', article.body 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 a = Article.find_by_path('my-article') 64 a = Article.find_by_path('my-article')
67 assert_equal "/myuser/#{a.slug}", path 65 assert_equal "/myuser/#{a.slug}", path
68 end 66 end
@@ -84,10 +82,9 @@ class ManageDocumentsTest &lt; ActionDispatch::IntegrationTest @@ -84,10 +82,9 @@ class ManageDocumentsTest &lt; ActionDispatch::IntegrationTest
84 assert_response :success 82 assert_response :success
85 83
86 assert_tag tag: 'a', attributes: { href: "/myprofile/myuser/cms/destroy/#{article.id}", 'data-confirm' => /Are you sure/ } 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 assert_equal "/myuser", path 88 assert_equal "/myuser", path
92 89
93 # the article was actually deleted 90 # the article was actually deleted
test/integration/manage_friendships_test.rb
@@ -24,11 +24,10 @@ class ManageFriendshipsTest &lt; ActionDispatch::IntegrationTest @@ -24,11 +24,10 @@ class ManageFriendshipsTest &lt; ActionDispatch::IntegrationTest
24 get "/myprofile/#{@person.identifier}/friends/remove/#{@friend.id}" 24 get "/myprofile/#{@person.identifier}/friends/remove/#{@friend.id}"
25 assert_response :success 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 :confirmation => '1' 28 :confirmation => '1'
29 - assert_response :redirect 29 + assert_response :success
30 30
31 - follow_redirect!  
32 31
33 assert assigns(:friends).empty? 32 assert assigns(:friends).empty?
34 refute @person.is_a_friend?(@friend) 33 refute @person.is_a_friend?(@friend)
test/support/integration_test.rb
@@ -14,9 +14,8 @@ class ActionDispatch::IntegrationTest @@ -14,9 +14,8 @@ class ActionDispatch::IntegrationTest
14 def login(username, password) 14 def login(username, password)
15 ActionDispatch::Integration::Session.any_instance.stubs(:https?).returns(true) 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 assert_not_equal '/account/login', path 19 assert_not_equal '/account/login', path
21 end 20 end
22 21
test/unit/access_control_test.rb 0 → 100644
@@ -0,0 +1,34 @@ @@ -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 &lt; ActiveSupport::TestCase @@ -89,7 +89,8 @@ class ActionTrackerNotificationTest &lt; ActiveSupport::TestCase
89 end 89 end
90 90
91 should "have comments through article action_tracker" do 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 article = create(TextileArticle, :profile_id => person.id) 94 article = create(TextileArticle, :profile_id => person.id)
94 process_delayed_job_queue 95 process_delayed_job_queue
95 notification = ActionTrackerNotification.last 96 notification = ActionTrackerNotification.last
test/unit/api/articles_test.rb
@@ -39,6 +39,41 @@ class ArticlesTest &lt; ActiveSupport::TestCase @@ -39,6 +39,41 @@ class ArticlesTest &lt; ActiveSupport::TestCase
39 assert_equal 403, last_response.status 39 assert_equal 403, last_response.status
40 end 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 should 'list article children' do 77 should 'list article children' do
43 article = create(Article, :profile_id => user.person.id, :name => "Parent") 78 article = create(Article, :profile_id => user.person.id, :name => "Parent")
44 child1 = create(Article, :parent_id => article.id, :profile_id => user.person.id, :name => "Some Child") 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 &lt; ActionView::TestCase @@ -1043,6 +1043,31 @@ class ApplicationHelperTest &lt; ActionView::TestCase
1043 assert_equal c.top_url, top_url 1043 assert_equal c.top_url, top_url
1044 end 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 protected 1071 protected
1047 include NoosferoTestHelper 1072 include NoosferoTestHelper
1048 1073
test/unit/article_block_test.rb
@@ -140,6 +140,8 @@ class ArticleBlockTest &lt; ActiveSupport::TestCase @@ -140,6 +140,8 @@ class ArticleBlockTest &lt; ActiveSupport::TestCase
140 block.article = file 140 block.article = file
141 block.save! 141 block.save!
142 142
  143 + UploadedFile.any_instance.stubs(:url).returns('myhost.mydomain/path/to/file')
  144 +
143 assert_tag_in_string instance_eval(&block.content), :tag => 'a', :content => _('Download') 145 assert_tag_in_string instance_eval(&block.content), :tag => 'a', :content => _('Download')
144 end 146 end
145 147
test/unit/article_test.rb
@@ -7,7 +7,8 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -7,7 +7,8 @@ class ArticleTest &lt; ActiveSupport::TestCase
7 7
8 def setup 8 def setup
9 ActiveSupport::TestCase::setup 9 ActiveSupport::TestCase::setup
10 - @profile = create_user('testing').person 10 + user = User.current = create_user 'testing'
  11 + @profile = user.person
11 end 12 end
12 attr_reader :profile 13 attr_reader :profile
13 14
@@ -21,6 +22,21 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -21,6 +22,21 @@ class ArticleTest &lt; ActiveSupport::TestCase
21 refute a.errors[:profile_id.to_s].present? 22 refute a.errors[:profile_id.to_s].present?
22 end 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 should 'require value for name' do 40 should 'require value for name' do
25 a = Article.new 41 a = Article.new
26 a.valid? 42 a.valid?
@@ -468,14 +484,12 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -468,14 +484,12 @@ class ArticleTest &lt; ActiveSupport::TestCase
468 end 484 end
469 485
470 should 'say that logged off user cannot see private article' do 486 should 'say that logged off user cannot see private article' do
471 - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile')  
472 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) 487 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false)
473 488
474 refute article.display_to?(nil) 489 refute article.display_to?(nil)
475 end 490 end
476 491
477 should 'say that not member of profile cannot see private article' do 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 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) 493 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false)
480 person = create_user('test_user').person 494 person = create_user('test_user').person
481 495
@@ -483,7 +497,6 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -483,7 +497,6 @@ class ArticleTest &lt; ActiveSupport::TestCase
483 end 497 end
484 498
485 should 'say that member user can not see private article' do 499 should 'say that member user can not see private article' do
486 - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile')  
487 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false, :show_to_followers => false) 500 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false, :show_to_followers => false)
488 person = create_user('test_user').person 501 person = create_user('test_user').person
489 profile.affiliate(person, Profile::Roles.member(profile.environment.id)) 502 profile.affiliate(person, Profile::Roles.member(profile.environment.id))
@@ -492,25 +505,23 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -492,25 +505,23 @@ class ArticleTest &lt; ActiveSupport::TestCase
492 end 505 end
493 506
494 should 'say that profile admin can see private article' do 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 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => false) 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 end 513 end
502 514
503 should 'say that profile moderator can see private article' do 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 end 521 end
511 522
512 should 'show article to non member if article public but profile private' do 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 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => true) 525 article = fast_create(Article, :name => 'test article', :profile_id => profile.id, :published => true)
515 person1 = create_user('test_user1').person 526 person1 = create_user('test_user1').person
516 profile.affiliate(person1, Profile::Roles.member(profile.environment.id)) 527 profile.affiliate(person1, Profile::Roles.member(profile.environment.id))
@@ -522,7 +533,6 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -522,7 +533,6 @@ class ArticleTest &lt; ActiveSupport::TestCase
522 end 533 end
523 534
524 should 'make new article private if created inside a private folder' do 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 folder = fast_create(Folder, :name => 'my_intranet', :profile_id => profile.id, :published => false) 536 folder = fast_create(Folder, :name => 'my_intranet', :profile_id => profile.id, :published => false)
527 article = fast_create(Article, :name => 'my private article', :profile_id => profile.id, :parent_id => folder.id) 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 &lt; ActiveSupport::TestCase @@ -530,7 +540,6 @@ class ArticleTest &lt; ActiveSupport::TestCase
530 end 540 end
531 541
532 should 'save as private' do 542 should 'save as private' do
533 - profile = fast_create(Profile, :name => 'test profile', :identifier => 'test_profile')  
534 folder = fast_create(Folder, :name => 'my_intranet', :profile_id => profile.id, :published => false) 543 folder = fast_create(Folder, :name => 'my_intranet', :profile_id => profile.id, :published => false)
535 article = fast_create(Article, :name => 'my private article') 544 article = fast_create(Article, :name => 'my private article')
536 article.profile = profile 545 article.profile = profile
@@ -1012,13 +1021,13 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1012,13 +1021,13 @@ class ArticleTest &lt; ActiveSupport::TestCase
1012 1021
1013 should 'not notify activity by default on create' do 1022 should 'not notify activity by default on create' do
1014 ActionTracker::Record.delete_all 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 assert_equal 0, ActionTracker::Record.count 1025 assert_equal 0, ActionTracker::Record.count
1017 end 1026 end
1018 1027
1019 should 'not notify activity by default on update' do 1028 should 'not notify activity by default on update' do
1020 ActionTracker::Record.delete_all 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 a.name = 'foo' 1031 a.name = 'foo'
1023 a.save! 1032 a.save!
1024 assert_equal 0, ActionTracker::Record.count 1033 assert_equal 0, ActionTracker::Record.count
@@ -1026,13 +1035,13 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1026,13 +1035,13 @@ class ArticleTest &lt; ActiveSupport::TestCase
1026 1035
1027 should 'not notify activity by default on destroy' do 1036 should 'not notify activity by default on destroy' do
1028 ActionTracker::Record.delete_all 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 a.destroy 1039 a.destroy
1031 assert_equal 0, ActionTracker::Record.count 1040 assert_equal 0, ActionTracker::Record.count
1032 end 1041 end
1033 1042
1034 should 'create activity' do 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 a.activity.destroy 1045 a.activity.destroy
1037 assert_nil a.activity 1046 assert_nil a.activity
1038 1047
@@ -1212,10 +1221,9 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1212,10 +1221,9 @@ class ArticleTest &lt; ActiveSupport::TestCase
1212 end 1221 end
1213 1222
1214 should 'get article galleries' do 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 end 1227 end
1220 1228
1221 should 'has many translations' do 1229 should 'has many translations' do
@@ -1236,7 +1244,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1236,7 +1244,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1236 end 1244 end
1237 1245
1238 should 'validate inclusion of language' do 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 a.language = '12' 1248 a.language = '12'
1241 a.valid? 1249 a.valid?
1242 assert a.errors[:language.to_s].present? 1250 assert a.errors[:language.to_s].present?
@@ -1268,7 +1276,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1268,7 +1276,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1268 end 1276 end
1269 1277
1270 should 'list possible translations' do 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 article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id) 1280 article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id)
1273 possible_translations = native_article.possible_translations 1281 possible_translations = native_article.possible_translations
1274 refute possible_translations.include?('en') 1282 refute possible_translations.include?('en')
@@ -1278,7 +1286,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1278,7 +1286,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1278 should 'verify if translation is already in use' do 1286 should 'verify if translation is already in use' do
1279 native_article = fast_create(Article, :language => 'pt') 1287 native_article = fast_create(Article, :language => 'pt')
1280 article_translation = fast_create(Article, :language => 'en', :translation_of_id => native_article.id) 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 a.language = 'en' 1290 a.language = 'en'
1283 a.translation_of = native_article 1291 a.translation_of = native_article
1284 a.valid? 1292 a.valid?
@@ -1290,7 +1298,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1290,7 +1298,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1290 1298
1291 should 'verify if native translation is already in use' do 1299 should 'verify if native translation is already in use' do
1292 native_article = fast_create(Article, :language => 'pt') 1300 native_article = fast_create(Article, :language => 'pt')
1293 - a = build(Article, :profile => fast_create(Profile)) 1301 + a = build(Article, :profile => profile)
1294 a.language = 'pt' 1302 a.language = 'pt'
1295 a.translation_of = native_article 1303 a.translation_of = native_article
1296 a.valid? 1304 a.valid?
@@ -1302,7 +1310,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1302,7 +1310,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1302 1310
1303 should 'translation have a language' do 1311 should 'translation have a language' do
1304 native_article = fast_create(Article, :language => 'pt') 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 a.translation_of = native_article 1314 a.translation_of = native_article
1307 a.valid? 1315 a.valid?
1308 assert a.errors[:language.to_s].present? 1316 assert a.errors[:language.to_s].present?
@@ -1312,8 +1320,8 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1312,8 +1320,8 @@ class ArticleTest &lt; ActiveSupport::TestCase
1312 end 1320 end
1313 1321
1314 should 'native translation have a language' do 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 a.language = 'en' 1325 a.language = 'en'
1318 a.translation_of = native_article 1326 a.translation_of = native_article
1319 a.valid? 1327 a.valid?
@@ -1378,22 +1386,22 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1378,22 +1386,22 @@ class ArticleTest &lt; ActiveSupport::TestCase
1378 end 1386 end
1379 1387
1380 should 'get only non translated articles' do 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 end 1393 end
1386 1394
1387 should 'not list own language as a possible translation if language has changed' do 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 refute a.possible_translations.include?('pt') 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 a.language = 'en' 1399 a.language = 'en'
1392 refute a.possible_translations.include?('en') 1400 refute a.possible_translations.include?('en')
1393 end 1401 end
1394 1402
1395 should 'list own language as a possible translation if language has not changed' do 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 assert a.possible_translations.include?('pt') 1405 assert a.possible_translations.include?('pt')
1398 end 1406 end
1399 1407
@@ -1435,7 +1443,6 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1435,7 +1443,6 @@ class ArticleTest &lt; ActiveSupport::TestCase
1435 should 'return only folders' do 1443 should 'return only folders' do
1436 not_folders = [RssFeed, TinyMceArticle, Event, TextileArticle] 1444 not_folders = [RssFeed, TinyMceArticle, Event, TextileArticle]
1437 folders = [Folder, Blog, Gallery, Forum] 1445 folders = [Folder, Blog, Gallery, Forum]
1438 - profile = fast_create(Profile)  
1439 1446
1440 not_folders.each do |klass| 1447 not_folders.each do |klass|
1441 item = fast_create(klass) 1448 item = fast_create(klass)
@@ -1451,7 +1458,6 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1451,7 +1458,6 @@ class ArticleTest &lt; ActiveSupport::TestCase
1451 should 'return no folders' do 1458 should 'return no folders' do
1452 not_folders = [RssFeed, TinyMceArticle, Event, TextileArticle] 1459 not_folders = [RssFeed, TinyMceArticle, Event, TextileArticle]
1453 folders = [Folder, Blog, Gallery, Forum] 1460 folders = [Folder, Blog, Gallery, Forum]
1454 - profile = fast_create(Profile)  
1455 1461
1456 not_folders.each do |klass| 1462 not_folders.each do |klass|
1457 item = fast_create(klass) 1463 item = fast_create(klass)
@@ -1611,18 +1617,16 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1611,18 +1617,16 @@ class ArticleTest &lt; ActiveSupport::TestCase
1611 end 1617 end
1612 1618
1613 should 'delegate region info to profile' do 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 article = fast_create(Article, :profile_id => profile.id) 1622 article = fast_create(Article, :profile_id => profile.id)
1618 article.region 1623 article.region
1619 article.region_id 1624 article.region_id
1620 end 1625 end
1621 1626
1622 should 'delegate environment info to profile' do 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 article = fast_create(Article, :profile_id => profile.id) 1630 article = fast_create(Article, :profile_id => profile.id)
1627 article.environment 1631 article.environment
1628 article.environment_id 1632 article.environment_id
@@ -1711,7 +1715,7 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -1711,7 +1715,7 @@ class ArticleTest &lt; ActiveSupport::TestCase
1711 1715
1712 should 'has a empty list of followers by default' do 1716 should 'has a empty list of followers by default' do
1713 a = Article.new 1717 a = Article.new
1714 - assert_equal [], a.followers 1718 + assert_equal [], a.person_followers
1715 end 1719 end
1716 1720
1717 should 'get first image from lead' do 1721 should 'get first image from lead' do
@@ -2229,6 +2233,14 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -2229,6 +2233,14 @@ class ArticleTest &lt; ActiveSupport::TestCase
2229 end 2233 end
2230 end 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 should 'have can_display_media_panel with default false' do 2244 should 'have can_display_media_panel with default false' do
2233 a = Article.new 2245 a = Article.new
2234 assert !a.can_display_media_panel? 2246 assert !a.can_display_media_panel?
@@ -2278,4 +2290,15 @@ class ArticleTest &lt; ActiveSupport::TestCase @@ -2278,4 +2290,15 @@ class ArticleTest &lt; ActiveSupport::TestCase
2278 assert_match 'Parent folder is archived', err.message 2290 assert_match 'Parent folder is archived', err.message
2279 end 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 end 2304 end
test/unit/blog_helper_test.rb
@@ -101,11 +101,9 @@ class BlogHelperTest &lt; ActionView::TestCase @@ -101,11 +101,9 @@ class BlogHelperTest &lt; ActionView::TestCase
101 101
102 should 'display link to file if post is an uploaded_file' do 102 should 'display link to file if post is an uploaded_file' do
103 file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true, :parent => blog) 103 file = create(UploadedFile, :uploaded_data => fixture_file_upload('/files/test.txt', 'text/plain'), :profile => profile, :published => true, :parent => blog)
104 -  
105 result = display_post(file) 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 end 107 end
110 108
111 should 'display image if post is an image' do 109 should 'display image if post is an image' do
test/unit/boxes_helper_test.rb
@@ -187,6 +187,7 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -187,6 +187,7 @@ class BoxesHelperTest &lt; ActionView::TestCase
187 block = Block.create!(:box => box) 187 block = Block.create!(:box => box)
188 block.stubs(:embedable?).returns(true) 188 block.stubs(:embedable?).returns(true)
189 stubs(:url_for).returns('') 189 stubs(:url_for).returns('')
  190 + @controller.stubs(:user).returns(box.owner)
190 assert_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '} 191 assert_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '}
191 end 192 end
192 193
@@ -195,6 +196,7 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -195,6 +196,7 @@ class BoxesHelperTest &lt; ActionView::TestCase
195 block = Block.create!(:box => box) 196 block = Block.create!(:box => box)
196 block.stubs(:embedable?).returns(false) 197 block.stubs(:embedable?).returns(false)
197 stubs(:url_for).returns('') 198 stubs(:url_for).returns('')
  199 + @controller.stubs(:user).returns(box.owner)
198 assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '} 200 assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '}
199 end 201 end
200 202
test/unit/comment_notifier_test.rb
@@ -60,7 +60,7 @@ class CommentNotifierTest &lt; ActiveSupport::TestCase @@ -60,7 +60,7 @@ class CommentNotifierTest &lt; ActiveSupport::TestCase
60 should "deliver mail to followers" do 60 should "deliver mail to followers" do
61 author = create_user('follower_author').person 61 author = create_user('follower_author').person
62 follower = create_user('follower').person 62 follower = create_user('follower').person
63 - @article.followers += [follower.email] 63 + @article.person_followers += [follower]
64 @article.save! 64 @article.save!
65 create_comment_and_notify(:source => @article, :author => author, :title => 'comment title', :body => 'comment body') 65 create_comment_and_notify(:source => @article, :author => author, :title => 'comment title', :body => 'comment body')
66 assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email 66 assert_includes ActionMailer::Base.deliveries.map(&:bcc).flatten, follower.email
test/unit/comment_test.rb
@@ -339,34 +339,27 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -339,34 +339,27 @@ class CommentTest &lt; ActiveSupport::TestCase
339 assert c.rejected? 339 assert c.rejected?
340 end 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 owner = create_user('owner_of_article').person 343 owner = create_user('owner_of_article').person
344 person = create_user('follower').person 344 person = create_user('follower').person
345 article = fast_create(Article, :profile_id => owner.id) 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 create(Comment, :source => article, :author => person, :title => 'new comment', :body => 'new comment') 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 end 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 article = fast_create(Article, :profile_id => create_user('article_owner').person.id) 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 create(Comment, :source => article, :name => 'follower', :email => 'follower@example.com', :title => 'new comment', :body => 'new comment') 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 end 356 end
364 357
365 should 'not subscribe owner as follower of an article on new comment' do 358 should 'not subscribe owner as follower of an article on new comment' do
366 owner = create_user('owner_of_article').person 359 owner = create_user('owner_of_article').person
367 article = fast_create(Article, :profile_id => owner.id) 360 article = fast_create(Article, :profile_id => owner.id)
368 create(Comment, :source => article, :author => owner, :title => 'new comment', :body => 'new comment') 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 end 363 end
371 364
372 should 'not subscribe admins as follower of an article on new comment' do 365 should 'not subscribe admins as follower of an article on new comment' do
@@ -377,8 +370,13 @@ class CommentTest &lt; ActiveSupport::TestCase @@ -377,8 +370,13 @@ class CommentTest &lt; ActiveSupport::TestCase
377 article = fast_create(Article, :profile_id => owner.id) 370 article = fast_create(Article, :profile_id => owner.id)
378 create(Comment, :source => article, :author => follower, :title => 'new comment', :body => 'new comment') 371 create(Comment, :source => article, :author => follower, :title => 'new comment', :body => 'new comment')
379 create(Comment, :source => article, :author => admin, :title => 'new comment', :body => 'new comment') 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 end 380 end
383 381
384 should 'update article activity when add a comment' do 382 should 'update article activity when add a comment' do
test/unit/highlights_block_test.rb
@@ -54,7 +54,19 @@ class HighlightsBlockTest &lt; ActiveSupport::TestCase @@ -54,7 +54,19 @@ class HighlightsBlockTest &lt; ActiveSupport::TestCase
54 should 'remove images with blank fields' do 54 should 'remove images with blank fields' do
55 h = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => '', :position => '', :title => ''}]) 55 h = HighlightsBlock.new(:images => [{:image_id => 1, :address => '/address', :position => 1, :title => 'address'}, {:image_id => '', :address => '', :position => '', :title => ''}])
56 h.save! 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 end 70 end
59 71
60 should 'be able to update display setting' do 72 should 'be able to update display setting' do
@@ -84,7 +96,7 @@ class HighlightsBlockTest &lt; ActiveSupport::TestCase @@ -84,7 +96,7 @@ class HighlightsBlockTest &lt; ActiveSupport::TestCase
84 block.save! 96 block.save!
85 block.reload 97 block.reload
86 assert_equal 2, block.images.count 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 end 100 end
89 101
90 should 'list images in order' do 102 should 'list images in order' do
test/unit/noosfero_test.rb
@@ -21,6 +21,7 @@ class NoosferoTest &lt; ActiveSupport::TestCase @@ -21,6 +21,7 @@ class NoosferoTest &lt; ActiveSupport::TestCase
21 should 'support setting default locale' do 21 should 'support setting default locale' do
22 Noosfero.default_locale = 'pt_BR' 22 Noosfero.default_locale = 'pt_BR'
23 assert_equal 'pt_BR', Noosfero.default_locale 23 assert_equal 'pt_BR', Noosfero.default_locale
  24 + Noosfero.default_locale = nil
24 end 25 end
25 26
26 should 'identifier format' do 27 should 'identifier format' do
test/unit/organization_mailing_test.rb
@@ -98,6 +98,11 @@ class OrganizationMailingTest &lt; ActiveSupport::TestCase @@ -98,6 +98,11 @@ class OrganizationMailingTest &lt; ActiveSupport::TestCase
98 assert_equal [Person['user_one'], Person['user_two']], mailing.recipients 98 assert_equal [Person['user_one'], Person['user_two']], mailing.recipients
99 end 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 should 'return recipients according to limit' do 106 should 'return recipients according to limit' do
102 mailing = create(OrganizationMailing, :source => community, :subject => 'Hello', :body => 'We have some news', :person => person) 107 mailing = create(OrganizationMailing, :source => community, :subject => 'Hello', :body => 'We have some news', :person => person)
103 assert_equal [Person['user_one']], mailing.recipients(0, 1) 108 assert_equal [Person['user_one']], mailing.recipients(0, 1)
test/unit/person_notifier_test.rb
@@ -49,7 +49,8 @@ class PersonNotifierTest &lt; ActiveSupport::TestCase @@ -49,7 +49,8 @@ class PersonNotifierTest &lt; ActiveSupport::TestCase
49 should 'display author name in delivered mail' do 49 should 'display author name in delivered mail' do
50 @community.add_member(@member) 50 @community.add_member(@member)
51 User.current = @admin.user 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 process_delayed_job_queue 54 process_delayed_job_queue
54 notify 55 notify
55 sent = ActionMailer::Base.deliveries.last 56 sent = ActionMailer::Base.deliveries.last
test/unit/person_test.rb
@@ -1845,4 +1845,100 @@ class PersonTest &lt; ActiveSupport::TestCase @@ -1845,4 +1845,100 @@ class PersonTest &lt; ActiveSupport::TestCase
1845 assert_equivalent [c1,c3], p1.comments 1845 assert_equivalent [c1,c3], p1.comments
1846 end 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 end 1944 end
test/unit/profile_test.rb
@@ -1816,6 +1816,21 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1816,6 +1816,21 @@ class ProfileTest &lt; ActiveSupport::TestCase
1816 assert_equal [person], community.members 1816 assert_equal [person], community.members
1817 end 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 should 'count unique members of a community' do 1834 should 'count unique members of a community' do
1820 person = fast_create(Person) 1835 person = fast_create(Person)
1821 community = fast_create(Community) 1836 community = fast_create(Community)
test/unit/raw_html_block_test.rb
@@ -22,4 +22,20 @@ class RawHTMLBlockTest &lt; ActiveSupport::TestCase @@ -22,4 +22,20 @@ class RawHTMLBlockTest &lt; ActiveSupport::TestCase
22 assert_match(/HTML$/, block.content) 22 assert_match(/HTML$/, block.content)
23 end 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 end 41 end
test/unit/uploaded_file_test.rb
@@ -357,4 +357,25 @@ class UploadedFileTest &lt; ActiveSupport::TestCase @@ -357,4 +357,25 @@ class UploadedFileTest &lt; ActiveSupport::TestCase
357 assert_instance_of Fixnum, UploadedFile.max_size 357 assert_instance_of Fixnum, UploadedFile.max_size
358 end 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 end 381 end
util/chat/apache/xmpp.conf
@@ -1,11 +0,0 @@ @@ -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,9 +19,9 @@ module ActsAsAccessible
19 nil 19 nil
20 end 20 end
21 21
22 - def affiliate(accessor, roles) 22 + def affiliate(accessor, roles, attributes = {})
23 roles = Array(roles) 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 end 25 end
26 26
27 def disaffiliate(accessor, roles) 27 def disaffiliate(accessor, roles)
vendor/plugins/access_control/lib/acts_as_accessor.rb
@@ -21,9 +21,9 @@ module ActsAsAccessor @@ -21,9 +21,9 @@ module ActsAsAccessor
21 (actual_roles - roles).each {|r| remove_role(r, resource)} 21 (actual_roles - roles).each {|r| remove_role(r, resource)}
22 end 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 ra = RoleAssignment.new(attributes) 27 ra = RoleAssignment.new(attributes)
28 role_assignments << ra 28 role_assignments << ra
29 resource.role_assignments << ra 29 resource.role_assignments << ra
@@ -44,6 +44,19 @@ module ActsAsAccessor @@ -44,6 +44,19 @@ module ActsAsAccessor
44 RoleAssignment.where(role_attributes nil, res) 44 RoleAssignment.where(role_attributes nil, res)
45 end 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 protected 60 protected
48 def role_attributes(role, resource) 61 def role_attributes(role, resource)
49 attributes = {:accessor_id => self.id, :accessor_type => self.class.base_class.name} 62 attributes = {:accessor_id => self.id, :accessor_type => self.class.base_class.name}
vendor/plugins/access_control/lib/role_assignment.rb
1 class RoleAssignment < ActiveRecord::Base 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 belongs_to :role 5 belongs_to :role
6 belongs_to :accessor, :polymorphic => true 6 belongs_to :accessor, :polymorphic => true