Commit cc81e07501b41177911bd389ce1bba503e1bd206

Authored by Leandro Santos
2 parents 97e6b3c1 6e1949cf

merging with master

Showing 136 changed files with 2164 additions and 423 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 136 files displayed.

@@ -92,6 +92,7 @@ Daniel Alves + Rafael Manzo <rr.manzo@gmail.com> @@ -92,6 +92,7 @@ Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
92 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> 92 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
93 Daniel Bucher <daniel.bucher88@gmail.com> 93 Daniel Bucher <daniel.bucher88@gmail.com>
94 Daniel Cunha <daniel@colivre.coop.br> 94 Daniel Cunha <daniel@colivre.coop.br>
  95 +daniel <dtygel@eita.org.br>
95 David Carlos <ddavidcarlos1392@gmail.com> 96 David Carlos <ddavidcarlos1392@gmail.com>
96 diegoamc <diegoamc90@gmail.com> 97 diegoamc <diegoamc90@gmail.com>
97 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com> 98 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
@@ -120,6 +121,7 @@ Diego Araujo + Rodrigo Souto + Rafael Manzo &lt;rr.manzo@gmail.com&gt; @@ -120,6 +121,7 @@ Diego Araujo + Rodrigo Souto + Rafael Manzo &lt;rr.manzo@gmail.com&gt;
120 Diego + Jefferson <diegoamc90@gmail.com> 121 Diego + Jefferson <diegoamc90@gmail.com>
121 Diego Martinez <diegoamc90@gmail.com> 122 Diego Martinez <diegoamc90@gmail.com>
122 Diego + Renan <renanteruoc@gmail.com> 123 Diego + Renan <renanteruoc@gmail.com>
  124 +dtygel <dtygel@gmail.com>
123 DylanGuedes <djmgguedes@gmail.com> 125 DylanGuedes <djmgguedes@gmail.com>
124 Eduardo Passos <eduardo@risa.localdomain.localhost> 126 Eduardo Passos <eduardo@risa.localdomain.localhost>
125 Eduardo Passos <eduardosteps@gmail.com> 127 Eduardo Passos <eduardosteps@gmail.com>
@@ -144,6 +146,7 @@ Italo Valcy &lt;italo@dcc.ufba.br&gt; @@ -144,6 +146,7 @@ Italo Valcy &lt;italo@dcc.ufba.br&gt;
144 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com> 146 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
145 Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com> 147 Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
146 Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com> 148 Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>
  149 +Jérôme Jutteau <j.jutteau@gmail.com>
147 João da Silva + Eduardo Morais + Rafael Manzo <rr.manzo@gmail.com> 150 João da Silva + Eduardo Morais + Rafael Manzo <rr.manzo@gmail.com>
148 João da Silva <jaodsilv@linux.ime.usp.br> 151 João da Silva <jaodsilv@linux.ime.usp.br>
149 João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br> 152 João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
@@ -247,8 +250,10 @@ Tallys Martins &lt;tallysmartins@gmail.com&gt; @@ -247,8 +250,10 @@ Tallys Martins &lt;tallysmartins@gmail.com&gt;
247 Tallys Martins <tallysmartins@yahoo.com.br> 250 Tallys Martins <tallysmartins@yahoo.com.br>
248 tallys <tallys@tallys> 251 tallys <tallys@tallys>
249 tallys <tallys@tallys.(none)> 252 tallys <tallys@tallys.(none)>
  253 +Thiago Casotti <thiago.casotti@uol.com.br>
250 Thiago Zoroastro <thiago.zoroastro@bol.com.br> 254 Thiago Zoroastro <thiago.zoroastro@bol.com.br>
251 Tuux <tuxa@galaxie.eu.org> 255 Tuux <tuxa@galaxie.eu.org>
  256 +TWS <tablettws@gmail.com>
252 Valessio Brito <contato@valessiobrito.com.br> 257 Valessio Brito <contato@valessiobrito.com.br>
253 Valessio Brito <contato@valessiobrito.info> 258 Valessio Brito <contato@valessiobrito.info>
254 Valessio Brito <valessio@gmail.com> 259 Valessio Brito <valessio@gmail.com>
@@ -20,18 +20,17 @@ gem &#39;locale&#39;, &#39;~&gt; 2.0.5&#39; @@ -20,18 +20,17 @@ gem &#39;locale&#39;, &#39;~&gt; 2.0.5&#39;
20 gem 'whenever', :require => false 20 gem 'whenever', :require => false
21 gem 'eita-jrails', '>= 0.9.5', :require => 'jrails' 21 gem 'eita-jrails', '>= 0.9.5', :require => 'jrails'
22 22
23 -group :assets do  
24 - gem 'uglifier', '>= 1.0.3'  
25 - gem 'sass-rails'  
26 -end 23 +# asset pipeline
  24 +gem 'uglifier', '>= 1.0.3'
  25 +gem 'sass-rails'
27 26
28 group :production do 27 group :production do
29 gem 'dalli', '~> 2.7.0' 28 gem 'dalli', '~> 2.7.0'
30 end 29 end
31 30
32 group :test do 31 group :test do
33 - gem 'rspec', '~> 2.10.0'  
34 - gem 'rspec-rails', '~> 2.10.1' 32 + gem 'rspec', '~> 2.14.0'
  33 + gem 'rspec-rails', '~> 2.14.1'
35 gem 'mocha', '~> 1.1.0', :require => false 34 gem 'mocha', '~> 1.1.0', :require => false
36 end 35 end
37 36
app/controllers/admin/role_controller.rb
@@ -2,7 +2,7 @@ class RoleController &lt; AdminController @@ -2,7 +2,7 @@ class RoleController &lt; AdminController
2 protect 'manage_environment_roles', :environment 2 protect 'manage_environment_roles', :environment
3 3
4 def index 4 def index
5 - @roles = environment.roles.find(:all) 5 + @roles = environment.roles.find(:all, :conditions => {:profile_id => nil})
6 end 6 end
7 7
8 def new 8 def new
app/controllers/application_controller.rb
@@ -9,6 +9,7 @@ class ApplicationController &lt; ActionController::Base @@ -9,6 +9,7 @@ class ApplicationController &lt; ActionController::Base
9 before_filter :allow_cross_domain_access 9 before_filter :allow_cross_domain_access
10 before_filter :login_required, :if => :private_environment? 10 before_filter :login_required, :if => :private_environment?
11 before_filter :verify_members_whitelist, :if => [:private_environment?, :user] 11 before_filter :verify_members_whitelist, :if => [:private_environment?, :user]
  12 + before_filter :redirect_to_current_user
12 13
13 def verify_members_whitelist 14 def verify_members_whitelist
14 render_access_denied unless user.is_admin? || environment.in_whitelist?(user) 15 render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
@@ -192,4 +193,15 @@ class ApplicationController &lt; ActionController::Base @@ -192,4 +193,15 @@ class ApplicationController &lt; ActionController::Base
192 def private_environment? 193 def private_environment?
193 @environment.enabled?(:restrict_to_members) 194 @environment.enabled?(:restrict_to_members)
194 end 195 end
  196 +
  197 + def redirect_to_current_user
  198 + if params[:profile] == '~'
  199 + if logged_in?
  200 + redirect_to params.merge(:profile => user.identifier)
  201 + else
  202 + render_not_found
  203 + end
  204 + end
  205 + end
  206 +
195 end 207 end
app/controllers/my_profile/cms_controller.rb
@@ -357,7 +357,8 @@ class CmsController &lt; MyProfileController @@ -357,7 +357,8 @@ class CmsController &lt; MyProfileController
357 @task.ip_address = request.remote_ip 357 @task.ip_address = request.remote_ip
358 @task.user_agent = request.user_agent 358 @task.user_agent = request.user_agent
359 @task.referrer = request.referrer 359 @task.referrer = request.referrer
360 - if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save 360 + @task.requestor = current_person if logged_in?
  361 + if (logged_in? || verify_recaptcha(:model => @task, :message => _('Please type the words correctly'))) && @task.save
361 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') 362 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.')
362 redirect_to @back_to 363 redirect_to @back_to
363 end 364 end
app/controllers/my_profile/profile_design_controller.rb
@@ -4,11 +4,19 @@ class ProfileDesignController &lt; BoxOrganizerController @@ -4,11 +4,19 @@ class ProfileDesignController &lt; BoxOrganizerController
4 4
5 protect 'edit_profile_design', :profile 5 protect 'edit_profile_design', :profile
6 6
7 - before_filter :protect_fixed_block, :only => [:save, :move_block] 7 + before_filter :protect_uneditable_block, :only => [:save]
  8 + before_filter :protect_fixed_block, :only => [:move_block]
  9 +
  10 + def protect_uneditable_block
  11 + block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
  12 + if !current_person.is_admin? && !block.editable?
  13 + render_access_denied
  14 + end
  15 + end
8 16
9 def protect_fixed_block 17 def protect_fixed_block
10 block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, '')) 18 block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
11 - if block.fixed && !current_person.is_admin? 19 + if !current_person.is_admin? && !block.movable?
12 render_access_denied 20 render_access_denied
13 end 21 end
14 end 22 end
app/controllers/my_profile/profile_members_controller.rb
@@ -58,6 +58,7 @@ class ProfileMembersController &lt; MyProfileController @@ -58,6 +58,7 @@ class ProfileMembersController &lt; MyProfileController
58 58
59 def change_role 59 def change_role
60 @roles = Profile::Roles.organization_member_roles(environment.id) 60 @roles = Profile::Roles.organization_member_roles(environment.id)
  61 + @custom_roles = profile.custom_roles
61 begin 62 begin
62 @member = profile.members.find(params[:id]) 63 @member = profile.members.find(params[:id])
63 rescue ActiveRecord::RecordNotFound 64 rescue ActiveRecord::RecordNotFound
app/controllers/my_profile/profile_roles_controller.rb 0 → 100644
@@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
  1 +class ProfileRolesController < MyProfileController
  2 +
  3 + protect 'manage_custom_roles', :profile
  4 +
  5 + def index
  6 + @roles = profile.custom_roles
  7 + end
  8 +
  9 + def new
  10 + @role = Role.new
  11 + end
  12 +
  13 + def create
  14 + @role = Role.new({:name => params[:role][:name], :permissions => params[:role][:permissions], :environment => environment }, :without_protection => true)
  15 + if @role.save
  16 + profile.custom_roles << @role
  17 + redirect_to :action => 'show', :id => @role
  18 + else
  19 + session[:notice] = _('Failed to create role')
  20 + render :action => 'new'
  21 + end
  22 + end
  23 +
  24 + def show
  25 + @role = environment.roles.find(params[:id])
  26 + end
  27 +
  28 + def edit
  29 + @role = environment.roles.find(params[:id])
  30 + end
  31 +
  32 + def assign_role_by_members
  33 + return redirect_to "/" if params[:q].nil? or !request.xhr?
  34 + arg = params[:q].downcase
  35 + result = find_by_contents(:people, environment, profile.members, params[:q])[:results]
  36 + render :text => prepare_to_token_input(result).to_json
  37 + end
  38 +
  39 + def destroy
  40 + @role = environment.roles.find(params[:id])
  41 + @members = profile.members_by_role(@role)
  42 + @roles_list = all_roles(environment, profile)
  43 + @roles_list.delete(@role)
  44 + end
  45 +
  46 + def remove
  47 + @role = environment.roles.find(params[:id])
  48 + @members = profile.members_by_role(@role)
  49 + member_roles = params[:roles] ? environment.roles.find(params[:roles].select{|r|!r.to_i.zero?}) : []
  50 + append_roles(@members, member_roles, profile)
  51 + if @role.destroy
  52 + session[:notice] = _('Role successfuly removed!')
  53 + else
  54 + session[:notice] = _('Failed to remove role!')
  55 + end
  56 + redirect_to :action => 'index'
  57 + end
  58 +
  59 + def update
  60 + @role = environment.roles.find(params[:id])
  61 + if @role.update_attributes(params[:role])
  62 + redirect_to :action => 'show', :id => @role
  63 + else
  64 + session[:notice] = _('Failed to edit role')
  65 + render :action => 'edit'
  66 + end
  67 + end
  68 +
  69 + def assign
  70 + @role = environment.roles.find(params[:id])
  71 + @roles_list = all_roles(environment, profile)
  72 + @roles_list.delete(@role)
  73 + end
  74 +
  75 + def define
  76 + @role = environment.roles.find(params[:id])
  77 + selected_role = params[:selected_role] ? environment.roles.find(params[:selected_role].to_i) : nil
  78 + if params[:assign_role_by].eql? "members"
  79 + members_list = params[:person_id].split(',').collect {|id| environment.profiles.find(id.to_i)}
  80 + members_list.collect{|person| person.add_role(@role, profile)}
  81 + elsif params[:assign_role_by].eql? "roles"
  82 + members = profile.members_by_role(selected_role)
  83 + replace_role(members, selected_role, @role, profile)
  84 + else
  85 + session[:notice] = _("Error")
  86 + end
  87 + redirect_to :action => 'index'
  88 + end
  89 +
  90 + protected
  91 +
  92 + def append_roles(members, roles, profile)
  93 + members.each do |person|
  94 + all_roles = person.find_roles(profile).map(&:role) + roles
  95 + person.define_roles(all_roles, profile)
  96 + end
  97 + end
  98 +
  99 + def all_roles(environment, profile)
  100 + Profile::Roles.organization_member_roles(environment.id) + profile.custom_roles
  101 + end
  102 +
  103 + def replace_roles(members, roles, profile)
  104 + members.each do |person|
  105 + person.define_roles(roles, profile)
  106 + end
  107 + end
  108 +
  109 + def replace_role(members, role, new_role, profile)
  110 + members.each do |person|
  111 + person.remove_role(role, profile)
  112 + person.add_role(new_role, profile)
  113 + end
  114 + end
  115 +
  116 +end
app/helpers/application_helper.rb
@@ -707,6 +707,24 @@ module ApplicationHelper @@ -707,6 +707,24 @@ module ApplicationHelper
707 javascript_include_tag script if script 707 javascript_include_tag script if script
708 end 708 end
709 709
  710 + def template_path
  711 + if profile.nil?
  712 + "/designs/templates/#{environment.layout_template}"
  713 + else
  714 + "/designs/templates/#{profile.layout_template}"
  715 + end
  716 + end
  717 +
  718 + def template_javascript_src
  719 + script = File.join template_path, '/javascripts/template.js'
  720 + script if File.exists? File.join(Rails.root, 'public', script)
  721 + end
  722 +
  723 + def templete_javascript_ng
  724 + script = template_javascript_src
  725 + javascript_include_tag script if script
  726 + end
  727 +
710 def file_field_or_thumbnail(label, image, i) 728 def file_field_or_thumbnail(label, image, i)
711 display_form_field label, ( 729 display_form_field label, (
712 render :partial => (image && image.valid? ? 'shared/show_thumbnail' : 'shared/change_image'), 730 render :partial => (image && image.valid? ? 'shared/show_thumbnail' : 'shared/change_image'),
app/helpers/blog_helper.rb
@@ -17,28 +17,28 @@ module BlogHelper @@ -17,28 +17,28 @@ module BlogHelper
17 _('Configure blog') 17 _('Configure blog')
18 end 18 end
19 19
20 - def list_posts(articles, format = 'full', paginate = true) 20 + def list_posts(articles, conf = { format: 'full', paginate: true })
21 pagination = will_paginate(articles, { 21 pagination = will_paginate(articles, {
22 :param_name => 'npage', 22 :param_name => 'npage',
23 :previous_label => _('&laquo; Newer posts'), 23 :previous_label => _('&laquo; Newer posts'),
24 :next_label => _('Older posts &raquo;'), 24 :next_label => _('Older posts &raquo;'),
25 :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"} 25 :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
26 - }) if articles.present? && paginate 26 + }) if articles.present? && conf[:paginate]
27 content = [] 27 content = []
28 artic_len = articles.length 28 artic_len = articles.length
29 articles.each_with_index{ |art,i| 29 articles.each_with_index{ |art,i|
30 - css_add = [ 'position-'+(i+1).to_s() ] 30 + css_add = [ 'blog-post', 'position-'+(i+1).to_s() ]
31 position = (i%2 == 0) ? 'odd-post' : 'even-post' 31 position = (i%2 == 0) ? 'odd-post' : 'even-post'
32 css_add << 'first' if i == 0 32 css_add << 'first' if i == 0
33 css_add << 'last' if i == (artic_len-1) 33 css_add << 'last' if i == (artic_len-1)
34 css_add << 'not-published' if !art.published? 34 css_add << 'not-published' if !art.published?
35 - css_add << position + '-inner'  
36 - content << content_tag('div',  
37 - content_tag('div',  
38 - display_post(art, format).html_safe + '<br style="clear:both"/>'.html_safe,  
39 - :class => 'blog-post ' + css_add.join(' '),  
40 - :id => "post-#{art.id}"), :class => position  
41 - ) 35 + css_add << position
  36 + content << (content_tag 'div', id: "post-#{art.id}", class: css_add do
  37 + content_tag 'div', class: position + '-inner blog-post-inner' do
  38 + display_post(art, conf[:format]).html_safe +
  39 + '<br style="clear:both"/>'.html_safe
  40 + end
  41 + end)
42 } 42 }
43 content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') 43 content.join("\n<hr class='sep-posts'/>\n") + (pagination or '')
44 end 44 end
@@ -46,7 +46,16 @@ module BlogHelper @@ -46,7 +46,16 @@ module BlogHelper
46 def display_post(article, format = 'full') 46 def display_post(article, format = 'full')
47 no_comments = (format == 'full') ? false : true 47 no_comments = (format == 'full') ? false : true
48 title = article_title(article, :no_comments => no_comments) 48 title = article_title(article, :no_comments => no_comments)
49 - html = send("display_#{format}_format", FilePresenter.for(article)).html_safe 49 + method = "display_#{format.split('+')[0]}_format"
  50 + html = send(method, FilePresenter.for(article)).html_safe
  51 + if format.split('+')[1] == 'pic'
  52 + img = article.first_image
  53 + if img.blank?
  54 + '<div class="post-pic empty"></div>'
  55 + else
  56 + '<div class="post-pic" style="background-image:url('+img+')"></div>'
  57 + end
  58 + end.to_s +
50 title + html 59 title + html
51 end 60 end
52 61
app/helpers/boxes_helper.rb
@@ -190,7 +190,7 @@ module BoxesHelper @@ -190,7 +190,7 @@ module BoxesHelper
190 else 190 else
191 "before-block-#{block.id}" 191 "before-block-#{block.id}"
192 end 192 end
193 - if block.nil? or modifiable?(block) 193 + if block.nil? || movable?(block)
194 content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover') 194 content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover')
195 else 195 else
196 "" 196 ""
@@ -199,14 +199,14 @@ module BoxesHelper @@ -199,14 +199,14 @@ module BoxesHelper
199 199
200 # makes the given block draggable so it can be moved away. 200 # makes the given block draggable so it can be moved away.
201 def block_handle(block) 201 def block_handle(block)
202 - modifiable?(block) ? draggable_element("block-#{block.id}", :revert => true) : "" 202 + movable?(block) ? draggable_element("block-#{block.id}", :revert => true) : ""
203 end 203 end
204 204
205 def block_edit_buttons(block) 205 def block_edit_buttons(block)
206 buttons = [] 206 buttons = []
207 nowhere = 'javascript: return false;' 207 nowhere = 'javascript: return false;'
208 208
209 - if modifiable?(block) 209 + if movable?(block)
210 if block.first? 210 if block.first?
211 buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere) 211 buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere)
212 else 212 else
@@ -229,15 +229,15 @@ module BoxesHelper @@ -229,15 +229,15 @@ module BoxesHelper
229 buttons << icon_button('left', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[1].id.to_s, :id => block.id }, :method => 'post' ) 229 buttons << icon_button('left', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[1].id.to_s, :id => block.id }, :method => 'post' )
230 end 230 end
231 end 231 end
  232 + end
232 233
233 - if block.editable?  
234 - buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })  
235 - end 234 + if editable?(block)
  235 + buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  236 + end
236 237
237 - if !block.main?  
238 - buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})  
239 - buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })  
240 - end 238 + if movable?(block) && !block.main?
  239 + buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})
  240 + buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })
241 end 241 end
242 242
243 if block.respond_to?(:help) 243 if block.respond_to?(:help)
@@ -273,7 +273,11 @@ module BoxesHelper @@ -273,7 +273,11 @@ module BoxesHelper
273 classes 273 classes
274 end 274 end
275 275
276 - def modifiable?(block)  
277 - return !block.fixed || environment.admins.include?(user) 276 + def movable?(block)
  277 + return block.movable? || user.is_admin?
  278 + end
  279 +
  280 + def editable?(block)
  281 + return block.editable? || user.is_admin?
278 end 282 end
279 end 283 end
app/helpers/layout_helper.rb
@@ -28,7 +28,7 @@ module LayoutHelper @@ -28,7 +28,7 @@ module LayoutHelper
28 end 28 end
29 29
30 def noosfero_javascript 30 def noosfero_javascript
31 - plugins_javascripts = @plugins.flat_map{ |plugin| plugin.js_files.map{ |js| plugin.class.public_path(js, true) } }.flatten 31 + plugins_javascripts = @plugins.flat_map{ |plugin| Array.wrap(plugin.js_files).map{ |js| plugin.class.public_path(js, true) } }.flatten
32 32
33 output = '' 33 output = ''
34 output += render 'layouts/javascript' 34 output += render 'layouts/javascript'
@@ -38,6 +38,8 @@ module LayoutHelper @@ -38,6 +38,8 @@ module LayoutHelper
38 output += theme_javascript_ng.to_s 38 output += theme_javascript_ng.to_s
39 output += javascript_tag 'render_all_jquery_ui_widgets()' 39 output += javascript_tag 'render_all_jquery_ui_widgets()'
40 40
  41 + output += templete_javascript_ng.to_s
  42 +
41 output 43 output
42 end 44 end
43 45
@@ -70,11 +72,7 @@ module LayoutHelper @@ -70,11 +72,7 @@ module LayoutHelper
70 end 72 end
71 73
72 def template_stylesheet_path 74 def template_stylesheet_path
73 - if profile.nil?  
74 - "/designs/templates/#{environment.layout_template}/stylesheets/style.css"  
75 - else  
76 - "/designs/templates/#{profile.layout_template}/stylesheets/style.css"  
77 - end 75 + File.join template_path, "/stylesheets/style.css"
78 end 76 end
79 77
80 78
app/helpers/tinymce_helper.rb
@@ -17,6 +17,7 @@ module TinymceHelper @@ -17,6 +17,7 @@ module TinymceHelper
17 searchreplace wordcount visualblocks visualchars code fullscreen 17 searchreplace wordcount visualblocks visualchars code fullscreen
18 insertdatetime media nonbreaking save table contextmenu directionality 18 insertdatetime media nonbreaking save table contextmenu directionality
19 emoticons template paste textcolor colorpicker textpattern], 19 emoticons template paste textcolor colorpicker textpattern],
  20 + :image_advtab => true,
20 :language => tinymce_language 21 :language => tinymce_language
21 22
22 options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image" 23 options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
app/models/article.rb
@@ -5,7 +5,7 @@ class Article &lt; ActiveRecord::Base @@ -5,7 +5,7 @@ class Article &lt; ActiveRecord::Base
5 :allow_members_to_edit, :translation_of_id, :language, 5 :allow_members_to_edit, :translation_of_id, :language,
6 :license_id, :parent_id, :display_posts_in_current_language, 6 :license_id, :parent_id, :display_posts_in_current_language,
7 :category_ids, :posts_per_page, :moderate_comments, 7 :category_ids, :posts_per_page, :moderate_comments,
8 - :accept_comments, :feed, :published, :source, 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 :image_builder, :show_to_followers 11 :image_builder, :show_to_followers
@@ -769,7 +769,9 @@ class Article &lt; ActiveRecord::Base @@ -769,7 +769,9 @@ class Article &lt; ActiveRecord::Base
769 end 769 end
770 770
771 def first_image 771 def first_image
772 - img = Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first || Nokogiri::HTML.fragment(self.body.to_s).search('img').first 772 + img = ( image.present? && { 'src' => image.public_filename } ) ||
  773 + Nokogiri::HTML.fragment(self.lead.to_s).css('img[src]').first ||
  774 + Nokogiri::HTML.fragment(self.body.to_s).search('img').first
773 img.nil? ? '' : img['src'] 775 img.nil? ? '' : img['src']
774 end 776 end
775 777
app/models/block.rb
1 class Block < ActiveRecord::Base 1 class Block < ActiveRecord::Base
2 2
3 - attr_accessible :title, :display, :limit, :box_id, :posts_per_page, :visualization_format, :language, :display_user, :box, :fixed 3 + attr_accessible :title, :display, :limit, :box_id, :posts_per_page,
  4 + :visualization_format, :language, :display_user,
  5 + :box, :edit_modes, :move_modes
4 6
5 # to be able to generate HTML 7 # to be able to generate HTML
6 include ActionView::Helpers::UrlHelper 8 include ActionView::Helpers::UrlHelper
@@ -23,7 +25,7 @@ class Block &lt; ActiveRecord::Base @@ -23,7 +25,7 @@ class Block &lt; ActiveRecord::Base
23 end 25 end
24 26
25 def get_limit 27 def get_limit
26 - [0,limit].max 28 + [0,limit.to_i].max
27 end 29 end
28 30
29 def embed_code 31 def embed_code
@@ -110,8 +112,13 @@ class Block &lt; ActiveRecord::Base @@ -110,8 +112,13 @@ class Block &lt; ActiveRecord::Base
110 # * <tt>'all'</tt>: the block is always displayed 112 # * <tt>'all'</tt>: the block is always displayed
111 settings_items :language, :type => :string, :default => 'all' 113 settings_items :language, :type => :string, :default => 'all'
112 114
113 - # The block can be configured to be fixed. Only can be edited by environment admins  
114 - settings_items :fixed, :type => :boolean, :default => false 115 + # The block can be configured to define the edition modes options. Only can be edited by environment admins
  116 + # It can assume the following values:
  117 + #
  118 + # * <tt>'all'</tt>: the block owner has all edit options for this block
  119 + # * <tt>'none'</tt>: the block owner can't do anything with the block
  120 + settings_items :edit_modes, :type => :string, :default => 'all'
  121 + settings_items :move_modes, :type => :string, :default => 'all'
115 122
116 # returns the description of the block, used when the user sees a list of 123 # returns the description of the block, used when the user sees a list of
117 # blocks to choose one to include in the design. 124 # blocks to choose one to include in the design.
@@ -148,7 +155,11 @@ class Block &lt; ActiveRecord::Base @@ -148,7 +155,11 @@ class Block &lt; ActiveRecord::Base
148 155
149 # Is this block editable? (Default to <tt>false</tt>) 156 # Is this block editable? (Default to <tt>false</tt>)
150 def editable? 157 def editable?
151 - true 158 + self.edit_modes == "all"
  159 + end
  160 +
  161 + def movable?
  162 + self.move_modes == "all"
152 end 163 end
153 164
154 # must always return false, except on MainBlock clas. 165 # must always return false, except on MainBlock clas.
@@ -228,6 +239,21 @@ class Block &lt; ActiveRecord::Base @@ -228,6 +239,21 @@ class Block &lt; ActiveRecord::Base
228 } 239 }
229 end 240 end
230 241
  242 + def edit_block_options
  243 + @edit_options ||= {
  244 + 'all' => _('Can be modified'),
  245 + 'none' => _('Cannot be modified')
  246 + }
  247 + end
  248 +
  249 + def move_block_options
  250 + @move_options ||= {
  251 + 'all' => _('Can be moved'),
  252 + 'none' => _('Cannot be moved')
  253 + }
  254 + end
  255 +
  256 +
231 def duplicate 257 def duplicate
232 duplicated_block = self.dup 258 duplicated_block = self.dup
233 duplicated_block.display = 'never' 259 duplicated_block.display = 'never'
app/models/blog.rb
@@ -76,7 +76,7 @@ class Blog &lt; Folder @@ -76,7 +76,7 @@ class Blog &lt; Folder
76 end 76 end
77 77
78 settings_items :visualization_format, :type => :string, :default => 'full' 78 settings_items :visualization_format, :type => :string, :default => 'full'
79 - validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format 79 + validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format
80 80
81 settings_items :display_posts_in_current_language, :type => :boolean, :default => false 81 settings_items :display_posts_in_current_language, :type => :boolean, :default => false
82 82
app/models/environment.rb
@@ -19,6 +19,8 @@ class Environment &lt; ActiveRecord::Base @@ -19,6 +19,8 @@ class Environment &lt; ActiveRecord::Base
19 filename 19 filename
20 end 20 end
21 21
  22 + NUMBER_OF_BOXES = 4
  23 +
22 PERMISSIONS['Environment'] = { 24 PERMISSIONS['Environment'] = {
23 'view_environment_admin_panel' => N_('View environment admin panel'), 25 'view_environment_admin_panel' => N_('View environment admin panel'),
24 'edit_environment_features' => N_('Edit environment features'), 26 'edit_environment_features' => N_('Edit environment features'),
@@ -172,7 +174,7 @@ class Environment &lt; ActiveRecord::Base @@ -172,7 +174,7 @@ class Environment &lt; ActiveRecord::Base
172 acts_as_having_boxes 174 acts_as_having_boxes
173 175
174 after_create do |env| 176 after_create do |env|
175 - 3.times do 177 + NUMBER_OF_BOXES.times do
176 env.boxes << Box.new 178 env.boxes << Box.new
177 end 179 end
178 180
@@ -737,8 +739,8 @@ class Environment &lt; ActiveRecord::Base @@ -737,8 +739,8 @@ class Environment &lt; ActiveRecord::Base
737 end 739 end
738 740
739 def is_default_template?(template) 741 def is_default_template?(template)
740 - is_default = template == community_default_template  
741 - is_default = is_default || template == person_default_template 742 + is_default = template == community_default_template
  743 + is_default = is_default || template == person_default_template
742 is_default = is_default || template == enterprise_default_template 744 is_default = is_default || template == enterprise_default_template
743 is_default 745 is_default
744 end 746 end
app/models/highlights_block.rb
@@ -26,8 +26,16 @@ class HighlightsBlock &lt; Block @@ -26,8 +26,16 @@ class HighlightsBlock &lt; Block
26 end 26 end
27 27
28 def featured_images 28 def featured_images
29 - block_images = images.select{|i| !i[:image_src].nil? }.sort { |x, y| x[:position] <=> y[:position] }  
30 - shuffle ? block_images.shuffle : block_images 29 + images = get_images
  30 + shuffle ? images.shuffle : images
  31 + end
  32 +
  33 + def get_images
  34 + images.select do |i|
  35 + !i[:image_src].nil?
  36 + end.sort do |x, y|
  37 + x[:position] <=> y[:position]
  38 + end
31 end 39 end
32 40
33 def content(args={}) 41 def content(args={})
app/models/organization.rb
@@ -29,6 +29,8 @@ class Organization &lt; Profile @@ -29,6 +29,8 @@ class Organization &lt; Profile
29 29
30 has_many :mailings, :class_name => 'OrganizationMailing', :foreign_key => :source_id, :as => 'source' 30 has_many :mailings, :class_name => 'OrganizationMailing', :foreign_key => :source_id, :as => 'source'
31 31
  32 + has_many :custom_roles, :class_name => 'Role', :foreign_key => :profile_id
  33 +
32 scope :more_popular, :order => 'members_count DESC' 34 scope :more_popular, :order => 'members_count DESC'
33 35
34 validate :presence_of_required_fieds, :unless => :is_template 36 validate :presence_of_required_fieds, :unless => :is_template
app/models/profile.rb
@@ -22,6 +22,8 @@ class Profile &lt; ActiveRecord::Base @@ -22,6 +22,8 @@ class Profile &lt; ActiveRecord::Base
22 :display => %w[compact] 22 :display => %w[compact]
23 } 23 }
24 24
  25 + NUMBER_OF_BOXES = 4
  26 +
25 def self.default_search_display 27 def self.default_search_display
26 'compact' 28 'compact'
27 end 29 end
@@ -43,7 +45,7 @@ class Profile &lt; ActiveRecord::Base @@ -43,7 +45,7 @@ class Profile &lt; ActiveRecord::Base
43 find_role('editor', env_id) 45 find_role('editor', env_id)
44 end 46 end
45 def self.organization_member_roles(env_id) 47 def self.organization_member_roles(env_id)
46 - all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? } 48 + all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? || !r.profile_id.nil?}
47 end 49 end
48 def self.all_roles(env_id) 50 def self.all_roles(env_id)
49 Role.all :conditions => { :environment_id => env_id } 51 Role.all :conditions => { :environment_id => env_id }
@@ -75,6 +77,7 @@ class Profile &lt; ActiveRecord::Base @@ -75,6 +77,7 @@ class Profile &lt; ActiveRecord::Base
75 'publish_content' => N_('Publish content'), 77 'publish_content' => N_('Publish content'),
76 'invite_members' => N_('Invite members'), 78 'invite_members' => N_('Invite members'),
77 'send_mail_to_members' => N_('Send e-Mail to members'), 79 'send_mail_to_members' => N_('Send e-Mail to members'),
  80 + 'manage_custom_roles' => N_('Manage custom roles'),
78 } 81 }
79 82
80 acts_as_accessible 83 acts_as_accessible
@@ -361,7 +364,7 @@ class Profile &lt; ActiveRecord::Base @@ -361,7 +364,7 @@ class Profile &lt; ActiveRecord::Base
361 if template 364 if template
362 apply_template(template, :copy_articles => false) 365 apply_template(template, :copy_articles => false)
363 else 366 else
364 - 3.times do 367 + NUMBER_OF_BOXES.times do
365 self.boxes << Box.new 368 self.boxes << Box.new
366 end 369 end
367 370
@@ -404,6 +407,7 @@ class Profile &lt; ActiveRecord::Base @@ -404,6 +407,7 @@ class Profile &lt; ActiveRecord::Base
404 alias_method_chain :template, :default 407 alias_method_chain :template, :default
405 408
406 def apply_template(template, options = {:copy_articles => true}) 409 def apply_template(template, options = {:copy_articles => true})
  410 + self.template = template
407 copy_blocks_from(template) 411 copy_blocks_from(template)
408 copy_articles_from(template) if options[:copy_articles] 412 copy_articles_from(template) if options[:copy_articles]
409 self.apply_type_specific_template(template) 413 self.apply_type_specific_template(template)
app/models/suggest_article.rb
1 class SuggestArticle < Task 1 class SuggestArticle < Task
2 2
3 - validates_presence_of :target_id, :article_name, :email, :name, :article_body 3 + validates_presence_of :target_id
  4 + validates_presence_of :email, :name, :if => Proc.new { |task| task.requestor.blank? }
  5 + validates_associated :article_object
4 6
5 settings_items :email, :type => String 7 settings_items :email, :type => String
6 settings_items :name, :type => String 8 settings_items :name, :type => String
7 - settings_items :article_name, :type => String  
8 - settings_items :article_body, :type => String  
9 - settings_items :article_abstract, :type => String  
10 - settings_items :article_parent_id, :type => String  
11 - settings_items :source, :type => String  
12 - settings_items :source_name, :type => String  
13 - settings_items :highlighted, :type => :boolean, :default => false  
14 settings_items :ip_address, :type => String 9 settings_items :ip_address, :type => String
15 settings_items :user_agent, :type => String 10 settings_items :user_agent, :type => String
16 settings_items :referrer, :type => String 11 settings_items :referrer, :type => String
  12 + settings_items :article, :type => Hash, :default => {}
17 13
18 after_create :schedule_spam_checking 14 after_create :schedule_spam_checking
19 15
@@ -24,34 +20,49 @@ class SuggestArticle &lt; Task @@ -24,34 +20,49 @@ class SuggestArticle &lt; Task
24 include Noosfero::Plugin::HotSpot 20 include Noosfero::Plugin::HotSpot
25 21
26 def sender 22 def sender
27 - "#{name} (#{email})" 23 + requestor ? "#{requestor.name}" : "#{name} (#{email})"
  24 + end
  25 +
  26 + def article_object
  27 + if @article_object.nil?
  28 + @article_object = article_type.new(article.merge({:profile => target}).except(:type))
  29 + if requestor.present?
  30 + @article_object.author = requestor
  31 + else
  32 + @article_object.author_name = name
  33 + end
  34 + end
  35 + @article_object
  36 + end
  37 +
  38 + def article_type
  39 + if article[:type].present?
  40 + type = article[:type].constantize
  41 + return type if type < Article
  42 + end
  43 + TinyMceArticle
28 end 44 end
29 45
30 def perform 46 def perform
31 - task = TinyMceArticle.new  
32 - task.profile = target  
33 - task.name = article_name  
34 - task.author_name = name  
35 - task.body = article_body  
36 - task.abstract = article_abstract  
37 - task.parent_id = article_parent_id  
38 - task.source = source  
39 - task.source_name = source_name  
40 - task.highlighted = highlighted  
41 - task.save! 47 + article_object.save!
42 end 48 end
43 49
44 def title 50 def title
45 _("Article suggestion") 51 _("Article suggestion")
46 end 52 end
47 53
  54 + def article_name
  55 + article[:name]
  56 + end
  57 +
48 def subject 58 def subject
49 article_name 59 article_name
50 end 60 end
51 61
52 def information 62 def information
53 - { :message => _('%{sender} suggested the publication of the article: %{subject}.'),  
54 - :variables => {:sender => sender} } 63 + variables = requestor.blank? ? {:requestor => sender} : {}
  64 + { :message => _('%{requestor} suggested the publication of the article: %{subject}.'),
  65 + :variables => variables }
55 end 66 end
56 67
57 def accept_details 68 def accept_details
@@ -63,8 +74,8 @@ class SuggestArticle &lt; Task @@ -63,8 +74,8 @@ class SuggestArticle &lt; Task
63 end 74 end
64 75
65 def target_notification_description 76 def target_notification_description
66 - _('%{sender} suggested the publication of the article: %{article}.') %  
67 - {:sender => sender, :article => article_name} 77 + _('%{requestor} suggested the publication of the article: %{article}.') %
  78 + {:requestor => sender, :article => article_name}
68 end 79 end
69 80
70 def target_notification_message 81 def target_notification_message
app/models/user.rb
@@ -45,7 +45,7 @@ class User &lt; ActiveRecord::Base @@ -45,7 +45,7 @@ class User &lt; ActiveRecord::Base
45 p = Person.new 45 p = Person.new
46 46
47 p.attributes = user.person_data 47 p.attributes = user.person_data
48 - p.identifier = user.login 48 + p.identifier = user.login if p.identifier.blank?
49 p.user = user 49 p.user = user
50 p.environment = user.environment 50 p.environment = user.environment
51 p.name ||= user.name || user.login 51 p.name ||= user.name || user.login
app/views/blocks/profile_info_actions/_join_leave_community.html.erb
1 -<div class='join-leave-button'> 1 +<div class='join-leave-button require-login-popup'>
2 <% if logged_in? %> 2 <% if logged_in? %>
3 <% if profile.members.include?(user) %> 3 <% if profile.members.include?(user) %>
4 <%= button(:delete, content_tag('span', _('Leave community')), profile.leave_url, 4 <%= button(:delete, content_tag('span', _('Leave community')), profile.leave_url,
app/views/box_organizer/edit.html.erb
@@ -5,12 +5,6 @@ @@ -5,12 +5,6 @@
5 5
6 <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %> 6 <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %>
7 7
8 - <% if environment.admins.include?(user) %>  
9 - <div class="fixed_block">  
10 - <%= labelled_check_box(_("Fixed"), "block[fixed]", value = "1", checked = @block.fixed) %>  
11 - </div>  
12 - <% end %>  
13 -  
14 <%= render :partial => partial_for_class(@block.class) %> 8 <%= render :partial => partial_for_class(@block.class) %>
15 9
16 <div class="display"> 10 <div class="display">
@@ -25,6 +19,15 @@ @@ -25,6 +19,15 @@
25 19
26 <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + environment.locales.map {|key, value| [value, key]} )) %> 20 <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + environment.locales.map {|key, value| [value, key]} )) %>
27 21
  22 + <% if user.is_admin? %>
  23 + <div class="edit-modes">
  24 + <%= labelled_form_field _('Edit options:'), select_tag('block[edit_modes]', options_from_collection_for_select(@block.edit_block_options, :first, :last, @block.edit_modes)) %>
  25 + </div>
  26 + <div class="move-modes">
  27 + <%= labelled_form_field _('Move options:'), select_tag('block[move_modes]', options_from_collection_for_select(@block.move_block_options, :first, :last, @block.move_modes)) %>
  28 + </div>
  29 + <% end %>
  30 +
28 <% button_bar do %> 31 <% button_bar do %>
29 <%= submit_button(:save, _('Save')) %> 32 <%= submit_button(:save, _('Save')) %>
30 <%= modal_close_button(_('Cancel')) %> 33 <%= modal_close_button(_('Cancel')) %>
app/views/cms/_blog.html.erb
@@ -64,7 +64,11 @@ @@ -64,7 +64,11 @@
64 <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> 64 <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%>
65 <% end %> 65 <% end %>
66 66
67 -<%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %> 67 +<%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [
  68 + [ _('Full post'), 'full'],
  69 + [ _('First paragraph'), 'short'],
  70 + [ _('First paragraph, with post picture'), 'short+pic']
  71 +])) %>
68 72
69 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %> 73 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %>
70 74
app/views/cms/suggest_an_article.html.erb
@@ -6,21 +6,22 @@ @@ -6,21 +6,22 @@
6 6
7 <%= labelled_form_for 'task' do |f| %> 7 <%= labelled_form_for 'task' do |f| %>
8 8
9 - <%= required labelled_form_field(_('Title'), text_field(:task, 'article_name', :size => 50)) %> 9 + <%= required labelled_form_field(_('Title'), text_field('task[article]', 'name', :size => 50)) %>
10 10
11 - <%= labelled_form_field(_('Source'), text_field(:task, 'source_name')) %> 11 + <%= labelled_form_field(_('Source'), text_field('task[article]', 'source_name')) %>
12 12
13 - <%= labelled_form_field(_('Source URL'), text_field(:task, 'source')) %> 13 + <%= labelled_form_field(_('Source URL'), text_field('task[article]', 'source')) %>
14 14
15 - <%= required labelled_form_field(_('Your name'), text_field(:task, 'name')) %>  
16 -  
17 - <%= required labelled_form_field(_('Email'), text_field(:task, 'email')) %> 15 + <% unless logged_in? %>
  16 + <%= required labelled_form_field(_('Your name'), text_field(:task, 'name')) %>
  17 + <%= required labelled_form_field(_('Email'), text_field(:task, 'email')) %>
  18 + <% end %>
18 19
19 - <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => :task, :abstract_method => 'article_abstract', :body_method => 'article_body'} %> 20 + <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => 'task[article]'} %>
20 21
21 <%= hidden_field_tag('back_to', @back_to) %> 22 <%= hidden_field_tag('back_to', @back_to) %>
22 23
23 - <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) %> 24 + <%= recaptcha_tags(:display => { :theme => 'clean' }, :ajax => true) unless logged_in? %>
24 25
25 <% button_bar do %> 26 <% button_bar do %>
26 <%= submit_button :save, _('Save') %> 27 <%= submit_button :save, _('Save') %>
app/views/content_viewer/blog_page.html.erb
@@ -18,6 +18,9 @@ @@ -18,6 +18,9 @@
18 format = inside_block.visualization_format 18 format = inside_block.visualization_format
19 paginate = false 19 paginate = false
20 end 20 end
21 - (blog.empty? ? content_tag('em', _('(no posts)')) : list_posts(posts, format, paginate)) 21 + (blog.empty? ?
  22 + content_tag('em', _('(no posts)')) :
  23 + list_posts(posts, format: format, paginate: paginate)
  24 + )
22 %> 25 %>
23 </div> 26 </div>
app/views/features/manage_fields.html.erb
1 <h1><%= _('Manage fields displayed for profiles') %></h1> 1 <h1><%= _('Manage fields displayed for profiles') %></h1>
2 2
  3 +<%= javascript_include_tag "manage-fields.js" %>
  4 +
3 <% tabs = [] %> 5 <% tabs = [] %>
4 <% tabs << {:title => _("Person's fields"), :id => 'person-fields', 6 <% tabs << {:title => _("Person's fields"), :id => 'person-fields',
5 :content => (render :partial => 'manage_person_fields')} %> 7 :content => (render :partial => 'manage_person_fields')} %>
@@ -11,5 +13,3 @@ @@ -11,5 +13,3 @@
11 <% end %> 13 <% end %>
12 14
13 <%= render_tabs(tabs) %> 15 <%= render_tabs(tabs) %>
14 -  
15 -<%= javascript_include_tag "manage-fields.js" %>  
app/views/profile/report_abuse.html.erb
@@ -24,7 +24,7 @@ @@ -24,7 +24,7 @@
24 $('#report-abuse-submit-button').css('cursor', 'progress'); 24 $('#report-abuse-submit-button').css('cursor', 'progress');
25 $.ajax({ 25 $.ajax({
26 type: 'POST', 26 type: 'POST',
27 - url: <%= url_for({:controller => 'profile', :action => 'register_report', :profile => profile.identifier}) %>, 27 + url: <%= url_for({:controller => 'profile', :action => 'register_report', :profile => profile.identifier}).to_json %>,
28 data: $(form).serialize(), 28 data: $(form).serialize(),
29 dataType: 'json', 29 dataType: 'json',
30 success: function(data, status, ajax){ 30 success: function(data, status, ajax){
app/views/profile_editor/edit.html.erb
1 <h1><%= _('Profile settings for %s') % profile.name %></h1> 1 <h1><%= _('Profile settings for %s') % profile.name %></h1>
2 2
3 -<%= javascript_include_tag 'deactivate_profile' %>  
4 <%= error_messages_for :profile_data %> 3 <%= error_messages_for :profile_data %>
5 4
6 <%= labelled_form_for :profile_data, :html => { :id => 'profile-data', :multipart => true } do |f| %> 5 <%= labelled_form_for :profile_data, :html => { :id => 'profile-data', :multipart => true } do |f| %>
app/views/profile_editor/index.html.erb
@@ -28,6 +28,8 @@ @@ -28,6 +28,8 @@
28 28
29 <%= control_panel_button(_('Manage Content'), 'cms', :controller => 'cms') %> 29 <%= control_panel_button(_('Manage Content'), 'cms', :controller => 'cms') %>
30 30
  31 + <%= control_panel_button(_('Manage Roles'), 'roles', :controller => 'profile_roles') %>
  32 +
31 <% unless profile.enterprise? %> 33 <% unless profile.enterprise? %>
32 <%= case profile.blogs.count 34 <%= case profile.blogs.count
33 when 0 35 when 0
app/views/profile_members/change_role.html.erb
1 <h3> <%= _('Changing role of %s') % @member.name %> </h3> 1 <h3> <%= _('Changing role of %s') % @member.name %> </h3>
2 2
3 <%= labelled_form_for :member, :url => {:action => 'update_roles'} do |f| %> 3 <%= labelled_form_for :member, :url => {:action => 'update_roles'} do |f| %>
4 -  
5 - <%= _('Roles:') %> <br> 4 +
  5 + <h4><%= _('Roles:') %></h4>
6 <% @roles.each do |r| %> 6 <% @roles.each do |r| %>
7 <%= labelled_check_box(r.name, 'roles[]', r.id, @associations.map(&:role).include?(r) ) %><br/> 7 <%= labelled_check_box(r.name, 'roles[]', r.id, @associations.map(&:role).include?(r) ) %><br/>
8 <ul class="role-permissions"> 8 <ul class="role-permissions">
@@ -11,6 +11,17 @@ @@ -11,6 +11,17 @@
11 <% end %> 11 <% end %>
12 </ul> 12 </ul>
13 <% end %> 13 <% end %>
  14 + <% unless @custom_roles.empty? %>
  15 + <h4><%= _('Custom Roles:') %></h4>
  16 + <% @custom_roles.each do |r| %>
  17 + <%= labelled_check_box(r.name, 'roles[]', r.id, @associations.map(&:role).include?(r) ) %><br/>
  18 + <ul class="role-permissions">
  19 + <% r.permissions.each do |p| %>
  20 + <li> <%= permission_name(p) %> </li>
  21 + <% end %>
  22 + </ul>
  23 + <% end %>
  24 + <% end %>
14 <%= hidden_field_tag 'person', @member.id %> 25 <%= hidden_field_tag 'person', @member.id %>
15 26
16 <% button_bar do %> 27 <% button_bar do %>
app/views/profile_roles/_form.html.erb 0 → 100644
@@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
  1 +<%= error_messages_for :role %>
  2 +
  3 +<%= labelled_form_for :role, :url => (mode == :edit) ? {:action => 'update', :id => role} : {:action => 'create'} do |f| %>
  4 +
  5 + <%= required_fields_message %>
  6 +
  7 + <%= required f.text_field(:name) %>
  8 +
  9 + <% permissions.each do |key| %>
  10 + <div class="permissions <%= key.downcase %>">
  11 + <h4><%= _('%s Permissions:' % key) %></h4>
  12 + <% ActiveRecord::Base::PERMISSIONS[key].keys.each do |p| %>
  13 + <%= check_box_tag("role[permissions][]", p, role.has_permission?(p), { :id => p }) %>
  14 + <%= content_tag(:label, permission_name(p), { :for => p }) %><br/>
  15 + <% end %>
  16 + </div>
  17 + <% end %>
  18 +
  19 + <% button_bar do %>
  20 + <%= submit_button('save', (mode == :edit) ? _('Save changes') : _('Create role'), :cancel => {:action => 'index'} ) %>
  21 + <% end %>
  22 +<% end %>
app/views/profile_roles/assign.html.erb 0 → 100644
@@ -0,0 +1,35 @@ @@ -0,0 +1,35 @@
  1 +<%= javascript_include_tag('assign_role.js') %>
  2 +
  3 +<h1> <%= _("Assign #{@role.name}") %> </h1>
  4 +
  5 +
  6 +<%= labelled_form_for :role, :url => { :action => 'define', :id => @role.id } do |f| %>
  7 +
  8 + <h2>
  9 + <%= _("Assign role by:") %>
  10 + </h2>
  11 + <p>
  12 + <%= labelled_radio_button _("Members"), :assign_role_by, "members", true, :id => "assign_role_by_members", :class => "assign_role_by" %>
  13 + &nbsp;
  14 + <%= labelled_radio_button _("Roles"), :assign_role_by, "roles", false, :id => "assign_role_by_roles", :class => "assign_role_by" %>
  15 + </p>
  16 + <div class="assign_by_members">
  17 + <%=token_input_field_tag(:person_id, 'search-profile-members', {:action => 'assign_role_by_members'},
  18 + {:focus => false, :hint_text => _('Select members to assign the role')}) %>
  19 +
  20 + <% button_bar do %>
  21 + <%= submit_button(:forward, _("Confirm")) %>
  22 + <% end %>
  23 + </div>
  24 + <div class="assign_by_roles" style="display: none;">
  25 + <h6>
  26 + <%= _("Replace role: ") %>
  27 + </h6>
  28 + <% @roles_list.each do |role| %>
  29 + <%= labelled_radio_button role.name , :selected_role, role.id , false, :class => "selected_role" %> <br>
  30 + <% end %>
  31 + <% button_bar do %>
  32 + <%= submit_button('save',_('Confirm'), :cancel => {:action => 'index'} ) %>
  33 + <% end %>
  34 + </div>
  35 +<% end %>
app/views/profile_roles/destroy.html.erb 0 → 100644
@@ -0,0 +1,23 @@ @@ -0,0 +1,23 @@
  1 +<h1> <%= _("Deleting #{@role.name}") %> </h1>
  2 +
  3 +<% if @members.nil? || @members.empty? %>
  4 + <p><%= _('This role is not being currently used.')%></p>
  5 + <p><%= _('Are you sure you want to delete this role?') %></p>
  6 +
  7 + <% button_bar do %>
  8 + <%= button(:remove, _('Yes, I am sure'), {:action => 'remove', :id => @role.id}, :method => :post) %>
  9 + <%= button(:cancel, _('No, I gave up'), {:action => 'index'}) %>
  10 + <% end %>
  11 +<% else %>
  12 + <p><%= _('There are members currently using this role.')%></p>
  13 + <p><%= _('To which role do you want to change them?') %></p>
  14 + <%= labelled_form_for :role, :url => { :action => 'remove', :id => @role.id } do |f| %>
  15 + <% @roles_list.each do |role| %>
  16 + <%= check_box_tag("roles[]", role.id, false ,{:id => role.key}) %>
  17 + <%= content_tag(:label, role.name, { :for => role.key }) %><br/>
  18 + <% end %>
  19 + <% button_bar do %>
  20 + <%= submit_button('save',_('Delete role'), :cancel => {:action => 'index'} ) %>
  21 + <% end %>
  22 + <% end %>
  23 +<% end %>
app/views/profile_roles/edit.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1> <%= _("Editing #{@role.name}") %> </h1>
  2 +
  3 +<%= render :partial => 'form', :locals => { :mode => :edit, :role => @role, :permissions => [@role.kind] } %>
app/views/profile_roles/index.html.erb 0 → 100644
@@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
  1 +<h1><%= _('Manage user roles') %></h1>
  2 +
  3 +<table>
  4 + <tr>
  5 + <th><%= _('Role') %></th>
  6 + <th><%= _('Actions') %></th>
  7 + </tr>
  8 + <% @roles.each do |role| %>
  9 + <tr>
  10 + <td>
  11 + <%= link_to role.name, :action => 'show', :id => role %>
  12 + </td>
  13 + <td>
  14 + <div style="text-align: center;">
  15 + <%= button_without_text :edit, _('Edit'), :action => 'edit', :id => role %>
  16 + <%= button_without_text :delete, _('Delete'), :action => 'destroy', :id => role %>
  17 + <%= button_without_text 'vertical-toggle', _('Assign'), :action => 'assign', :id => role %>
  18 + </div>
  19 + </td>
  20 + </tr>
  21 + <% end %>
  22 +</table>
  23 +
  24 +<% button_bar do %>
  25 + <%= button :add, _('Create a new role'), :action => 'new' %>
  26 + <%= button :back, _('Back to control panel'), :controller => 'profile_editor' %>
  27 +<% end %>
app/views/profile_roles/new.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h1> <%= _("Create a new role") %> </h1>
  2 +
  3 +<%= render :partial => 'form', :locals => { :mode => :create, :role => @role, :permissions => ['Profile'] } %>
app/views/profile_roles/show.html.erb 0 → 100644
@@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
  1 +<h1> <%= _(@role.name) %></h1>
  2 +
  3 +<h3> <%= _('Permissions') %> </h3>
  4 +<ul>
  5 + <% @role.permissions.each do |p| %>
  6 + <li> <%= permission_name(p) %> </li>
  7 + <% end %>
  8 +</ul>
  9 +
  10 +<% button_bar do %>
  11 + <%= button :edit, _('Edit'), :action => 'edit', :id => @role %>
  12 + <%= button :back, _('Back to roles management'), :action => 'index' %>
  13 +<% end %>
app/views/shared/_profile_search_form.html.erb
  1 +<% search_label = _("Find in %s's content") % profile.short_name %>
1 <%= form_tag( { :controller => 'profile_search', :profile => profile.identifier}, :method => 'get', :class => 'search_form' ) do %> 2 <%= form_tag( { :controller => 'profile_search', :profile => profile.identifier}, :method => 'get', :class => 'search_form' ) do %>
2 <div class="search-field"> 3 <div class="search-field">
3 <span class="formfield"> 4 <span class="formfield">
4 - <%= search_input_with_suggestions 'q', :articles, @q, :title => _("Find in %s's content") % profile.short_name %> 5 + <%= search_input_with_suggestions 'q', :articles, @q, :title => search_label, :placeholder => search_label %>
5 </span> 6 </span>
6 <%= submit_button(:search, _('Search')) %> 7 <%= submit_button(:search, _('Search')) %>
7 <div> 8 <div>
app/views/spam/_suggest_article.html.erb
@@ -7,13 +7,13 @@ @@ -7,13 +7,13 @@
7 <ul class="suggest-article-details" style="display: none"> 7 <ul class="suggest-article-details" style="display: none">
8 <li><strong><%=_('Sent by')%></strong>: <%=task.name%> </li> 8 <li><strong><%=_('Sent by')%></strong>: <%=task.name%> </li>
9 <li><strong><%=_('Email')%></strong>: <%=task.email%> </li> 9 <li><strong><%=_('Email')%></strong>: <%=task.email%> </li>
10 - <li><strong><%=_('Source')%></strong>: <%=task.source_name%> </li>  
11 - <li><strong><%=_('Source URL')%></strong>: <%=task.source%> </li>  
12 - <li><strong><%=_('Folder')%></strong>: <%=(a = Article.find_by_id(task.article_parent_id))?a.name : '<em>' + s_('Folder|none') + '</em>'%> </li>  
13 - <li><strong><%=_('Lead')%></strong>: <%=task.article_abstract.blank? ? '<em>' + s_('Abstract|empty') + '</em>' : task.article_abstract%> </li> 10 + <li><strong><%=_('Source')%></strong>: <%=task.article_object.source_name%> </li>
  11 + <li><strong><%=_('Source URL')%></strong>: <%=task.article_object.source%> </li>
  12 + <li><strong><%=_('Folder')%></strong>: <%=(a = Article.find_by_id(task.article_object.parent_id))?a.name : '<em>' + s_('Folder|none') + '</em>'%> </li>
  13 + <li><strong><%=_('Lead')%></strong>: <%=task.article_object.abstract.blank? ? '<em>' + s_('Abstract|empty') + '</em>' : task.article_object.abstract%> </li>
14 <li><strong><%=_('Body')%></strong>: 14 <li><strong><%=_('Body')%></strong>:
15 <div class='suggest-article-body'> 15 <div class='suggest-article-body'>
16 - <%= task.article_body %> 16 + <%= task.article_object.body %>
17 </div> 17 </div>
18 </li> 18 </li>
19 </ul> 19 </ul>
app/views/tasks/_add_member_accept_details.html.erb
1 <%= content = _("Roles:")+"<br />" 1 <%= content = _("Roles:")+"<br />"
2 -roles = Profile::Roles.organization_member_roles(task.target.environment.id) 2 +roles = Profile::Roles.organization_member_roles(task.target.environment.id) + profile.custom_roles
3 roles.each do |role| 3 roles.each do |role|
4 content += labelled_check_box(role.name, "tasks[#{task.id}][task][roles][]", role.id, false)+"<br />" 4 content += labelled_check_box(role.name, "tasks[#{task.id}][task][roles][]", role.id, false)+"<br />"
5 end 5 end
6 content_tag('p', content, :class => 'member-classify-suggestion') 6 content_tag('p', content, :class => 'member-classify-suggestion')
7 %> 7 %>
8 -  
app/views/tasks/_suggest_article_accept_details.html.erb
1 <%= render :file => 'shared/tiny_mce' %> 1 <%= render :file => 'shared/tiny_mce' %>
2 2
3 -<%= labelled_form_field(_("Sent by: "), f.text_field(:name)) %>  
4 -<p><%= label_tag(_("Email: %s") % task.email) %> </p>  
5 -<%= required labelled_form_field(_('Title'), f.text_field(:article_name, :size => 50)) %>  
6 -<%= labelled_form_field(_('Source'), f.text_field(:source_name)) %>  
7 -<%= labelled_form_field(_("Source URL"), f.text_field(:source)) %> 3 +<% unless task.requestor %>
  4 + <%= labelled_form_field(_("Sent by: "), f.text_field(:name)) %>
  5 + <p><%= label_tag(_("Email: %s") % task.email) %> </p>
  6 +<% end %>
8 7
9 -<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article_parent_id]", task.target) %>  
10 -<%= labelled_form_field(_('Highlight this article'), f.check_box(:highlighted)) %> 8 +<%= f.fields_for 'article', OpenStruct.new(task.article) do |a| %>
  9 + <%= required labelled_form_field(_('Title'), a.text_field(:name, :size => 50)) %>
  10 + <%= labelled_form_field(_('Source'), a.text_field(:source_name)) %>
  11 + <%= labelled_form_field(_("Source URL"), a.text_field(:source)) %>
11 12
12 -<%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :f => f, :abstract_method => 'article_abstract', :body_method => 'article_body', :lead_id => task.id} %> 13 + <%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article][parent_id]", task.target, task.article[:parent_id]) %>
  14 + <%= labelled_form_field(_('Highlight this article'), a.check_box(:highlighted)) %>
  15 +
  16 + <%= a.hidden_field(:type) %>
  17 +
  18 + <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :f => a, :lead_id => task.id} %>
  19 +<% end %>
app/views/user_mailer/profiles_suggestions_email.html.erb
@@ -10,8 +10,8 @@ @@ -10,8 +10,8 @@
10 <% @people_suggestions.each do |person| %> 10 <% @people_suggestions.each do |person| %>
11 <li><a href="<%= url_for(person.public_profile_url) %>"><%= person.name %></a></li> 11 <li><a href="<%= url_for(person.public_profile_url) %>"><%= person.name %></a></li>
12 <% end %> 12 <% end %>
13 - <ul>  
14 - <%= _("To see the full list of friends suggestions, follow the link: %s") % @people_suggestions_url %> 13 + </ul>
  14 + <%= _("To see the full list of friends suggestions, follow the link: %s") % url_for(@people_suggestions_url) %>
15 <% end %> 15 <% end %>
16 16
17 <% unless @communities_suggestions.empty? %> 17 <% unless @communities_suggestions.empty? %>
@@ -21,13 +21,15 @@ @@ -21,13 +21,15 @@
21 <% @communities_suggestions.each do |community| %> 21 <% @communities_suggestions.each do |community| %>
22 <li><a href="<%= url_for(community.public_profile_url) %>"><%= community.name %></a></li> 22 <li><a href="<%= url_for(community.public_profile_url) %>"><%= community.name %></a></li>
23 <% end %> 23 <% end %>
24 - <ul>  
25 - <%= _("To see the full list of communities suggestions, follow the link: %s") % @communities_suggestions_url %> 24 + </ul>
  25 + <%= _("To see the full list of communities suggestions, follow the link: %s") % url_for(@communities_suggestions_url) %>
26 <% end %> 26 <% end %>
27 27
28 28
29 <%= _("Greetings,") %> 29 <%= _("Greetings,") %>
30 30
31 ---  
32 -<%= _('%s team.') % @environment %> 31 +<p><%= _("Greetings,") %></p>
  32 +
  33 +--<br/>
  34 +<%= _('%s team.') % @environment %><br/>
33 <%= @url %> 35 <%= @url %>
config/environments/development.rb
@@ -35,4 +35,8 @@ Noosfero::Application.configure do @@ -35,4 +35,8 @@ Noosfero::Application.configure do
35 config.assets.debug = true 35 config.assets.debug = true
36 36
37 config.consider_all_requests_local = true 37 config.consider_all_requests_local = true
  38 +
  39 + # send emails to /tmp/mails
  40 + config.action_mailer.delivery_method = :file
  41 +
38 end 42 end
config/routes.rb
@@ -56,37 +56,37 @@ Noosfero::Application.routes.draw do @@ -56,37 +56,37 @@ Noosfero::Application.routes.draw do
56 match 'search(/:action(/*category_path))', :controller => 'search' 56 match 'search(/:action(/*category_path))', :controller => 'search'
57 57
58 # events 58 # events
59 - match 'profile/:profile/events_by_day', :controller => 'events', :action => 'events_by_day', :profile => /#{Noosfero.identifier_format}/  
60 - match 'profile/:profile/events_by_month', :controller => 'events', :action => 'events_by_month', :profile => /#{Noosfero.identifier_format}/  
61 - match 'profile/:profile/events/:year/:month/:day', :controller => 'events', :action => 'events', :year => /\d*/, :month => /\d*/, :day => /\d*/, :profile => /#{Noosfero.identifier_format}/  
62 - match 'profile/:profile/events/:year/:month', :controller => 'events', :action => 'events', :year => /\d*/, :month => /\d*/, :profile => /#{Noosfero.identifier_format}/  
63 - match 'profile/:profile/events', :controller => 'events', :action => 'events', :profile => /#{Noosfero.identifier_format}/ 59 + match 'profile/:profile/events_by_day', :controller => 'events', :action => 'events_by_day', :profile => /#{Noosfero.identifier_format_in_url}/
  60 + match 'profile/:profile/events_by_month', :controller => 'events', :action => 'events_by_month', :profile => /#{Noosfero.identifier_format_in_url}/
  61 + match 'profile/:profile/events/:year/:month/:day', :controller => 'events', :action => 'events', :year => /\d*/, :month => /\d*/, :day => /\d*/, :profile => /#{Noosfero.identifier_format_in_url}/
  62 + match 'profile/:profile/events/:year/:month', :controller => 'events', :action => 'events', :year => /\d*/, :month => /\d*/, :profile => /#{Noosfero.identifier_format_in_url}/
  63 + match 'profile/:profile/events', :controller => 'events', :action => 'events', :profile => /#{Noosfero.identifier_format_in_url}/
64 64
65 # catalog 65 # catalog
66 - match 'catalog/:profile', :controller => 'catalog', :action => 'index', :profile => /#{Noosfero.identifier_format}/, :as => :catalog 66 + match 'catalog/:profile', :controller => 'catalog', :action => 'index', :profile => /#{Noosfero.identifier_format_in_url}/, :as => :catalog
67 67
68 # invite 68 # invite
69 - match 'profile/:profile/invite/friends', :controller => 'invite', :action => 'invite_friends', :profile => /#{Noosfero.identifier_format}/  
70 - match 'profile/:profile/invite/:action', :controller => 'invite', :profile => /#{Noosfero.identifier_format}/ 69 + match 'profile/:profile/invite/friends', :controller => 'invite', :action => 'invite_friends', :profile => /#{Noosfero.identifier_format_in_url}/
  70 + match 'profile/:profile/invite/:action', :controller => 'invite', :profile => /#{Noosfero.identifier_format_in_url}/
71 71
72 # feeds per tag 72 # feeds per tag
73 - match 'profile/:profile/tags/:id/feed', :controller => 'profile', :action =>'tag_feed', :id => /.+/, :profile => /#{Noosfero.identifier_format}/, :as => :tag_feed 73 + match 'profile/:profile/tags/:id/feed', :controller => 'profile', :action =>'tag_feed', :id => /.+/, :profile => /#{Noosfero.identifier_format_in_url}/, :as => :tag_feed
74 74
75 # profile tags 75 # profile tags
76 - match 'profile/:profile/tags/:id', :controller => 'profile', :action => 'content_tagged', :id => /.+/, :profile => /#{Noosfero.identifier_format}/  
77 - match 'profile/:profile/tags(/:id)', :controller => 'profile', :action => 'tags', :profile => /#{Noosfero.identifier_format}/ 76 + match 'profile/:profile/tags/:id', :controller => 'profile', :action => 'content_tagged', :id => /.+/, :profile => /#{Noosfero.identifier_format_in_url}/
  77 + match 'profile/:profile/tags(/:id)', :controller => 'profile', :action => 'tags', :profile => /#{Noosfero.identifier_format_in_url}/
78 78
79 # profile search 79 # profile search
80 - match 'profile/:profile/search', :controller => 'profile_search', :action => 'index', :profile => /#{Noosfero.identifier_format}/ 80 + match 'profile/:profile/search', :controller => 'profile_search', :action => 'index', :profile => /#{Noosfero.identifier_format_in_url}/
81 81
82 # comments 82 # comments
83 - match 'profile/:profile/comment/:action/:id', :controller => 'comment', :profile => /#{Noosfero.identifier_format}/ 83 + match 'profile/:profile/comment/:action/:id', :controller => 'comment', :profile => /#{Noosfero.identifier_format_in_url}/
84 84
85 # public profile information 85 # public profile information
86 - match 'profile/:profile(/:action(/:id))', :controller => 'profile', :action => 'index', :id => /[^\/]*/, :profile => /#{Noosfero.identifier_format}/, :as => :profile 86 + match 'profile/:profile(/:action(/:id))', :controller => 'profile', :action => 'index', :id => /[^\/]*/, :profile => /#{Noosfero.identifier_format_in_url}/, :as => :profile
87 87
88 # contact 88 # contact
89 - match 'contact/:profile/:action(/:id)', :controller => 'contact', :action => 'index', :id => /.*/, :profile => /#{Noosfero.identifier_format}/ 89 + match 'contact/:profile/:action(/:id)', :controller => 'contact', :action => 'index', :id => /.*/, :profile => /#{Noosfero.identifier_format_in_url}/
90 90
91 # map balloon 91 # map balloon
92 match 'map_balloon/:action/:id', :controller => 'map_balloon', :id => /.*/ 92 match 'map_balloon/:action/:id', :controller => 'map_balloon', :id => /.*/
@@ -98,8 +98,8 @@ Noosfero::Application.routes.draw do @@ -98,8 +98,8 @@ Noosfero::Application.routes.draw do
98 ## Controllers that are profile-specific (for profile admins ) 98 ## Controllers that are profile-specific (for profile admins )
99 ###################################################### 99 ######################################################
100 # profile customization - "My profile" 100 # profile customization - "My profile"
101 - match 'myprofile/:profile', :controller => 'profile_editor', :action => 'index', :profile => /#{Noosfero.identifier_format}/  
102 - match 'myprofile/:profile/:controller(/:action(/:id))', :controller => Noosfero.pattern_for_controllers_in_directory('my_profile'), :profile => /#{Noosfero.identifier_format}/, :as => :myprofile 101 + match 'myprofile/:profile', :controller => 'profile_editor', :action => 'index', :profile => /#{Noosfero.identifier_format_in_url}/
  102 + match 'myprofile/:profile/:controller(/:action(/:id))', :controller => Noosfero.pattern_for_controllers_in_directory('my_profile'), :profile => /#{Noosfero.identifier_format_in_url}/, :as => :myprofile
103 103
104 104
105 ###################################################### 105 ######################################################
@@ -127,14 +127,14 @@ Noosfero::Application.routes.draw do @@ -127,14 +127,14 @@ Noosfero::Application.routes.draw do
127 # cache stuff - hack 127 # cache stuff - hack
128 match 'public/:action/:id', :controller => 'public' 128 match 'public/:action/:id', :controller => 'public'
129 129
130 - match ':profile/*page/versions', :controller => 'content_viewer', :action => 'article_versions', :profile => /#{Noosfero.identifier_format}/, :constraints => EnvironmentDomainConstraint.new 130 + match ':profile/*page/versions', :controller => 'content_viewer', :action => 'article_versions', :profile => /#{Noosfero.identifier_format_in_url}/, :constraints => EnvironmentDomainConstraint.new
131 match '*page/versions', :controller => 'content_viewer', :action => 'article_versions' 131 match '*page/versions', :controller => 'content_viewer', :action => 'article_versions'
132 132
133 - match ':profile/*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff', :profile => /#{Noosfero.identifier_format}/, :constraints => EnvironmentDomainConstraint.new 133 + match ':profile/*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff', :profile => /#{Noosfero.identifier_format_in_url}/, :constraints => EnvironmentDomainConstraint.new
134 match '*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff' 134 match '*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff'
135 135
136 # match requests for profiles that don't have a custom domain 136 # match requests for profiles that don't have a custom domain
137 - match ':profile(/*page)', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format}/, :constraints => EnvironmentDomainConstraint.new 137 + match ':profile(/*page)', :controller => 'content_viewer', :action => 'view_page', :profile => /#{Noosfero.identifier_format_in_url}/, :constraints => EnvironmentDomainConstraint.new
138 138
139 # match requests for content in domains hosted for profiles 139 # match requests for content in domains hosted for profiles
140 match '/(*page)', :controller => 'content_viewer', :action => 'view_page' 140 match '/(*page)', :controller => 'content_viewer', :action => 'view_page'
db/migrate/20150203143051_add_reference_to_role.rb 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +class AddReferenceToRole < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :roles, :profile_id, :integer
  4 + end
  5 + def self.down
  6 + remove_column :roles , :profile_id
  7 + end
  8 +end
db/migrate/20150210143723_add_custom_roles_permission_to_admin_roles.rb 0 → 100644
@@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
  1 +class AddCustomRolesPermissionToAdminRoles < ActiveRecord::Migration
  2 + def self.up
  3 + environment_admin = Role.find_by_key("environment_administrator")
  4 + profile_admin = Role.find_by_key("profile_admin")
  5 + environment_admin.permissions.append("manage_custom_roles")
  6 + profile_admin.permissions.append("manage_custom_roles")
  7 + environment_admin.save!
  8 + profile_admin.save!
  9 + end
  10 + def self.down
  11 + environment_admin = Role.find_by_key("environment_administrator")
  12 + profile_admin = Role.find_by_key("profile_admin")
  13 + environment_admin.permissions.delete("manage_custom_roles")
  14 + profile_admin.permissions.delete("manage_custom_roles")
  15 + environment_admin.save!
  16 + profile_admin.save!
  17 + end
  18 +end
db/migrate/20150423144533_add_new_box_to_every_environment_and_profile.rb 0 → 100644
@@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
  1 +class AddNewBoxToEveryEnvironmentAndProfile < ActiveRecord::Migration
  2 + def up
  3 + Environment.find_each do |env|
  4 + env.boxes << Box.new if env.boxes.count < 4
  5 + end
  6 +
  7 + Profile.find_each do |profile|
  8 + profile.boxes << Box.new if profile.boxes.count < 4
  9 + end
  10 + end
  11 +
  12 + def down
  13 + say "this migration can't be reverted"
  14 + end
  15 +end
@@ -593,6 +593,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do @@ -593,6 +593,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do
593 t.boolean "system", :default => false 593 t.boolean "system", :default => false
594 t.text "permissions" 594 t.text "permissions"
595 t.integer "environment_id" 595 t.integer "environment_id"
  596 + t.integer "profile_id"
596 end 597 end
597 598
598 create_table "scraps", :force => true do |t| 599 create_table "scraps", :force => true do |t|
debian/changelog
  1 +noosfero (1.2~0) UNRELEASED; urgency=medium
  2 +
  3 + * Temporary version in heavy development
  4 +
  5 + -- Antonio Terceiro <terceiro@debian.org> Fri, 08 May 2015 16:08:18 -0300
  6 +
  7 +noosfero (1.1) wheezy; urgency=low
  8 +
  9 + * Noosfero 1.1 final release
  10 +
  11 + -- Antonio Terceiro <terceiro@colivre.coop.br> Mon, 04 May 2015 18:47:35 -0300
  12 +
1 noosfero (1.1~rc4) wheezy; urgency=medium 13 noosfero (1.1~rc4) wheezy; urgency=medium
2 14
3 * Fourth release candidate for Noosfero 1.1 15 * Fourth release candidate for Noosfero 1.1
debian/control
@@ -14,8 +14,8 @@ Build-Depends: cucumber, @@ -14,8 +14,8 @@ Build-Depends: cucumber,
14 ruby-database-cleaner, 14 ruby-database-cleaner,
15 ruby-gettext, 15 ruby-gettext,
16 ruby-mocha, 16 ruby-mocha,
17 - ruby-rspec,  
18 - ruby-rspec-rails, 17 + ruby-rspec (>= 2.14),
  18 + ruby-rspec-rails (>= 2.14),
19 ruby-selenium-webdriver, 19 ruby-selenium-webdriver,
20 ruby-sqlite3, 20 ruby-sqlite3,
21 ruby-tidy, 21 ruby-tidy,
@@ -59,7 +59,9 @@ Depends: adduser, @@ -59,7 +59,9 @@ Depends: adduser,
59 ruby-redcloth, 59 ruby-redcloth,
60 ruby-rest-client, 60 ruby-rest-client,
61 ruby-rmagick, 61 ruby-rmagick,
  62 + ruby-sass-rails,
62 ruby-tzinfo (>= 1.1.0-2~), 63 ruby-tzinfo (>= 1.1.0-2~),
  64 + ruby-uglifier,
63 ruby-whenever, 65 ruby-whenever,
64 ruby-will-paginate (>= 2.3.12-1~), 66 ruby-will-paginate (>= 2.3.12-1~),
65 tango-icon-theme, 67 tango-icon-theme,
debian/noosfero.install
@@ -25,6 +25,7 @@ etc/init.d/noosfero etc/init.d @@ -25,6 +25,7 @@ etc/init.d/noosfero etc/init.d
25 etc/logrotate.d/noosfero etc/logrotate.d 25 etc/logrotate.d/noosfero etc/logrotate.d
26 etc/noosfero/varnish-accept-language.vcl etc/noosfero 26 etc/noosfero/varnish-accept-language.vcl etc/noosfero
27 etc/noosfero/varnish-noosfero.vcl etc/noosfero 27 etc/noosfero/varnish-noosfero.vcl etc/noosfero
  28 +etc/awstats-noosfero.conf etc/noosfero
28 lib usr/share/noosfero 29 lib usr/share/noosfero
29 locale usr/share/noosfero 30 locale usr/share/noosfero
30 plugins usr/share/noosfero 31 plugins usr/share/noosfero
features/change_appearance.feature 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +Feature: Change appearance
  2 + As a user
  3 + I want to change the appearance of my profile page
  4 +
  5 + Background:
  6 + Given the following users
  7 + | login | name |
  8 + | joaosilva | Joao Silva |
  9 +
  10 + Scenario: Change appearance from default(3 boxes) to Left Top and Right(4 boxes)
  11 + Given I am logged in as "joaosilva"
  12 + And I go to joaosilva's control panel
  13 + And I follow "Edit sideboxes"
  14 + And I should not see an element ".box-4"
  15 + And I go to joaosilva's control panel
  16 + And I follow "Edit Appearance"
  17 + And I follow "Left Top and Right"
  18 + And I go to joaosilva's control panel
  19 + And I follow "Edit sideboxes"
  20 + And I should see an element ".box-4"
features/signup.feature
@@ -267,32 +267,6 @@ Feature: signup @@ -267,32 +267,6 @@ Feature: signup
267 Then I should be on the homepage 267 Then I should be on the homepage
268 268
269 @selenium 269 @selenium
270 - Scenario: join community on signup  
271 - Given the following users  
272 - | login | name |  
273 - | mariasilva | Maria Silva |  
274 - And the following communities  
275 - | name | identifier | owner |  
276 - | Free Software | freesoftware | mariasilva |  
277 - And feature "skip_new_user_email_confirmation" is disabled on environment  
278 - And I am on /freesoftware  
279 - When I follow "Join"  
280 - And I follow "New user"  
281 - And I fill in the following within ".no-boxes":  
282 - | e-Mail | josesilva@example.com |  
283 - | Username | josesilva |  
284 - | Password | secret |  
285 - | Password confirmation | secret |  
286 - | Full name | José da Silva |  
287 - And wait for the captcha signup time  
288 - And I press "Create my account"  
289 - And I go to josesilva's confirmation URL  
290 - And I fill in "Username" with "josesilva"  
291 - And I fill in "Password" with "secret"  
292 - And I press "Log in"  
293 - Then "José da Silva" should be a member of "Free Software"  
294 -  
295 - @selenium  
296 Scenario: user registration is moderated by admin 270 Scenario: user registration is moderated by admin
297 Given feature "admin_must_approve_new_users" is enabled on environment 271 Given feature "admin_must_approve_new_users" is enabled on environment
298 And feature "skip_new_user_email_confirmation" is disabled on environment 272 And feature "skip_new_user_email_confirmation" is disabled on environment
features/step_definitions/noosfero_steps.rb
@@ -94,8 +94,8 @@ Given /^the following blocks$/ do |table| @@ -94,8 +94,8 @@ Given /^the following blocks$/ do |table|
94 owner.boxes<< Box.new 94 owner.boxes<< Box.new
95 owner.boxes.first.blocks << MainBlock.new 95 owner.boxes.first.blocks << MainBlock.new
96 end 96 end
97 - box_id = owner.boxes.last.id  
98 - klass.constantize.create!(item.merge(:box_id => box_id)) 97 + box = owner.boxes.where(:position => 3).first
  98 + klass.constantize.create!(item.merge(:box => box))
99 end 99 end
100 end 100 end
101 101
lib/authenticated_system.rb
@@ -60,7 +60,11 @@ module AuthenticatedSystem @@ -60,7 +60,11 @@ module AuthenticatedSystem
60 if logged_in? && authorized? 60 if logged_in? && authorized?
61 true 61 true
62 else 62 else
63 - access_denied 63 + if params[:require_login_popup]
  64 + render :json => { :require_login_popup => true }
  65 + else
  66 + access_denied
  67 + end
64 end 68 end
65 end 69 end
66 70
lib/noosfero.rb
@@ -57,6 +57,12 @@ module Noosfero @@ -57,6 +57,12 @@ module Noosfero
57 '[a-z0-9][a-z0-9~.]*([_\-][a-z0-9~.]+)*' 57 '[a-z0-9][a-z0-9~.]*([_\-][a-z0-9~.]+)*'
58 end 58 end
59 59
  60 + # All valid identifiers, plus ~ meaning "the current user". See
  61 + # ApplicationController#redirect_to_current_user
  62 + def self.identifier_format_in_url
  63 + "(#{identifier_format}|~)"
  64 + end
  65 +
60 def self.default_hostname 66 def self.default_hostname
61 Environment.table_exists? && Environment.default ? Environment.default.default_hostname : 'localhost' 67 Environment.table_exists? && Environment.default ? Environment.default.default_hostname : 'localhost'
62 end 68 end
lib/noosfero/plugin.rb
@@ -8,6 +8,10 @@ class Noosfero::Plugin @@ -8,6 +8,10 @@ class Noosfero::Plugin
8 self.context = context 8 self.context = context
9 end 9 end
10 10
  11 + def environment
  12 + context.environment if self.context
  13 + end
  14 +
11 class << self 15 class << self
12 16
13 attr_writer :should_load 17 attr_writer :should_load
@@ -35,6 +39,7 @@ class Noosfero::Plugin @@ -35,6 +39,7 @@ class Noosfero::Plugin
35 # filters must be loaded after all extensions 39 # filters must be loaded after all extensions
36 klasses.each do |plugin| 40 klasses.each do |plugin|
37 load_plugin_filters plugin 41 load_plugin_filters plugin
  42 + load_plugin_hotspots plugin
38 end 43 end
39 end 44 end
40 45
@@ -108,6 +113,23 @@ class Noosfero::Plugin @@ -108,6 +113,23 @@ class Noosfero::Plugin
108 end 113 end
109 end 114 end
110 115
  116 + # This is a generic method to extend the hotspots list with plugins
  117 + # hotspots. This allows plugins to extend other plugins.
  118 + # To use this, the plugin must define its hotspots inside a module Hotspots.
  119 + # Its also needed to include Noosfero::Plugin::HotSpot module
  120 + # in order to dispatch plugins methods.
  121 + #
  122 + # Checkout FooPlugin for usage example.
  123 + def load_plugin_hotspots(plugin)
  124 + ActionDispatch::Reloader.to_prepare do
  125 + begin
  126 + module_name = "#{plugin.name}::Hotspots"
  127 + Noosfero::Plugin.send(:include, module_name.constantize)
  128 + rescue NameError
  129 + end
  130 + end
  131 + end
  132 +
111 def add_controller_filters(controller_class, plugin, filters) 133 def add_controller_filters(controller_class, plugin, filters)
112 unless filters.is_a?(Array) 134 unless filters.is_a?(Array)
113 filters = [filters] 135 filters = [filters]
lib/noosfero/version.rb
1 module Noosfero 1 module Noosfero
2 PROJECT = 'noosfero' 2 PROJECT = 'noosfero'
3 - VERSION = '1.1~rc4' 3 + VERSION = '1.2~0'
4 end 4 end
5 5
6 root = File.expand_path(File.dirname(__FILE__) + '/../..') 6 root = File.expand_path(File.dirname(__FILE__) + '/../..')
lib/tasks/backup.rake
1 -desc "Creates a backup of the user files stored in public/"  
2 -task :backup do  
3 - dirs = Dir.glob('public/images/[0-9][0-9][0-9][0-9]') + ['public/articles', 'public/thumbnails', 'public/user_themes'].select { |d| File.exists?(d) }  
4 - tarball = 'backups/files-' + Time.now.strftime('%Y-%m-%d-%R') + '.tar' 1 +task :load_backup_config do
  2 + $config = YAML.load_file('config/database.yml')
  3 +end
  4 +
  5 +task :check_backup_support => :load_backup_config do
  6 + if $config['production']['adapter'] != 'postgresql'
  7 + fail("Only PostgreSQL is supported for backups at the moment")
  8 + end
  9 +end
  10 +
  11 +backup_dirs = [
  12 + 'public/image_uploads',
  13 + 'public/articles',
  14 + 'public/thumbnails',
  15 + 'public/user_themes',
  16 +]
  17 +
  18 +desc "Creates a backup of the database and uploaded files"
  19 +task :backup => :check_backup_support do
  20 + dirs = backup_dirs.select { |d| File.exists?(d) }
  21 +
  22 + backup_name = Time.now.strftime('%Y-%m-%d-%R')
  23 + backup_file = File.join('tmp/backup', backup_name) + '.tar.gz'
  24 + mkdir_p 'tmp/backup'
  25 + dump = File.join('tmp/backup', backup_name) + '.sql'
  26 +
  27 + database = $config['production']['database']
  28 + host = $config['production']['host']
  29 + sh "pg_dump -h #{host} #{database} > #{dump}"
  30 +
  31 + sh 'tar', 'chaf', backup_file, dump, *dirs
  32 + rm_f dump
  33 +
  34 + puts "****************************************************"
  35 + puts "Backup in #{backup_file} !"
  36 + puts
  37 + puts "To restore, use:"
  38 + puts "$ rake restore BACKUP=#{backup_file}"
  39 + puts "****************************************************"
  40 +end
  41 +
  42 +def invalid_backup!(message, items=[])
  43 + puts "E: #{message}"
  44 + items.each do |i|
  45 + puts "E: - #{i}"
  46 + end
  47 + puts "E: Is this a backup archive created by Noosfero with \`rake backup\`?"
  48 + exit 1
  49 +end
  50 +
  51 +desc "Restores a backup created previousy with \`rake backup\`"
  52 +task :restore => :check_backup_support do
  53 + backup = ENV["BACKUP"]
  54 + unless backup
  55 + puts "usage: rake restore BACKUP=/path/to/backup"
  56 + exit 1
  57 + end
  58 +
  59 + files = `tar taf #{backup}`.split
  60 +
  61 + # validate files in the backup
  62 + invalid_files = []
  63 + files.each do |f|
  64 + if f !~ /tmp\/backup\// && (backup_dirs.none? { |d| f =~ /^#{d}\// })
  65 + invalid_files << f
  66 + end
  67 + end
  68 + if invalid_files.size > 0
  69 + invalid_backup!("Invalid files found in the backup archive", invalid_files)
  70 + end
  71 +
  72 + # find database dump in the archive
  73 + dumps = files.select do |f|
  74 + File.dirname(f) == 'tmp/backup' && f =~ /\.sql$/
  75 + end
  76 + if dumps.size == 0
  77 + invalid_backup!("Could not find a database dump in the archive.")
  78 + elsif dumps.size > 1
  79 + invalid_backup!("Multiple database dumps found in the archive:", dumps)
  80 + end
  81 + dump = dumps.first
  82 +
  83 + database = $config['production']['database']
  84 + username = $config['production']['username']
  85 + host = $config['production']['host']
  86 +
  87 + puts "WARNING: backups should be restored to an empty database, otherwise"
  88 + puts "data from the backup may not be loaded properly."
  89 + puts
  90 + puts 'You can remove the existing database and create a new one with:'
  91 + puts
  92 + puts "$ sudo -u postgres dropdb -h #{host} #{database}"
  93 + puts "$ sudo -u postgres createdb -h #{host} #{database} --owner #{username}"
  94 + puts
  95 + print "Are you sure you want to continue (y/N)? "
  96 + response = $stdin.gets.strip
  97 + unless ['y', 'yes'].include?(response.downcase)
  98 + puts "*** ABORTED."
  99 + exit 1
  100 + end
  101 +
  102 + sh 'tar', 'xaf', backup
  103 + sh "rails dbconsole production < #{dump}"
  104 + rm_f dump
5 105
6 - mkdir_p(File.dirname(tarball))  
7 - sh('tar', 'cf', tarball, *dirs) 106 + puts "****************************************************"
  107 + puts "Backup restored!"
  108 + puts "****************************************************"
8 end 109 end
lib/tasks/doc.rake
@@ -12,9 +12,8 @@ namespace :noosfero do @@ -12,9 +12,8 @@ namespace :noosfero do
12 end 12 end
13 end 13 end
14 task :unlink_plugins_textiles do 14 task :unlink_plugins_textiles do
15 - root = Pathname.new(File.dirname(__FILE__) + '/../..').expand_path  
16 - rm_f Dir.glob(root.join('doc/noosfero/plugins/*.textile')) -  
17 - [root.join('doc/noosfero/plugins/index.textile')] 15 + rm_f Dir.glob('doc/noosfero/plugins/*.textile') -
  16 + ['doc/noosfero/plugins/index.textile']
18 end 17 end
19 input = Dir.glob('doc/noosfero/**/*.textile') + plugins_textiles.map{|i| "doc/noosfero/plugins/#{File.basename(i)}"} 18 input = Dir.glob('doc/noosfero/**/*.textile') + plugins_textiles.map{|i| "doc/noosfero/plugins/#{File.basename(i)}"}
20 topics_xhtml = input.map { |item| item.sub('.textile', '.en.xhtml') }.uniq 19 topics_xhtml = input.map { |item| item.sub('.textile', '.en.xhtml') }.uniq
lib/tasks/error_messages.rake
@@ -4,7 +4,7 @@ targets = [] @@ -4,7 +4,7 @@ targets = []
4 templates.each do |template| 4 templates.each do |template|
5 target = template.gsub(/.erb$/, '') 5 target = template.gsub(/.erb$/, '')
6 targets << target 6 targets << target
7 - file target => [:makemo, template] do 7 + file target => [:makemo, template, :environment] do
8 require 'erb' 8 require 'erb'
9 erb = ERB.new(File.read(template)) 9 erb = ERB.new(File.read(template))
10 File.open(target, 'w') do |file| 10 File.open(target, 'w') do |file|
plugins/event/po/pt/event.po
@@ -5,8 +5,8 @@ @@ -5,8 +5,8 @@
5 # 5 #
6 msgid "" 6 msgid ""
7 msgstr "" 7 msgstr ""
8 -"Project-Id-Version: 1.0-690-gcb6e853\n"  
9 -"POT-Creation-Date: 2015-03-05 12:09-0300\n" 8 +"Project-Id-Version: 1.1~rc4\n"
  9 +"POT-Creation-Date: 2015-04-20 19:44-0300\n"
10 "PO-Revision-Date: 2015-01-30 00:18-0000\n" 10 "PO-Revision-Date: 2015-01-30 00:18-0000\n"
11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" 11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 "Language-Team: LANGUAGE <LL@li.org>\n" 12 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,61 +16,53 @@ msgstr &quot;&quot; @@ -16,61 +16,53 @@ msgstr &quot;&quot;
16 "Content-Transfer-Encoding: 8bit\n" 16 "Content-Transfer-Encoding: 8bit\n"
17 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" 17 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
18 18
  19 +#: plugins/event/lib/event_plugin.rb:4
  20 +msgid "Event Extras"
  21 +msgstr "Extras para Eventos"
  22 +
  23 +#: plugins/event/lib/event_plugin.rb:8
  24 +msgid ""
  25 +"Include a new block to show the environment's or profiles' events information"
  26 +msgstr ""
  27 +"Adiciona um novo bloco para apresentar as informações de eventos do ambiente "
  28 +"ou dos perfis"
  29 +
19 #: plugins/event/lib/event_plugin/event_block.rb:12 30 #: plugins/event/lib/event_plugin/event_block.rb:12
20 msgid "Events" 31 msgid "Events"
21 msgstr "Eventos" 32 msgstr "Eventos"
22 33
23 #: plugins/event/lib/event_plugin/event_block.rb:16 34 #: plugins/event/lib/event_plugin/event_block.rb:16
24 msgid "Show the profile events or all environment events." 35 msgid "Show the profile events or all environment events."
25 -msgstr "Mostrar todos os eventos." 36 +msgstr "Mostra todos os eventos de um perfil ou do ambiente."
26 37
27 #: plugins/event/lib/event_plugin/event_block.rb:65 38 #: plugins/event/lib/event_plugin/event_block.rb:65
28 -#, fuzzy  
29 msgid "One month ago" 39 msgid "One month ago"
30 msgid_plural "%d months ago" 40 msgid_plural "%d months ago"
31 -msgstr[0] "Iniciou a um mês atrás."  
32 -msgstr[1] "Iniciou a %d meses atrás." 41 +msgstr[0] "Um mês atrás"
  42 +msgstr[1] "%d meses atrás."
33 43
34 #: plugins/event/lib/event_plugin/event_block.rb:67 44 #: plugins/event/lib/event_plugin/event_block.rb:67
35 msgid "Yesterday" 45 msgid "Yesterday"
36 msgid_plural "%d days ago" 46 msgid_plural "%d days ago"
37 -msgstr[0] ""  
38 -msgstr[1] "" 47 +msgstr[0] "Ontem"
  48 +msgstr[1] "%d dias atrás"
39 49
40 #: plugins/event/lib/event_plugin/event_block.rb:69 50 #: plugins/event/lib/event_plugin/event_block.rb:69
41 msgid "Today" 51 msgid "Today"
42 -msgstr "" 52 +msgstr "Hoje"
43 53
44 #: plugins/event/lib/event_plugin/event_block.rb:71 54 #: plugins/event/lib/event_plugin/event_block.rb:71
45 msgid "Tomorrow" 55 msgid "Tomorrow"
46 msgid_plural "%d days left to start" 56 msgid_plural "%d days left to start"
47 -msgstr[0] ""  
48 -msgstr[1] "" 57 +msgstr[0] "Amanhã"
  58 +msgstr[1] "%d dias para começar"
49 59
50 #: plugins/event/lib/event_plugin/event_block.rb:73 60 #: plugins/event/lib/event_plugin/event_block.rb:73
51 -#, fuzzy  
52 msgid "One month left to start" 61 msgid "One month left to start"
53 msgid_plural "%d months left to start" 62 msgid_plural "%d months left to start"
54 msgstr[0] "Um mês para iniciar" 63 msgstr[0] "Um mês para iniciar"
55 msgstr[1] "% meses para iniciar" 64 msgstr[1] "% meses para iniciar"
56 65
57 -#: plugins/event/lib/event_plugin.rb:4  
58 -msgid "Event Extras"  
59 -msgstr "Eventos"  
60 -  
61 -#: plugins/event/lib/event_plugin.rb:8  
62 -msgid ""  
63 -"Include a new block to show the environment's or profiles' events information"  
64 -msgstr ""  
65 -"Adiciona um novo bloco para apresentar as informações de eventos do ambiente "  
66 -"ou de perfis"  
67 -  
68 -#: plugins/event/views/event_plugin/event_block_item.html.erb:6  
69 -msgid "Duration: 1 day"  
70 -msgid_plural "Duration: %s days"  
71 -msgstr[0] ""  
72 -msgstr[1] ""  
73 -  
74 #: plugins/event/views/profile_design/event_plugin/_event_block.html.erb:1 66 #: plugins/event/views/profile_design/event_plugin/_event_block.html.erb:1
75 msgid "Limit of items" 67 msgid "Limit of items"
76 msgstr "Limite de itens" 68 msgstr "Limite de itens"
@@ -94,12 +86,17 @@ msgstr &quot;Mostrar apenas eventos futuros&quot; @@ -94,12 +86,17 @@ msgstr &quot;Mostrar apenas eventos futuros&quot;
94 86
95 #: plugins/event/views/profile_design/event_plugin/_event_block.html.erb:22 87 #: plugins/event/views/profile_design/event_plugin/_event_block.html.erb:22
96 msgid "Limit of days to display" 88 msgid "Limit of days to display"
97 -msgstr "Limite de dias de distância para mostrar eventos" 89 +msgstr "Limite de dias para mostrar"
98 90
99 #: plugins/event/views/profile_design/event_plugin/_event_block.html.erb:24 91 #: plugins/event/views/profile_design/event_plugin/_event_block.html.erb:24
100 -#, fuzzy  
101 msgid "Only show events in this interval of days." 92 msgid "Only show events in this interval of days."
102 -msgstr "Mostar somente eventos que acontecem dentro do limite de dias" 93 +msgstr "Mostar somente os eventos nesse intervalo de dias"
  94 +
  95 +#: plugins/event/views/event_plugin/event_block_item.html.erb:6
  96 +msgid "Duration: 1 day"
  97 +msgid_plural "Duration: %s days"
  98 +msgstr[0] "Duração: 1 dia"
  99 +msgstr[1] "Duração: %s dias"
103 100
104 #~ msgid "Started one day ago." 101 #~ msgid "Started one day ago."
105 #~ msgid_plural "Started %d days ago." 102 #~ msgid_plural "Started %d days ago."
plugins/foo/lib/foo_plugin.rb
1 class FooPlugin < Noosfero::Plugin 1 class FooPlugin < Noosfero::Plugin
  2 + include Noosfero::Plugin::HotSpot
2 3
3 def self.plugin_name 4 def self.plugin_name
4 "Foo" 5 "Foo"
@@ -8,12 +9,29 @@ class FooPlugin &lt; Noosfero::Plugin @@ -8,12 +9,29 @@ class FooPlugin &lt; Noosfero::Plugin
8 _("A sample plugin to test autoload craziness.") 9 _("A sample plugin to test autoload craziness.")
9 end 10 end
10 11
  12 + module Hotspots
  13 + # -> Custom foo plugin hotspot
  14 + # do something to extend the FooPlugin behaviour
  15 + # receive params a, b and c
  16 + # returns = boolean or something else
  17 + def foo_plugin_my_hotspot(a, b, c)
  18 + end
  19 +
  20 + # -> Custom title for foo profiles tab
  21 + # returns = a string with a custom title
  22 + def foo_plugin_tab_title
  23 + end
  24 + end
  25 +
11 def control_panel_buttons 26 def control_panel_buttons
12 {:title => 'Foo plugin button', :icon => '', :url => ''} 27 {:title => 'Foo plugin button', :icon => '', :url => ''}
13 end 28 end
14 29
15 def profile_tabs 30 def profile_tabs
16 - {:title => 'Foo plugin tab', :id => 'foo_plugin', :content => lambda {'Foo plugin random content'} } 31 + title = plugins.dispatch_first(:foo_plugin_tab_title)
  32 + title = 'Foo plugin tab' unless title
  33 +
  34 + {:title => title, :id => 'foo_plugin', :content => lambda {'Foo plugin random content'} }
17 end 35 end
18 36
19 end 37 end
plugins/foo/test/unit/foo_plugin_test.rb
@@ -4,7 +4,25 @@ class FooPluginTest &lt; ActiveSupport::TestCase @@ -4,7 +4,25 @@ class FooPluginTest &lt; ActiveSupport::TestCase
4 def test_foo 4 def test_foo
5 FooPlugin::Bar.create! 5 FooPlugin::Bar.create!
6 end 6 end
  7 +
7 def test_monkey_patch 8 def test_monkey_patch
8 Profile.new.bar 9 Profile.new.bar
9 end 10 end
  11 +
  12 + should "respond to new hotspots" do
  13 + plugin = FooPlugin.new
  14 +
  15 + assert plugin.respond_to?(:foo_plugin_my_hotspot)
  16 + assert plugin.respond_to?(:foo_plugin_tab_title)
  17 + end
  18 +
  19 + should "other plugin respond to new hotspots" do
  20 + class TestPlugin < Noosfero::Plugin
  21 + end
  22 +
  23 + plugin = TestPlugin.new
  24 +
  25 + assert plugin.respond_to?(:foo_plugin_my_hotspot)
  26 + assert plugin.respond_to?(:foo_plugin_tab_title)
  27 + end
10 end 28 end
plugins/google_analytics/lib/ext/profile.rb
@@ -2,4 +2,9 @@ require_dependency &#39;profile&#39; @@ -2,4 +2,9 @@ require_dependency &#39;profile&#39;
2 2
3 class Profile 3 class Profile
4 settings_items :google_analytics_profile_id 4 settings_items :google_analytics_profile_id
  5 + attr_accessible :google_analytics_profile_id
  6 +
  7 + descendants.each do |descendant|
  8 + descendant.attr_accessible :google_analytics_profile_id
  9 + end
5 end 10 end
plugins/google_analytics/lib/google_analytics_plugin.rb
@@ -19,12 +19,15 @@ class GoogleAnalyticsPlugin &lt; Noosfero::Plugin @@ -19,12 +19,15 @@ class GoogleAnalyticsPlugin &lt; Noosfero::Plugin
19 19
20 def head_ending 20 def head_ending
21 unless profile_id.blank? 21 unless profile_id.blank?
22 - expanded_template('tracking-code.rhtml',{:profile_id => profile_id}) 22 + expanded_template('tracking-code.html.erb',{:profile_id => profile_id})
23 end 23 end
24 end 24 end
25 25
26 def profile_editor_extras 26 def profile_editor_extras
27 - expanded_template('profile-editor-extras.rhtml',{:profile_id => profile_id}) 27 + analytics_id = profile_id
  28 + lambda {
  29 + render :file => 'profile-editor-extras', :locals => { :profile_id => analytics_id }
  30 + }
28 end 31 end
29 32
30 end 33 end
plugins/google_analytics/test/functional/profile_editor_controller_test.rb 0 → 100644
@@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
  1 +require 'test_helper'
  2 +require 'profile_editor_controller'
  3 +
  4 +# Re-raise errors caught by the controller.
  5 +class ProfileEditorController; def rescue_action(e) raise e end; end
  6 +
  7 +class ProfileEditorControllerTest < ActionController::TestCase
  8 +
  9 + def setup
  10 + @controller = ProfileEditorController.new
  11 + @request = ActionController::TestRequest.new
  12 + @response = ActionController::TestResponse.new
  13 + @profile = create_user('default_user').person
  14 + login_as(@profile.identifier)
  15 + Environment.default.enable_plugin(GoogleAnalyticsPlugin.name)
  16 + end
  17 +
  18 + attr_accessor :profile
  19 +
  20 + should 'add extra fields to profile editor info and settings' do
  21 + get :edit, :profile => profile.identifier
  22 + assert_tag_in_string @response.body, :tag => 'label', :content => /Google Analytics/, :attributes => { :for => 'profile_data_google_analytics_profile_id' }
  23 + assert_tag_in_string @response.body, :tag => 'input', :attributes => { :id => 'profile_data_google_analytics_profile_id' }
  24 + end
  25 +
  26 + should 'save code filled in on field' do
  27 + post :edit, :profile => profile.identifier, :profile_data => {:google_analytics_profile_id => 12345678}
  28 + assert_equal '12345678', Person.find(profile.id).google_analytics_profile_id
  29 + end
  30 +
  31 +end
plugins/google_analytics/test/unit/google_analytics_plugin_test.rb
@@ -27,11 +27,6 @@ class GoogleAnalyticsPluginTest &lt; ActiveSupport::TestCase @@ -27,11 +27,6 @@ class GoogleAnalyticsPluginTest &lt; ActiveSupport::TestCase
27 assert_equal 'content', @plugin.head_ending 27 assert_equal 'content', @plugin.head_ending
28 end 28 end
29 29
30 - should 'add extra fields to profile editor info and settings' do  
31 - assert_tag_in_string @plugin.profile_editor_extras,  
32 - :tag => 'input', :attributes => {:id => 'profile_data_google_analytics_profile_id', :value => 10}  
33 - end  
34 -  
35 should 'extends Profile with attr google_analytics_profile_id' do 30 should 'extends Profile with attr google_analytics_profile_id' do
36 assert_respond_to Profile.new, :google_analytics_profile_id 31 assert_respond_to Profile.new, :google_analytics_profile_id
37 end 32 end
plugins/google_analytics/views/profile-editor-extras.html.erb 0 → 100644
@@ -0,0 +1,3 @@ @@ -0,0 +1,3 @@
  1 +<h2><%= c_('Statistics') %></h2>
  2 +<%= labelled_form_field(_('Google Analytics Profile ID'), text_field(:profile_data, :google_analytics_profile_id, :value => profile_id)) %>
  3 +<%= link_to(_('See how to configure statistics for your profile'), '/doc/plugins/google_analytics', :target => '_blank') %>
plugins/google_analytics/views/profile-editor-extras.rhtml
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -<% extend ApplicationHelper %>  
2 -  
3 -<h2><%= c_('Statistics') %></h2>  
4 -<%= labelled_form_field(_('Google Analytics Profile ID'), text_field(:profile_data, :google_analytics_profile_id, :value => profile_id)) %>  
5 -<%= link_to(_('See how to configure statistics for your profile'), '/doc/plugins/google_analytics', :target => '_blank') %>  
plugins/google_analytics/views/tracking-code.html.erb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<script>
  2 + (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
  3 + (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
  4 + m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  5 + })(window,document,'script','//www.google-analytics.com/analytics.js','ga');
  6 +
  7 + ga('create', '<%= escape_javascript locals[:profile_id] %>', 'auto');
  8 + ga('send', 'pageview');
  9 +</script>
plugins/google_analytics/views/tracking-code.rhtml
@@ -1,10 +0,0 @@ @@ -1,10 +0,0 @@
1 -<script type="text/javascript">  
2 - var _gaq = _gaq || [];  
3 - _gaq.push(['_setAccount', '<%= escape_javascript locals[:profile_id] %>']);  
4 - _gaq.push(['_trackPageview']);  
5 - (function() {  
6 - var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;  
7 - ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';  
8 - var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);  
9 - })();  
10 -</script>  
plugins/ldap/lib/ldap_authentication.rb
@@ -77,18 +77,20 @@ class LdapAuthentication @@ -77,18 +77,20 @@ class LdapAuthentication
77 end 77 end
78 78
79 def get_user_attributes_from_ldap_entry(entry) 79 def get_user_attributes_from_ldap_entry(entry)
80 - {  
81 - :dn => entry.dn,  
82 - :fullname => LdapAuthentication.get_attr(entry, self.attr_fullname),  
83 - :mail => LdapAuthentication.get_attr(entry, self.attr_mail),  
84 - } 80 + attributes = entry.instance_values["myhash"]
  81 +
  82 + attributes[:dn] = entry.dn
  83 + attributes[:fullname] = LdapAuthentication.get_attr(entry, self.attr_fullname)
  84 + attributes[:mail] = LdapAuthentication.get_attr(entry, self.attr_mail)
  85 +
  86 + attributes
85 end 87 end
86 88
87 # Return the attributes needed for the LDAP search. It will only 89 # Return the attributes needed for the LDAP search. It will only
88 # include the user attributes if on-the-fly registration is enabled 90 # include the user attributes if on-the-fly registration is enabled
89 def search_attributes 91 def search_attributes
90 if onthefly_register? 92 if onthefly_register?
91 - ['dn', self.attr_fullname, self.attr_mail] 93 + nil
92 else 94 else
93 ['dn'] 95 ['dn']
94 end 96 end
@@ -111,6 +113,7 @@ class LdapAuthentication @@ -111,6 +113,7 @@ class LdapAuthentication
111 end 113 end
112 login_filter = Net::LDAP::Filter.eq( self.attr_login, login ) 114 login_filter = Net::LDAP::Filter.eq( self.attr_login, login )
113 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" ) 115 object_filter = Net::LDAP::Filter.eq( "objectClass", "*" )
  116 +
114 attrs = {} 117 attrs = {}
115 118
116 search_filter = object_filter & login_filter 119 search_filter = object_filter & login_filter
plugins/ldap/lib/ldap_plugin.rb
1 require File.dirname(__FILE__) + '/ldap_authentication.rb' 1 require File.dirname(__FILE__) + '/ldap_authentication.rb'
2 2
3 class LdapPlugin < Noosfero::Plugin 3 class LdapPlugin < Noosfero::Plugin
  4 + include Noosfero::Plugin::HotSpot
4 5
5 def self.plugin_name 6 def self.plugin_name
6 "LdapPlugin" 7 "LdapPlugin"
@@ -10,6 +11,26 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -10,6 +11,26 @@ class LdapPlugin &lt; Noosfero::Plugin
10 _("A plugin that add ldap support.") 11 _("A plugin that add ldap support.")
11 end 12 end
12 13
  14 + module Hotspots
  15 + # -> Custom ldap plugin hotspot to set profile data before user creation
  16 + # receive the followings params:
  17 + # - attrs with ldap received data
  18 + # - login received by ldap
  19 + # - params from current context
  20 + # returns = updated person_data hash
  21 + def ldap_plugin_set_profile_data(attrs, params)
  22 + [attrs, params]
  23 + end
  24 +
  25 + # -> Custom ldap plugin hotspot to update user object
  26 + # receive the followings params:
  27 + # - user: user object
  28 + # - attrs with ldap received data
  29 + # returns = none
  30 + def ldap_plugin_update_user(user, attrs)
  31 + end
  32 + end
  33 +
13 def allow_user_registration 34 def allow_user_registration
14 false 35 false
15 end 36 end
@@ -35,17 +56,22 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -35,17 +56,22 @@ class LdapPlugin &lt; Noosfero::Plugin
35 56
36 if attrs 57 if attrs
37 user.login = login 58 user.login = login
38 - user.email = attrs[:mail] 59 + user.email = get_email(attrs, login)
39 user.name = attrs[:fullname] 60 user.name = attrs[:fullname]
40 user.password = password 61 user.password = password
41 user.password_confirmation = password 62 user.password_confirmation = password
42 - user.person_data = context.params[:profile_data] 63 + user.person_data = plugins.pipeline(:ldap_plugin_set_profile_data, attrs, context.params).last[:profile_data]
43 user.activated_at = Time.now.utc 64 user.activated_at = Time.now.utc
44 user.activation_code = nil 65 user.activation_code = nil
45 66
46 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes) 67 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes)
47 begin 68 begin
48 - user = nil unless user.save 69 + if user.save
  70 + user.activate
  71 + plugins.dispatch(:ldap_plugin_update_user, user, attrs)
  72 + else
  73 + user = nil
  74 + end
49 rescue 75 rescue
50 #User not saved 76 #User not saved
51 end 77 end
@@ -54,7 +80,6 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -54,7 +80,6 @@ class LdapPlugin &lt; Noosfero::Plugin
54 end 80 end
55 81
56 else 82 else
57 -  
58 return nil if !user.activated? 83 return nil if !user.activated?
59 84
60 begin 85 begin
@@ -69,6 +94,16 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -69,6 +94,16 @@ class LdapPlugin &lt; Noosfero::Plugin
69 user 94 user
70 end 95 end
71 96
  97 + def get_email(attrs, login)
  98 + return attrs[:mail] unless attrs[:mail].blank?
  99 +
  100 + if attrs[:fullname]
  101 + return attrs[:fullname].to_slug + "@ldap.user"
  102 + else
  103 + return login.to_slug + "@ldap.user"
  104 + end
  105 + end
  106 +
72 def login_extra_contents 107 def login_extra_contents
73 proc do 108 proc do
74 @person = Person.new(:environment => @environment) 109 @person = Person.new(:environment => @environment)
plugins/require_auth_to_comment/controllers/require_auth_to_comment_plugin_admin_controller.rb 0 → 100644
@@ -0,0 +1,14 @@ @@ -0,0 +1,14 @@
  1 +class RequireAuthToCommentPluginAdminController < AdminController
  2 +
  3 + def index
  4 + settings = params[:settings]
  5 + settings ||= {}
  6 + @settings = Noosfero::Plugin::Settings.new(environment, RequireAuthToCommentPlugin, settings)
  7 + if request.post?
  8 + @settings.save!
  9 + session[:notice] = 'Settings succefully saved.'
  10 + redirect_to :action => 'index'
  11 + end
  12 + end
  13 +
  14 +end
plugins/require_auth_to_comment/lib/require_auth_to_comment_plugin.rb
@@ -21,11 +21,20 @@ class RequireAuthToCommentPlugin &lt; Noosfero::Plugin @@ -21,11 +21,20 @@ class RequireAuthToCommentPlugin &lt; Noosfero::Plugin
21 end 21 end
22 22
23 def stylesheet? 23 def stylesheet?
24 - true 24 + !display_login_popup?
  25 + end
  26 +
  27 + def display_login_popup?
  28 + settings = Noosfero::Plugin::Settings.new(context.environment, self.class)
  29 + settings.require_type == 'display_login_popup'
  30 + end
  31 +
  32 + def self.require_type_default_setting
  33 + 'hide_button'
25 end 34 end
26 35
27 def js_files 36 def js_files
28 - ['hide_comment_form.js', 'jquery.livequery.min.js'] 37 + ['hide_comment_form.js', 'jquery.livequery.min.js'] + (display_login_popup? ? ['comment_require_login.js'] : [])
29 end 38 end
30 39
31 def body_beginning 40 def body_beginning
plugins/require_auth_to_comment/public/comment_require_login.js 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +(function($) {
  2 + $(window).bind('userDataLoaded', function(event, data) {
  3 + if (!data.login && $('meta[name="profile.allow_unauthenticated_comments"]').length <= 0) {
  4 + $('.display-comment-form').unbind();
  5 + $('.display-comment-form').addClass('require-login-popup');
  6 + }
  7 + });
  8 +})(jQuery);
plugins/require_auth_to_comment/test/unit/require_auth_to_comment_plugin_test.rb
@@ -5,9 +5,10 @@ class RequireAuthToCommentPluginTest &lt; ActiveSupport::TestCase @@ -5,9 +5,10 @@ class RequireAuthToCommentPluginTest &lt; ActiveSupport::TestCase
5 def setup 5 def setup
6 @plugin = RequireAuthToCommentPlugin.new 6 @plugin = RequireAuthToCommentPlugin.new
7 @comment = Comment.new 7 @comment = Comment.new
  8 + @environment = fast_create(Environment)
8 end 9 end
9 10
10 - attr_reader :plugin, :comment 11 + attr_reader :plugin, :comment, :environment
11 12
12 should 'reject comments for unauthenticated users' do 13 should 'reject comments for unauthenticated users' do
13 plugin.context = logged_in(false) 14 plugin.context = logged_in(false)
@@ -29,6 +30,35 @@ class RequireAuthToCommentPluginTest &lt; ActiveSupport::TestCase @@ -29,6 +30,35 @@ class RequireAuthToCommentPluginTest &lt; ActiveSupport::TestCase
29 assert !comment.rejected? 30 assert !comment.rejected?
30 end 31 end
31 32
  33 + should 'the default require type setting be hide_button' do
  34 + assert_equal 'hide_button', plugin.class.require_type_default_setting
  35 + end
  36 +
  37 + should 'display_login_popup? be false by default' do
  38 + context = mock();
  39 + context.expects(:environment).returns(environment)
  40 + plugin.expects(:context).returns(context)
  41 + assert !plugin.display_login_popup?
  42 + end
  43 +
  44 + should 'display_login_popup? be true if require_type is defined as display_login_popup' do
  45 + context = mock();
  46 + context.expects(:environment).returns(environment)
  47 + environment[:settings] = {:require_auth_to_comment_plugin => {:require_type => "display_login_popup"}}
  48 + plugin.expects(:context).returns(context)
  49 + assert plugin.display_login_popup?
  50 + end
  51 +
  52 + should 'not display stylesheet if login popup is active' do
  53 + plugin.expects(:display_login_popup?).returns(true)
  54 + assert !plugin.stylesheet?
  55 + end
  56 +
  57 + should 'display stylesheet if login popup is inactive' do
  58 + plugin.expects(:display_login_popup?).returns(false)
  59 + assert plugin.stylesheet?
  60 + end
  61 +
32 protected 62 protected
33 63
34 def logged_in(boolean) 64 def logged_in(boolean)
plugins/require_auth_to_comment/views/require_auth_to_comment_plugin_admin/index.html.erb 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +<h1><%= _('Require auth to comment Settings')%></h1>
  2 +
  3 +<%= form_for(:settings) do |f| %>
  4 +
  5 + <div class="require-type">
  6 + <strong>
  7 + <div class="hide-button">
  8 + <%= radio_button(:settings, :require_type, 'hide_button') %> <%= _('Hide button') %>
  9 + </div>
  10 + <div class="display-login-popup">
  11 + <%= radio_button(:settings, :require_type, 'display_login_popup') %> <%= _('Display login popup') %>
  12 + </div>
  13 + </strong>
  14 + </div>
  15 +
  16 + <% button_bar do %>
  17 + <%= submit_button(:save, _('Save'), :cancel => {:controller => 'plugins', :action => 'index'}) %>
  18 + <% end %>
  19 +
  20 +<% end %>
plugins/send_email/controllers/send_email_plugin_base_controller.rb
@@ -11,7 +11,8 @@ module SendEmailPluginBaseController @@ -11,7 +11,8 @@ module SendEmailPluginBaseController
11 ) 11 )
12 @mail.subject = params[:subject] unless params[:subject].blank? 12 @mail.subject = params[:subject] unless params[:subject].blank?
13 if @mail.valid? 13 if @mail.valid?
14 - SendEmailPlugin::Sender.send_message(request.referer, @context_url, @mail).deliver 14 + @referer = request.referer
  15 + SendEmailPlugin::Sender.send_message(@referer, @context_url, @mail).deliver
15 if request.xhr? 16 if request.xhr?
16 render :text => _('Message sent') 17 render :text => _('Message sent')
17 else 18 else
plugins/send_email/lib/send_email_plugin.rb
@@ -16,9 +16,9 @@ class SendEmailPlugin &lt; Noosfero::Plugin @@ -16,9 +16,9 @@ class SendEmailPlugin &lt; Noosfero::Plugin
16 16
17 def parse_content(html, source) 17 def parse_content(html, source)
18 if context.profile 18 if context.profile
19 - html.gsub!(/\{sendemail\}/, "/profile/#{context.profile.identifier}/plugin/send_email/deliver") 19 + html.gsub!(/({|%7[Bb])sendemail(}|%7[Dd])/, "/profile/#{context.profile.identifier}/plugin/send_email/deliver")
20 else 20 else
21 - html.gsub!(/\{sendemail\}/, '/plugin/send_email/deliver') 21 + html.gsub!(/({|%7[Bb])sendemail(}|%7[Dd])/, '/plugin/send_email/deliver')
22 end 22 end
23 [html, source] 23 [html, source]
24 end 24 end
plugins/send_email/lib/send_email_plugin/mail.rb
@@ -10,12 +10,11 @@ class SendEmailPlugin::Mail @@ -10,12 +10,11 @@ class SendEmailPlugin::Mail
10 validate :recipients_format 10 validate :recipients_format
11 11
12 def initialize(attributes = {:subject => 'New mail'}) 12 def initialize(attributes = {:subject => 'New mail'})
13 - @environment = attributes[:environment]  
14 - @from = attributes[:from]  
15 - @to = attributes[:to]  
16 - @subject = attributes[:subject]  
17 - @message = attributes[:message]  
18 - @params = attributes[:params] 13 + if attributes
  14 + attributes.each do |attr,value|
  15 + self.send("#{attr}=", value)
  16 + end
  17 + end
19 end 18 end
20 19
21 def recipients_format 20 def recipients_format
@@ -36,7 +35,7 @@ class SendEmailPlugin::Mail @@ -36,7 +35,7 @@ class SendEmailPlugin::Mail
36 end 35 end
37 36
38 def params=(value = {}) 37 def params=(value = {})
39 - [:action, :controller, :to, :message, :subject, :from].each{|k| value.delete(k)} 38 + [:profile, :action, :controller, :to, :message, :subject, :from, :commit].each{|k| value.delete(k)}
40 @params = value 39 @params = value
41 end 40 end
42 41
plugins/send_email/lib/send_email_plugin/sender.rb
@@ -7,9 +7,9 @@ class SendEmailPlugin::Sender &lt; Noosfero::Plugin::MailerBase @@ -7,9 +7,9 @@ class SendEmailPlugin::Sender &lt; Noosfero::Plugin::MailerBase
7 @params = mail.params 7 @params = mail.params
8 8
9 mail( 9 mail(
  10 + content_type: 'text/plain',
10 to: mail.to, 11 to: mail.to,
11 from: mail.from, 12 from: mail.from,
12 - body: mail.params,  
13 subject: "[#{mail.environment.name}] #{mail.subject}" 13 subject: "[#{mail.environment.name}] #{mail.subject}"
14 ) 14 )
15 end 15 end
plugins/send_email/test/functional/send_email_plugin_base_controller_test.rb
@@ -54,6 +54,13 @@ def run_common_tests @@ -54,6 +54,13 @@ def run_common_tests
54 post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john') 54 post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john')
55 assert_equal '[Colivre.net] Hello john', ActionMailer::Base.deliveries.first.subject 55 assert_equal '[Colivre.net] Hello john', ActionMailer::Base.deliveries.first.subject
56 end 56 end
  57 +
  58 + should 'deliver mail with message from view' do
  59 + Environment.any_instance.stubs(:send_email_plugin_allow_to).returns('john@example.com')
  60 + post :deliver, @extra_args.merge(:to => 'john@example.com', :message => 'Hi john', :subject => 'Hello john')
  61 + assert_match /Contact from/, ActionMailer::Base.deliveries.first.body.to_s
  62 + end
  63 +
57 end 64 end
58 65
59 class SendEmailPluginProfileControllerTest < ActionController::TestCase 66 class SendEmailPluginProfileControllerTest < ActionController::TestCase
plugins/send_email/test/unit/send_email_plugin_sender_test.rb
@@ -15,12 +15,14 @@ class SendEmailPluginSenderTest &lt; ActiveSupport::TestCase @@ -15,12 +15,14 @@ class SendEmailPluginSenderTest &lt; ActiveSupport::TestCase
15 end 15 end
16 16
17 should 'be able to deliver mail' do 17 should 'be able to deliver mail' do
  18 + @mail.expects(:params).returns({})
18 response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) 19 response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail)
19 assert_equal 'noreply@localhost', response.from.join 20 assert_equal 'noreply@localhost', response.from.join
20 assert_equal "[Noosfero] #{@mail.subject}", response.subject 21 assert_equal "[Noosfero] #{@mail.subject}", response.subject
21 end 22 end
22 23
23 should 'deliver mail to john@example.com' do 24 should 'deliver mail to john@example.com' do
  25 + @mail.expects(:params).returns({})
24 response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail) 26 response = SendEmailPlugin::Sender.send_message("http://localhost/contact", 'http//profile', @mail)
25 assert_equal ['john@example.com'], response.to 27 assert_equal ['john@example.com'], response.to
26 end 28 end
plugins/send_email/test/unit/send_email_plugin_test.rb
@@ -26,4 +26,12 @@ class SendEmailPluginTest &lt; ActiveSupport::TestCase @@ -26,4 +26,12 @@ class SendEmailPluginTest &lt; ActiveSupport::TestCase
26 assert_match /profile\/#{@plugin.context.profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content("expand this macro {sendemail}", nil).first 26 assert_match /profile\/#{@plugin.context.profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content("expand this macro {sendemail}", nil).first
27 end 27 end
28 28
  29 + should 'expand macro used on form on profile context' do
  30 + profile = fast_create(Community)
  31 + @plugin.context.stubs(:profile).returns(profile)
  32 + article = RawHTMLArticle.create!(:name => 'Raw HTML', :body => "<form action='{sendemail}'></form>", :profile => profile)
  33 +
  34 + assert_match /profile\/#{profile.identifier}\/plugin\/send_email\/deliver/, @plugin.parse_content(article.to_html, nil).first
  35 + end
  36 +
29 end 37 end
plugins/send_email/views/send_email_plugin/sender/message.html.erb
@@ -1,8 +0,0 @@ @@ -1,8 +0,0 @@
1 -<%= _('Contact from %s') % @referer %>  
2 -  
3 -<%= word_wrap(@message || @mail.message) %>  
4 -<% (@params || @mail.params).each_pair do |key, value| %>  
5 -<%= key %>: <%= word_wrap(value) %>  
6 -<% end %>  
7 ----  
8 -<%= url_for @context_url %>  
plugins/send_email/views/send_email_plugin/sender/send_message.html.erb 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +<%= _('Contact from %s') % @referer %>
  2 +
  3 +<%= word_wrap(@message || @mail.message) %>
  4 +
  5 +<% (@params || @mail.params).each_pair do |key, value| %>
  6 +<%= key %>: <%= word_wrap(value) %>
  7 +<% end %>
  8 +---
  9 +<%= url_for @context_url %>
plugins/send_email/views/send_email_plugin/success.html.erb
@@ -2,7 +2,7 @@ @@ -2,7 +2,7 @@
2 2
3 <table class='sendemail-plugin-message-sent'> 3 <table class='sendemail-plugin-message-sent'>
4 <tr><td class='label'><strong><%= c_('Subject') %>:</strong></td><td class='value'><em><%=h @mail.subject %></em></td></tr> 4 <tr><td class='label'><strong><%= c_('Subject') %>:</strong></td><td class='value'><em><%=h @mail.subject %></em></td></tr>
5 - <tr><td class='label'><strong><%= c_('Message') %>:</strong></td><td class='value'><pre><%=h render :file => 'send_email_plugin/sender/message' %></pre></td></tr> 5 + <tr><td class='label'><strong><%= c_('Message') %>:</strong></td><td class='value'><pre><%=h render :file => 'send_email_plugin/sender/send_message' %></pre></td></tr>
6 </table> 6 </table>
7 7
8 <p><%= button :back, c_('Back'), :back %></p> 8 <p><%= button :back, c_('Back'), :back %></p>
plugins/sub_organizations/db/migrate/20150508153119_add_timestamp_to_relation.rb 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +class AddTimestampToRelation < ActiveRecord::Migration
  2 + def change
  3 + add_column :sub_organizations_plugin_relations, :created_at, :datetime
  4 + add_column :sub_organizations_plugin_relations, :updated_at, :datetime
  5 + end
  6 +end
plugins/sub_organizations/lib/sub_organizations_plugin/relation.rb
1 class SubOrganizationsPlugin::Relation < Noosfero::Plugin::ActiveRecord 1 class SubOrganizationsPlugin::Relation < Noosfero::Plugin::ActiveRecord
2 - record_timestamps = false  
3 -  
4 belongs_to :parent, :polymorphic => true 2 belongs_to :parent, :polymorphic => true
5 belongs_to :child, :polymorphic => true 3 belongs_to :child, :polymorphic => true
6 4
plugins/vote/public/style.css
1 .vote-actions { 1 .vote-actions {
2 - position: absolute;  
3 top: 40px; 2 top: 40px;
4 right: 0px; 3 right: 0px;
5 } 4 }
plugins/vote/views/vote/_vote.html.erb
@@ -5,7 +5,7 @@ reload_url = url_for(:controller =&gt; &#39;vote_plugin_profile&#39;, :profile =&gt; profile.i @@ -5,7 +5,7 @@ reload_url = url_for(:controller =&gt; &#39;vote_plugin_profile&#39;, :profile =&gt; profile.i
5 5
6 <span id="vote_<%= model %>_<%= target.id %>_<%= vote %>" data-reload_url=<%= reload_url %> class="vote-action action <%= action %>-action"> 6 <span id="vote_<%= model %>_<%= target.id %>_<%= vote %>" data-reload_url=<%= reload_url %> class="vote-action action <%= action %>-action">
7 7
8 - <%= link_to_remote content_tag(:span, count, :class=>'like-action-counter') + content_tag(:span, '', :class=>"action-icon #{action}"), :url => url, :html => {:class => "#{active ? 'like-action-active':''} #{user ? '':'disabled'}"} %> 8 + <%= link_to content_tag(:span, count, :class=>'like-action-counter') + content_tag(:span, '', :class=>"action-icon #{action}"), url, :class => "#{active ? 'like-action-active':''} #{user ? '':'disabled'} require-login-popup" %>
9 9
10 <% if !voters.blank? %> 10 <% if !voters.blank? %>
11 <span class="vote-detail"> 11 <span class="vote-detail">
public/designs/templates/lefttopright/config.yml 0 → 100644
@@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
  1 +name: "Top and Side Bars"
  2 +title: "1 max colum at left, 1 min colum at right, 1 top line"
  3 +description: "A template with 1 colum in left, 1 colum in right and 1 line in top"
  4 +number_of_boxes: 4
public/designs/templates/lefttopright/javascripts/template.js 0 → 100644
@@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
  1 +$(document).ready(function() {
  2 + var box_4_height = $(".box-4").height();
  3 +
  4 + // Make box-2(the most left one) stay align with box-4
  5 + $(".box-2").css("margin-top", "-"+box_4_height+"px");
  6 +});
public/designs/templates/lefttopright/stylesheets/style.css 0 → 100644
@@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
  1 +#boxes {
  2 + display: table;
  3 + width: 100%;
  4 +}
  5 +
  6 +.box-1 {
  7 + width: 58%;
  8 + float: left;
  9 + margin: 1% 1% 0% 1%;
  10 +}
  11 +
  12 +
  13 +.box-2 {
  14 + position: relative;
  15 + float: left;
  16 + width: 20%;
  17 +}
  18 +
  19 +.box-3 {
  20 + position: relative;
  21 + float: right;
  22 + width: 20%;
  23 + margin-top: 1%;
  24 +}
  25 +
  26 +.box-4 {
  27 + float: left;
  28 + width: 79%;
  29 + margin-left: 21%;
  30 +}
  31 +
  32 +#profile-activity ul,
  33 +#profile-network ul,
  34 +#profile-wall ul {
  35 + width: 460px;
  36 +}
  37 +#profile-activity ul.comment-replies,
  38 +#profile-network ul.comment-replies,
  39 +#profile-wall ul.comment-replies {
  40 + width: auto;
  41 +}
  42 +
public/designs/templates/lefttopright/thumbnail.png 0 → 100644

3.02 KB

public/designs/templates/lefttopright/thumbnail.svg 0 → 100644
@@ -0,0 +1,434 @@ @@ -0,0 +1,434 @@
  1 +<?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2 +<!-- Created with Inkscape (http://www.inkscape.org/) -->
  3 +
  4 +<svg
  5 + xmlns:dc="http://purl.org/dc/elements/1.1/"
  6 + xmlns:cc="http://creativecommons.org/ns#"
  7 + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  8 + xmlns:svg="http://www.w3.org/2000/svg"
  9 + xmlns="http://www.w3.org/2000/svg"
  10 + xmlns:xlink="http://www.w3.org/1999/xlink"
  11 + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  12 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  13 + width="64px"
  14 + height="64px"
  15 + id="svg2383"
  16 + sodipodi:version="0.32"
  17 + inkscape:version="0.48.3.1 r9886"
  18 + sodipodi:docname="thumbnail.svg"
  19 + inkscape:output_extension="org.inkscape.output.svg.inkscape"
  20 + inkscape:export-filename="thumbnail.png"
  21 + inkscape:export-xdpi="90"
  22 + inkscape:export-ydpi="90"
  23 + version="1.1">
  24 + <defs
  25 + id="defs2385">
  26 + <linearGradient
  27 + id="linearGradient3263">
  28 + <stop
  29 + id="stop3265"
  30 + offset="0"
  31 + style="stop-color:#204a87;stop-opacity:1" />
  32 + <stop
  33 + id="stop3267"
  34 + offset="1"
  35 + style="stop-color:#729fcf;stop-opacity:1" />
  36 + </linearGradient>
  37 + <linearGradient
  38 + id="linearGradient3257"
  39 + inkscape:collect="always">
  40 + <stop
  41 + id="stop3259"
  42 + offset="0"
  43 + style="stop-color:#204a87;stop-opacity:1" />
  44 + <stop
  45 + id="stop3261"
  46 + offset="1"
  47 + style="stop-color:#729fcf;stop-opacity:1" />
  48 + </linearGradient>
  49 + <linearGradient
  50 + inkscape:collect="always"
  51 + id="linearGradient3245">
  52 + <stop
  53 + style="stop-color:#204a87;stop-opacity:1"
  54 + offset="0"
  55 + id="stop3247" />
  56 + <stop
  57 + style="stop-color:#729fcf;stop-opacity:1"
  58 + offset="1"
  59 + id="stop3249" />
  60 + </linearGradient>
  61 + <inkscape:perspective
  62 + sodipodi:type="inkscape:persp3d"
  63 + inkscape:vp_x="0 : 32 : 1"
  64 + inkscape:vp_y="0 : 1000 : 0"
  65 + inkscape:vp_z="64 : 32 : 1"
  66 + inkscape:persp3d-origin="32 : 21.333333 : 1"
  67 + id="perspective2391" />
  68 + <filter
  69 + inkscape:collect="always"
  70 + id="filter3241">
  71 + <feGaussianBlur
  72 + inkscape:collect="always"
  73 + stdDeviation="0.9075"
  74 + id="feGaussianBlur3243" />
  75 + </filter>
  76 + <linearGradient
  77 + inkscape:collect="always"
  78 + xlink:href="#linearGradient3245"
  79 + id="linearGradient3251"
  80 + x1="11.5"
  81 + y1="60.5"
  82 + x2="3.5"
  83 + y2="3.5"
  84 + gradientUnits="userSpaceOnUse"
  85 + gradientTransform="translate(2,0)" />
  86 + <linearGradient
  87 + inkscape:collect="always"
  88 + xlink:href="#linearGradient3263"
  89 + id="linearGradient3253"
  90 + x1="49.5"
  91 + y1="60.5"
  92 + x2="23.5"
  93 + y2="3.5"
  94 + gradientUnits="userSpaceOnUse"
  95 + gradientTransform="translate(2,0)" />
  96 + <linearGradient
  97 + inkscape:collect="always"
  98 + xlink:href="#linearGradient3257"
  99 + id="linearGradient3255"
  100 + x1="60.5"
  101 + y1="60.5"
  102 + x2="51.5"
  103 + y2="3.5"
  104 + gradientUnits="userSpaceOnUse" />
  105 + <filter
  106 + color-interpolation-filters="sRGB"
  107 + inkscape:collect="always"
  108 + id="filter3241-2">
  109 + <feGaussianBlur
  110 + inkscape:collect="always"
  111 + stdDeviation="0.9075"
  112 + id="feGaussianBlur3243-4" />
  113 + </filter>
  114 + <linearGradient
  115 + inkscape:collect="always"
  116 + xlink:href="#linearGradient3245-1"
  117 + id="linearGradient3251-0"
  118 + x1="11.5"
  119 + y1="60.5"
  120 + x2="3.5"
  121 + y2="3.5"
  122 + gradientUnits="userSpaceOnUse"
  123 + gradientTransform="translate(249.71429,298.93361)" />
  124 + <linearGradient
  125 + inkscape:collect="always"
  126 + id="linearGradient3245-1">
  127 + <stop
  128 + style="stop-color:#204a87;stop-opacity:1"
  129 + offset="0"
  130 + id="stop3247-6" />
  131 + <stop
  132 + style="stop-color:#729fcf;stop-opacity:1"
  133 + offset="1"
  134 + id="stop3249-5" />
  135 + </linearGradient>
  136 + <filter
  137 + color-interpolation-filters="sRGB"
  138 + inkscape:collect="always"
  139 + id="filter3241-4-8">
  140 + <feGaussianBlur
  141 + inkscape:collect="always"
  142 + stdDeviation="0.9075"
  143 + id="feGaussianBlur3243-0-7" />
  144 + </filter>
  145 + <linearGradient
  146 + inkscape:collect="always"
  147 + xlink:href="#linearGradient3263-5-8"
  148 + id="linearGradient5185"
  149 + gradientUnits="userSpaceOnUse"
  150 + gradientTransform="matrix(1.4160224,0,0,0.76166072,243.22589,313.33388)"
  151 + x1="42.5"
  152 + y1="60.5"
  153 + x2="19.5"
  154 + y2="3.5" />
  155 + <linearGradient
  156 + id="linearGradient3263-5-8">
  157 + <stop
  158 + id="stop3265-4-3"
  159 + offset="0"
  160 + style="stop-color:#204a87;stop-opacity:1" />
  161 + <stop
  162 + id="stop3267-2-4"
  163 + offset="1"
  164 + style="stop-color:#729fcf;stop-opacity:1" />
  165 + </linearGradient>
  166 + <filter
  167 + color-interpolation-filters="sRGB"
  168 + inkscape:collect="always"
  169 + id="filter3241-0">
  170 + <feGaussianBlur
  171 + inkscape:collect="always"
  172 + stdDeviation="0.9075"
  173 + id="feGaussianBlur3243-3" />
  174 + </filter>
  175 + <linearGradient
  176 + inkscape:collect="always"
  177 + xlink:href="#linearGradient3245-7"
  178 + id="linearGradient5168"
  179 + gradientUnits="userSpaceOnUse"
  180 + gradientTransform="matrix(1.0025263,0,0,0.76423683,344.68831,300.13218)"
  181 + x1="11.5"
  182 + y1="60.5"
  183 + x2="3.5"
  184 + y2="3.5" />
  185 + <linearGradient
  186 + inkscape:collect="always"
  187 + id="linearGradient3245-7">
  188 + <stop
  189 + style="stop-color:#204a87;stop-opacity:1"
  190 + offset="0"
  191 + id="stop3247-0" />
  192 + <stop
  193 + style="stop-color:#729fcf;stop-opacity:1"
  194 + offset="1"
  195 + id="stop3249-7" />
  196 + </linearGradient>
  197 + <linearGradient
  198 + inkscape:collect="always"
  199 + xlink:href="#linearGradient3245-70"
  200 + id="linearGradient3251-55"
  201 + x1="11.5"
  202 + y1="60.5"
  203 + x2="3.5"
  204 + y2="3.5"
  205 + gradientUnits="userSpaceOnUse"
  206 + gradientTransform="matrix(1.0025263,0,0,0.76423683,344.68831,300.13218)" />
  207 + <linearGradient
  208 + inkscape:collect="always"
  209 + id="linearGradient3245-70">
  210 + <stop
  211 + style="stop-color:#204a87;stop-opacity:1"
  212 + offset="0"
  213 + id="stop3247-2" />
  214 + <stop
  215 + style="stop-color:#729fcf;stop-opacity:1"
  216 + offset="1"
  217 + id="stop3249-87" />
  218 + </linearGradient>
  219 + <linearGradient
  220 + inkscape:collect="always"
  221 + xlink:href="#linearGradient3245-1"
  222 + id="linearGradient5832"
  223 + gradientUnits="userSpaceOnUse"
  224 + gradientTransform="translate(249.71429,298.93361)"
  225 + x1="11.5"
  226 + y1="60.5"
  227 + x2="3.5"
  228 + y2="3.5" />
  229 + <linearGradient
  230 + inkscape:collect="always"
  231 + xlink:href="#linearGradient3263-5-8"
  232 + id="linearGradient5834"
  233 + gradientUnits="userSpaceOnUse"
  234 + gradientTransform="matrix(1.4160224,0,0,0.76166072,243.22589,313.33388)"
  235 + x1="42.5"
  236 + y1="60.5"
  237 + x2="19.5"
  238 + y2="3.5" />
  239 + <linearGradient
  240 + inkscape:collect="always"
  241 + xlink:href="#linearGradient3245-7"
  242 + id="linearGradient5836"
  243 + gradientUnits="userSpaceOnUse"
  244 + gradientTransform="matrix(1.0025263,0,0,0.76423683,344.68831,300.13218)"
  245 + x1="11.5"
  246 + y1="60.5"
  247 + x2="3.5"
  248 + y2="3.5" />
  249 + <linearGradient
  250 + inkscape:collect="always"
  251 + xlink:href="#linearGradient3245-70"
  252 + id="linearGradient5838"
  253 + gradientUnits="userSpaceOnUse"
  254 + gradientTransform="matrix(1.0025263,0,0,0.76423683,344.68831,300.13218)"
  255 + x1="11.5"
  256 + y1="60.5"
  257 + x2="3.5"
  258 + y2="3.5" />
  259 + </defs>
  260 + <sodipodi:namedview
  261 + id="base"
  262 + pagecolor="#ffffff"
  263 + bordercolor="#666666"
  264 + borderopacity="1.0"
  265 + inkscape:pageopacity="0.0"
  266 + inkscape:pageshadow="2"
  267 + inkscape:zoom="2.5351563"
  268 + inkscape:cx="-16.066434"
  269 + inkscape:cy="0.12147739"
  270 + inkscape:current-layer="layer1"
  271 + showgrid="true"
  272 + inkscape:document-units="px"
  273 + inkscape:grid-bbox="true"
  274 + inkscape:window-width="1364"
  275 + inkscape:window-height="678"
  276 + inkscape:window-x="0"
  277 + inkscape:window-y="27"
  278 + objecttolerance="10"
  279 + gridtolerance="10"
  280 + guidetolerance="10"
  281 + inkscape:window-maximized="0">
  282 + <inkscape:grid
  283 + type="xygrid"
  284 + id="grid2382"
  285 + visible="true"
  286 + enabled="true"
  287 + originx="0.5px"
  288 + originy="0.5px"
  289 + empcolor="#0000ff"
  290 + empopacity="0.1254902"
  291 + dotted="true" />
  292 + </sodipodi:namedview>
  293 + <metadata
  294 + id="metadata2388">
  295 + <rdf:RDF>
  296 + <cc:Work
  297 + rdf:about="">
  298 + <dc:format>image/svg+xml</dc:format>
  299 + <dc:type
  300 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  301 + </cc:Work>
  302 + </rdf:RDF>
  303 + </metadata>
  304 + <g
  305 + id="layer1"
  306 + inkscape:label="Layer 1"
  307 + inkscape:groupmode="layer">
  308 + <g
  309 + transform="translate(-247.62879,-298.93361)"
  310 + id="g5187">
  311 + <g
  312 + id="g4846">
  313 + <g
  314 + id="g3190-2"
  315 + style="opacity:0.4;filter:url(#filter3241-2)"
  316 + transform="translate(250.71429,299.93361)">
  317 + <rect
  318 + y="1.5"
  319 + x="1.5"
  320 + height="59"
  321 + width="11"
  322 + id="rect3184-1"
  323 + style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  324 + ry="2"
  325 + rx="2" />
  326 + </g>
  327 + <rect
  328 + y="300.43362"
  329 + x="251.21428"
  330 + height="59"
  331 + width="11"
  332 + id="rect2395-8"
  333 + style="fill:url(#linearGradient5832);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  334 + ry="2"
  335 + rx="2" />
  336 + <rect
  337 + ry="1"
  338 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  339 + id="rect3158-7"
  340 + width="9"
  341 + height="57"
  342 + x="252.21428"
  343 + y="301.43362"
  344 + rx="1" />
  345 + </g>
  346 + <g
  347 + transform="matrix(0.69260722,0,0,1,81.51265,0)"
  348 + id="g5180">
  349 + <rect
  350 + rx="2"
  351 + ry="2"
  352 + style="opacity:0.4;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3241-4-8);enable-background:accumulate"
  353 + id="rect3188-8"
  354 + width="31"
  355 + height="59"
  356 + x="16.5"
  357 + y="2.5"
  358 + transform="matrix(1.4160224,0,0,0.76166071,243.80989,314.09132)" />
  359 + <rect
  360 + y="314.47638"
  361 + x="265.17426"
  362 + height="44.937984"
  363 + width="43.896694"
  364 + id="rect3156-3"
  365 + style="fill:url(#linearGradient5834);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:1.03852236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  366 + ry="1.5233214" />
  367 + <rect
  368 + y="315.23804"
  369 + x="266.59027"
  370 + height="43.414661"
  371 + width="41.064651"
  372 + id="rect3162-1"
  373 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:1.03852236;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  374 + ry="0.7616607"
  375 + inkscape:export-xdpi="90"
  376 + inkscape:export-ydpi="90" />
  377 + </g>
  378 + <g
  379 + transform="matrix(0.9761091,0,0,1,6.3333026,0)"
  380 + id="g5108">
  381 + <rect
  382 + rx="2"
  383 + ry="2"
  384 + style="opacity:0.4;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:#000000;stroke-width:1;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;filter:url(#filter3241-0);enable-background:accumulate"
  385 + id="rect3184-5"
  386 + width="11"
  387 + height="59"
  388 + x="2.5"
  389 + y="2.5"
  390 + transform="matrix(0,1.0025263,-0.76423683,0,312.09322,298.92289)" />
  391 + <g
  392 + transform="matrix(0,1,-1,0,611.46116,-45.820829)"
  393 + id="g4877-9">
  394 + <rect
  395 + ry="1.5284736"
  396 + style="fill:url(#linearGradient5836);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:0.87531;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  397 + id="rect2395-95"
  398 + width="11.02779"
  399 + height="45.089973"
  400 + x="346.19211"
  401 + y="301.27853" />
  402 + <rect
  403 + y="302.04276"
  404 + x="347.19461"
  405 + height="43.561501"
  406 + width="9.0227375"
  407 + id="rect3158-2"
  408 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:0.87531;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  409 + ry="0.76423681" />
  410 + </g>
  411 + </g>
  412 + <g
  413 + id="g4877-8"
  414 + transform="translate(-47.956003,13.002947)">
  415 + <rect
  416 + y="301.27853"
  417 + x="346.19211"
  418 + height="45.089973"
  419 + width="11.02779"
  420 + id="rect2395-1"
  421 + style="fill:url(#linearGradient5838);fill-opacity:1;fill-rule:nonzero;stroke:#204a87;stroke-width:0.87531;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  422 + ry="1.5284736" />
  423 + <rect
  424 + ry="0.76423681"
  425 + style="opacity:0.6;fill:none;stroke:#ffffff;stroke-width:0.87531;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
  426 + id="rect3158-71"
  427 + width="9.0227375"
  428 + height="43.561501"
  429 + x="347.19461"
  430 + y="302.04276" />
  431 + </g>
  432 + </g>
  433 + </g>
  434 +</svg>