Commit ea5d6c29804a666f657d717ecb56e1dfde0f902e

Authored by Leandro Santos
2 parents 40ab912d 6e1949cf

merging with master

Showing 82 changed files with 1582 additions and 137 deletions   Show diff stats
@@ -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>
@@ -27,23 +27,17 @@ gem &#39;api-pagination&#39;, &#39;~&gt; 4.1.1&#39; @@ -27,23 +27,17 @@ gem &#39;api-pagination&#39;, &#39;~&gt; 4.1.1&#39;
27 gem 'rack-cors' 27 gem 'rack-cors'
28 gem 'rack-contrib' 28 gem 'rack-contrib'
29 29
30 -#gem 'grape-swagger-rails'  
31 -  
32 -# FIXME list here all actual dependencies (i.e. the ones in debian/control),  
33 -# with their GEM names (not the Debian package names)  
34 - 30 +# asset pipeline
  31 +gem 'uglifier', '>= 1.0.3'
35 gem 'sass-rails' 32 gem 'sass-rails'
36 -group :assets do  
37 - gem 'uglifier', '>= 1.0.3'  
38 -end  
39 33
40 group :production do 34 group :production do
41 gem 'dalli', '~> 2.7.0' 35 gem 'dalli', '~> 2.7.0'
42 end 36 end
43 37
44 group :test do 38 group :test do
45 - gem 'rspec', '~> 2.10.0'  
46 - gem 'rspec-rails', '~> 2.10.1' 39 + gem 'rspec', '~> 2.14.0'
  40 + gem 'rspec-rails', '~> 2.14.1'
47 gem 'mocha', '~> 1.1.0', :require => false 41 gem 'mocha', '~> 1.1.0', :require => false
48 end 42 end
49 43
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
@@ -14,6 +14,7 @@ class ApplicationController &lt; ActionController::Base @@ -14,6 +14,7 @@ class ApplicationController &lt; ActionController::Base
14 def log_user 14 def log_user
15 Rails.logger.info "Logged in: #{user.identifier}" if user 15 Rails.logger.info "Logged in: #{user.identifier}" if user
16 end 16 end
  17 + before_filter :redirect_to_current_user
17 18
18 def verify_members_whitelist 19 def verify_members_whitelist
19 render_access_denied unless user.is_admin? || environment.in_whitelist?(user) 20 render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
@@ -197,4 +198,15 @@ class ApplicationController &lt; ActionController::Base @@ -197,4 +198,15 @@ class ApplicationController &lt; ActionController::Base
197 def private_environment? 198 def private_environment?
198 @environment.enabled?(:restrict_to_members) 199 @environment.enabled?(:restrict_to_members)
199 end 200 end
  201 +
  202 + def redirect_to_current_user
  203 + if params[:profile] == '~'
  204 + if logged_in?
  205 + redirect_to params.merge(:profile => user.identifier)
  206 + else
  207 + render_not_found
  208 + end
  209 + end
  210 + end
  211 +
200 end 212 end
app/controllers/my_profile/profile_design_controller.rb
@@ -4,12 +4,20 @@ class ProfileDesignController &lt; BoxOrganizerController @@ -4,12 +4,20 @@ 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 return if params[:id].blank? 18 return if params[:id].blank?
11 block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, '')) 19 block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
12 - if block.present? && block.fixed && !current_person.is_admin? 20 + if block.present? && !current_person.is_admin? && !block.movable?
13 render_access_denied 21 render_access_denied
14 end 22 end
15 end 23 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
@@ -717,6 +717,24 @@ module ApplicationHelper @@ -717,6 +717,24 @@ module ApplicationHelper
717 javascript_include_tag script if script 717 javascript_include_tag script if script
718 end 718 end
719 719
  720 + def template_path
  721 + if profile.nil?
  722 + "/designs/templates/#{environment.layout_template}"
  723 + else
  724 + "/designs/templates/#{profile.layout_template}"
  725 + end
  726 + end
  727 +
  728 + def template_javascript_src
  729 + script = File.join template_path, '/javascripts/template.js'
  730 + script if File.exists? File.join(Rails.root, 'public', script)
  731 + end
  732 +
  733 + def templete_javascript_ng
  734 + script = template_javascript_src
  735 + javascript_include_tag script if script
  736 + end
  737 +
720 def file_field_or_thumbnail(label, image, i) 738 def file_field_or_thumbnail(label, image, i)
721 display_form_field label, ( 739 display_form_field label, (
722 render :partial => (image && image.valid? ? 'shared/show_thumbnail' : 'shared/change_image'), 740 render :partial => (image && image.valid? ? 'shared/show_thumbnail' : 'shared/change_image'),
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 url = url_for(:action => 'move_block', :target => id) 194 url = url_for(:action => 'move_block', :target => id)
195 content_tag('div', _('Drop Here'), :id => id, :class => 'block-target' ) + drop_receiving_element(id, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover', :activeClass => 'block-target-active', :tolerance => 'pointer', :onDrop => "function(ev, ui) { dropBlock('#{url}', '#{_('loading...')}', ev, ui);}") 195 content_tag('div', _('Drop Here'), :id => id, :class => 'block-target' ) + drop_receiving_element(id, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover', :activeClass => 'block-target-active', :tolerance => 'pointer', :onDrop => "function(ev, ui) { dropBlock('#{url}', '#{_('loading...')}', ev, ui);}")
196 else 196 else
@@ -200,7 +200,7 @@ module BoxesHelper @@ -200,7 +200,7 @@ module BoxesHelper
200 200
201 # makes the given block draggable so it can be moved away. 201 # makes the given block draggable so it can be moved away.
202 def block_handle(block) 202 def block_handle(block)
203 - return "" unless modifiable?(block) 203 + return "" unless movable?(block)
204 icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>" 204 icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>"
205 block_draggable("block-#{block.id}", 205 block_draggable("block-#{block.id}",
206 :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}") 206 :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}")
@@ -225,7 +225,7 @@ module BoxesHelper @@ -225,7 +225,7 @@ module BoxesHelper
225 buttons = [] 225 buttons = []
226 nowhere = 'javascript: return false;' 226 nowhere = 'javascript: return false;'
227 227
228 - if modifiable?(block) 228 + if movable?(block)
229 if block.first? 229 if block.first?
230 buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere) 230 buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere)
231 else 231 else
@@ -248,15 +248,15 @@ module BoxesHelper @@ -248,15 +248,15 @@ module BoxesHelper
248 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' ) 248 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' )
249 end 249 end
250 end 250 end
  251 + end
251 252
252 - if block.editable?  
253 - buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })  
254 - end 253 + if editable?(block)
  254 + buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  255 + end
255 256
256 - if !block.main?  
257 - buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})  
258 - buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })  
259 - end 257 + if movable?(block) && !block.main?
  258 + buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})
  259 + buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })
260 end 260 end
261 261
262 if block.respond_to?(:help) 262 if block.respond_to?(:help)
@@ -292,7 +292,11 @@ module BoxesHelper @@ -292,7 +292,11 @@ module BoxesHelper
292 classes 292 classes
293 end 293 end
294 294
295 - def modifiable?(block)  
296 - return !block.fixed || environment.admins.include?(user) 295 + def movable?(block)
  296 + return block.movable? || user.is_admin?
  297 + end
  298 +
  299 + def editable?(block)
  300 + return block.editable? || user.is_admin?
297 end 301 end
298 end 302 end
app/helpers/layout_helper.rb
@@ -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/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
@@ -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.
@@ -178,7 +185,11 @@ class Block &lt; ActiveRecord::Base @@ -178,7 +185,11 @@ class Block &lt; ActiveRecord::Base
178 185
179 # Is this block editable? (Default to <tt>false</tt>) 186 # Is this block editable? (Default to <tt>false</tt>)
180 def editable? 187 def editable?
181 - true 188 + self.edit_modes == "all"
  189 + end
  190 +
  191 + def movable?
  192 + self.move_modes == "all"
182 end 193 end
183 194
184 # must always return false, except on MainBlock clas. 195 # must always return false, except on MainBlock clas.
@@ -258,6 +269,21 @@ class Block &lt; ActiveRecord::Base @@ -258,6 +269,21 @@ class Block &lt; ActiveRecord::Base
258 } 269 }
259 end 270 end
260 271
  272 + def edit_block_options
  273 + @edit_options ||= {
  274 + 'all' => _('Can be modified'),
  275 + 'none' => _('Cannot be modified')
  276 + }
  277 + end
  278 +
  279 + def move_block_options
  280 + @move_options ||= {
  281 + 'all' => _('Can be moved'),
  282 + 'none' => _('Cannot be moved')
  283 + }
  284 + end
  285 +
  286 +
261 def duplicate 287 def duplicate
262 duplicated_block = self.dup 288 duplicated_block = self.dup
263 duplicated_block.display = 'never' 289 duplicated_block.display = 'never'
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/organization.rb
@@ -36,6 +36,8 @@ class Organization &lt; Profile @@ -36,6 +36,8 @@ class Organization &lt; Profile
36 36
37 has_many :mailings, :class_name => 'OrganizationMailing', :foreign_key => :source_id, :as => 'source' 37 has_many :mailings, :class_name => 'OrganizationMailing', :foreign_key => :source_id, :as => 'source'
38 38
  39 + has_many :custom_roles, :class_name => 'Role', :foreign_key => :profile_id
  40 +
39 scope :more_popular, :order => 'members_count DESC' 41 scope :more_popular, :order => 'members_count DESC'
40 42
41 validate :presence_of_required_fieds, :unless => :is_template 43 validate :presence_of_required_fieds, :unless => :is_template
app/models/profile.rb
@@ -50,6 +50,8 @@ class Profile &lt; ActiveRecord::Base @@ -50,6 +50,8 @@ class Profile &lt; ActiveRecord::Base
50 self.template.custom_fields[field][:title] 50 self.template.custom_fields[field][:title]
51 end 51 end
52 52
  53 + NUMBER_OF_BOXES = 4
  54 +
53 def self.default_search_display 55 def self.default_search_display
54 'compact' 56 'compact'
55 end 57 end
@@ -71,7 +73,7 @@ class Profile &lt; ActiveRecord::Base @@ -71,7 +73,7 @@ class Profile &lt; ActiveRecord::Base
71 find_role('editor', env_id) 73 find_role('editor', env_id)
72 end 74 end
73 def self.organization_member_roles(env_id) 75 def self.organization_member_roles(env_id)
74 - all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? } 76 + all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? || !r.profile_id.nil?}
75 end 77 end
76 def self.all_roles(env_id) 78 def self.all_roles(env_id)
77 Role.all :conditions => { :environment_id => env_id } 79 Role.all :conditions => { :environment_id => env_id }
@@ -103,6 +105,7 @@ class Profile &lt; ActiveRecord::Base @@ -103,6 +105,7 @@ class Profile &lt; ActiveRecord::Base
103 'publish_content' => N_('Publish content'), 105 'publish_content' => N_('Publish content'),
104 'invite_members' => N_('Invite members'), 106 'invite_members' => N_('Invite members'),
105 'send_mail_to_members' => N_('Send e-Mail to members'), 107 'send_mail_to_members' => N_('Send e-Mail to members'),
  108 + 'manage_custom_roles' => N_('Manage custom roles'),
106 } 109 }
107 110
108 acts_as_accessible 111 acts_as_accessible
@@ -399,7 +402,7 @@ class Profile &lt; ActiveRecord::Base @@ -399,7 +402,7 @@ class Profile &lt; ActiveRecord::Base
399 if template 402 if template
400 apply_template(template, :copy_articles => false) 403 apply_template(template, :copy_articles => false)
401 else 404 else
402 - 3.times do 405 + NUMBER_OF_BOXES.times do
403 self.boxes << Box.new 406 self.boxes << Box.new
404 end 407 end
405 408
@@ -442,6 +445,7 @@ class Profile &lt; ActiveRecord::Base @@ -442,6 +445,7 @@ class Profile &lt; ActiveRecord::Base
442 alias_method_chain :template, :default 445 alias_method_chain :template, :default
443 446
444 def apply_template(template, options = {:copy_articles => true}) 447 def apply_template(template, options = {:copy_articles => true})
  448 + self.template = template
445 copy_blocks_from(template) 449 copy_blocks_from(template)
446 copy_articles_from(template) if options[:copy_articles] 450 copy_articles_from(template) if options[:copy_articles]
447 self.apply_type_specific_template(template) 451 self.apply_type_specific_template(template)
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/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/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 -  
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,
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/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 '(?!index)[a-z0-9][a-z0-9~.]*([_\-][a-z0-9~.]+)*' 57 '(?!index)[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/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/ldap/lib/ldap_plugin.rb
@@ -18,7 +18,8 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -18,7 +18,8 @@ class LdapPlugin &lt; Noosfero::Plugin
18 # - login received by ldap 18 # - login received by ldap
19 # - params from current context 19 # - params from current context
20 # returns = updated person_data hash 20 # returns = updated person_data hash
21 - def ldap_plugin_set_profile_data(attrs, login, params) 21 + def ldap_plugin_set_profile_data(attrs, params)
  22 + [attrs, params]
22 end 23 end
23 24
24 # -> Custom ldap plugin hotspot to update user object 25 # -> Custom ldap plugin hotspot to update user object
@@ -55,19 +56,22 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -55,19 +56,22 @@ class LdapPlugin &lt; Noosfero::Plugin
55 56
56 if attrs 57 if attrs
57 user.login = login 58 user.login = login
58 - user.email = attrs[:mail] 59 + user.email = get_email(attrs, login)
59 user.name = attrs[:fullname] 60 user.name = attrs[:fullname]
60 user.password = password 61 user.password = password
61 user.password_confirmation = password 62 user.password_confirmation = password
62 - person_data = plugins.dispatch(:ldap_plugin_set_profile_data, attrs, login, context.params)  
63 - user.person_data = person_data.blank? ? context.params[:profile_data] : person_data 63 + user.person_data = plugins.pipeline(:ldap_plugin_set_profile_data, attrs, context.params).last[:profile_data]
64 user.activated_at = Time.now.utc 64 user.activated_at = Time.now.utc
65 user.activation_code = nil 65 user.activation_code = nil
66 66
67 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes) 67 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes)
68 begin 68 begin
69 - user = nil unless user.save!  
70 - plugins.dispatch(:ldap_plugin_update_user, user, attrs) 69 + if user.save
  70 + user.activate
  71 + plugins.dispatch(:ldap_plugin_update_user, user, attrs)
  72 + else
  73 + user = nil
  74 + end
71 rescue 75 rescue
72 #User not saved 76 #User not saved
73 end 77 end
@@ -90,6 +94,16 @@ class LdapPlugin &lt; Noosfero::Plugin @@ -90,6 +94,16 @@ class LdapPlugin &lt; Noosfero::Plugin
90 user 94 user
91 end 95 end
92 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 +
93 def login_extra_contents 107 def login_extra_contents
94 proc do 108 proc do
95 @person = Person.new(:environment => @environment) 109 @person = Person.new(:environment => @environment)
plugins/pairwise
1 -Subproject commit c733dd106a1adf55a4674e82ea809237fa42252b 1 +Subproject commit b18d03a73f4db349adc25d730c5afcedb57cecb1
plugins/proposals_discussion
1 -Subproject commit 1bd718a5f8a5268ca580dded82a6c5fc5b8480dd 1 +Subproject commit 32e6b1fef12caf0eb674f516a39ac88ea418bd82
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/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>
public/designs/templates/topleft/stylesheets/style.css
@@ -20,7 +20,7 @@ @@ -20,7 +20,7 @@
20 20
21 .box-3 { 21 .box-3 {
22 position: relative; 22 position: relative;
23 - display: table-footer-group; 23 + display: table-header-group;
24 width: 100%; 24 width: 100%;
25 } 25 }
26 26
public/images/blocks/4.png 0 → 100644

1.14 KB

public/images/blocks/4.svg 0 → 100644
@@ -0,0 +1,83 @@ @@ -0,0 +1,83 @@
  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:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
  11 + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
  12 + width="64"
  13 + height="64"
  14 + id="svg2"
  15 + sodipodi:version="0.32"
  16 + inkscape:version="0.48.3.1 r9886"
  17 + version="1.0"
  18 + sodipodi:docname="4.svg"
  19 + inkscape:output_extension="org.inkscape.output.svg.inkscape"
  20 + inkscape:export-filename="/home/noosfero/sites/noosfero/public/images/blocks/4.png"
  21 + inkscape:export-xdpi="87.968124"
  22 + inkscape:export-ydpi="87.968124">
  23 + <defs
  24 + id="defs4" />
  25 + <sodipodi:namedview
  26 + id="base"
  27 + pagecolor="#ffffff"
  28 + bordercolor="#666666"
  29 + borderopacity="1.0"
  30 + inkscape:pageopacity="0.0"
  31 + inkscape:pageshadow="2"
  32 + inkscape:zoom="5.921875"
  33 + inkscape:cx="32"
  34 + inkscape:cy="32"
  35 + inkscape:document-units="px"
  36 + inkscape:current-layer="layer1"
  37 + width="64px"
  38 + height="64px"
  39 + inkscape:window-width="1366"
  40 + inkscape:window-height="681"
  41 + inkscape:window-x="0"
  42 + inkscape:window-y="27"
  43 + showgrid="false"
  44 + inkscape:window-maximized="1" />
  45 + <metadata
  46 + id="metadata7">
  47 + <rdf:RDF>
  48 + <cc:Work
  49 + rdf:about="">
  50 + <dc:format>image/svg+xml</dc:format>
  51 + <dc:type
  52 + rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
  53 + <dc:title></dc:title>
  54 + </cc:Work>
  55 + </rdf:RDF>
  56 + </metadata>
  57 + <g
  58 + inkscape:label="Camada 1"
  59 + inkscape:groupmode="layer"
  60 + id="layer1">
  61 + <path
  62 + sodipodi:type="arc"
  63 + style="fill:#000000;fill-opacity:0;stroke:#000000;stroke-width:4.5;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:0.19607843"
  64 + id="path2162"
  65 + sodipodi:cx="24.12665"
  66 + sodipodi:cy="24.063324"
  67 + sodipodi:rx="21.593668"
  68 + sodipodi:ry="21.277044"
  69 + d="M 45.720318 24.063324 A 21.593668 21.277044 0 1 1 2.5329819,24.063324 A 21.593668 21.277044 0 1 1 45.720318 24.063324 z"
  70 + transform="translate(7.8733501,7.936676)" />
  71 + <text
  72 + xml:space="preserve"
  73 + style="font-size:42.00993729px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:0.19607843;stroke:none;font-family:FreeSans"
  74 + x="16.267668"
  75 + y="47.399117"
  76 + id="text3134"
  77 + sodipodi:linespacing="125%"><tspan
  78 + sodipodi:role="line"
  79 + id="tspan3136"
  80 + x="16.267668"
  81 + y="47.399117">4</tspan></text>
  82 + </g>
  83 +</svg>
public/images/control-panel/role-management.gif 0 → 100644

2.07 KB

public/images/control-panel/role-management.png 0 → 100644

3.63 KB

public/javascripts/application.js
@@ -31,6 +31,7 @@ @@ -31,6 +31,7 @@
31 *= require select-or-die/_src/selectordie.js 31 *= require select-or-die/_src/selectordie.js
32 *= require block-store.js 32 *= require block-store.js
33 *= require jquery.typewatch.js 33 *= require jquery.typewatch.js
  34 +*= require require_login.js
34 */ 35 */
35 36
36 // scope for noosfero stuff 37 // scope for noosfero stuff
public/javascripts/assign_role.js 0 → 100644
@@ -0,0 +1,19 @@ @@ -0,0 +1,19 @@
  1 +(function($){
  2 + 'use strict';
  3 +
  4 + function toggle_assignment_method() {
  5 + if (this.value != "roles") {
  6 + $('.assign_by_roles').hide();
  7 + $('.assign_by_members').show();
  8 + } else {
  9 + $('.assign_by_members').hide();
  10 + $('.assign_by_roles').show();
  11 + }
  12 + }
  13 +
  14 + $(document).ready(function() {
  15 + $('.assign_by_roles').hide();
  16 + // Event triggers
  17 + $('.assign_role_by').click(toggle_assignment_method);
  18 + });
  19 +})(jQuery);
public/javascripts/require_login.js 0 → 100644
@@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
  1 +(function($) {
  2 + $(window).bind('userDataLoaded', function(event, data) {
  3 + $(".require-login-popup").live('click', function(){
  4 + clicked = $(this);
  5 + url = clicked.attr("href");
  6 + if(url!=undefined && url!='' && url!='#') {
  7 + if(!data.login) {
  8 + url = $.param.querystring(url, "require_login_popup=true");
  9 + }
  10 + loading_for_button(this);
  11 + $.post(url, function(data){
  12 + if(data.require_login_popup) {
  13 + $('#link_login').click(); //TODO see a better way to show login popup
  14 + }
  15 + }).complete(function() {
  16 + clicked.css("cursor","");
  17 + $(".small-loading").remove();
  18 + });
  19 + } else {
  20 + $('#link_login').click();
  21 + }
  22 + return false;
  23 + });
  24 + });
  25 +})(jQuery);
public/stylesheets/application.css
@@ -1817,6 +1817,18 @@ a.button.disabled, input.disabled { @@ -1817,6 +1817,18 @@ a.button.disabled, input.disabled {
1817 background-repeat: no-repeat; 1817 background-repeat: no-repeat;
1818 background-position: top right; 1818 background-position: top right;
1819 } 1819 }
  1820 +#box-organizer div.box-1 {
  1821 + background-image: url(../images/blocks/1.png);
  1822 +}
  1823 +#box-organizer div.box-2 {
  1824 + background-image: url(../images/blocks/2.png);
  1825 +}
  1826 +#box-organizer div.box-3 {
  1827 + background-image: url(../images/blocks/3.png);
  1828 +}
  1829 +#box-organizer div.box-4 {
  1830 + background-image: url(../images/blocks/4.png);
  1831 +}
1820 #box-organizer .block { 1832 #box-organizer .block {
1821 cursor: move; 1833 cursor: move;
1822 } 1834 }
@@ -4675,6 +4687,12 @@ h1#agenda-title { @@ -4675,6 +4687,12 @@ h1#agenda-title {
4675 .controller-profile_editor a.control-panel-welcome-page { 4687 .controller-profile_editor a.control-panel-welcome-page {
4676 background-image: url(../images/control-panel/welcome-page.png) 4688 background-image: url(../images/control-panel/welcome-page.png)
4677 } 4689 }
  4690 +.controller-profile_editor a.control-panel-roles {
  4691 + background-image: url(../images/control-panel/role-management.png)
  4692 +}
  4693 +.controller-profile_editor .msie6 a.control-panel-roles {
  4694 + background-image: url(../images/control-panel/role-management.gif)
  4695 +}
4678 /* ==> public/stylesheets/controller_profile_members.css <== */ 4696 /* ==> public/stylesheets/controller_profile_members.css <== */
4679 .controller-profile_members .no-boxes { 4697 .controller-profile_members .no-boxes {
4680 margin: 30px 4698 margin: 30px
script/install-dependencies/debian-wheezy.sh
1 -binary_packages='deb http://download.noosfero.org/debian/wheezy-1.1 ./' 1 +binary_packages='deb http://download.noosfero.org/debian/wheezy-1.2 ./'
2 2
3 source_packages=$(echo "$binary_packages" | sed -e 's/^deb/deb-src/') 3 source_packages=$(echo "$binary_packages" | sed -e 's/^deb/deb-src/')
4 4
@@ -53,6 +53,13 @@ FPQAoNmiMgP6zGF9rgOEWMEiFEryayrz @@ -53,6 +53,13 @@ FPQAoNmiMgP6zGF9rgOEWMEiFEryayrz
53 EOF 53 EOF
54 fi 54 fi
55 55
  56 +if grep -qrl wheezy /etc/apt/sources.list* && ! grep -qrl wheezy-backports /etc/apt/sources.list*; then
  57 + sudo tee /etc/apt/sources.list.d/backports.list <<EOF
  58 +deb http://httpredir.debian.org/debian wheezy-backports main
  59 +EOF
  60 +fi
  61 +
  62 +
56 if test -f tmp/debian/Release.gpg; then 63 if test -f tmp/debian/Release.gpg; then
57 echo "deb file://$(pwd)/tmp/debian/ ./" | sudo tee /etc/apt/sources.list.d/local.list 64 echo "deb file://$(pwd)/tmp/debian/ ./" | sudo tee /etc/apt/sources.list.d/local.list
58 sudo apt-key add tmp/debian/signing-key.asc 65 sudo apt-key add tmp/debian/signing-key.asc
@@ -65,6 +72,9 @@ run sudo apt-get -qy dist-upgrade @@ -65,6 +72,9 @@ run sudo apt-get -qy dist-upgrade
65 72
66 run sudo apt-get -y install dctrl-tools 73 run sudo apt-get -y install dctrl-tools
67 74
  75 +# *sigh* need ruby-rspec from backports
  76 +run sudo apt-get -y install -t wheezy-backports ruby-rspec
  77 +
68 # needed to run noosfero 78 # needed to run noosfero
69 packages=$(grep-dctrl -n -s Build-Depends,Depends,Recommends -S -X noosfero debian/control | sed -e '/^\s*#/d; s/([^)]*)//g; s/,\s*/\n/g' | grep -v 'memcached\|debconf\|dbconfig-common\|misc:Depends\|adduser\|mail-transport-agent') 79 packages=$(grep-dctrl -n -s Build-Depends,Depends,Recommends -S -X noosfero debian/control | sed -e '/^\s*#/d; s/([^)]*)//g; s/,\s*/\n/g' | grep -v 'memcached\|debconf\|dbconfig-common\|misc:Depends\|adduser\|mail-transport-agent')
70 run sudo apt-get -y install $packages 80 run sudo apt-get -y install $packages
test/functional/application_controller_test.rb
@@ -578,4 +578,22 @@ class ApplicationControllerTest &lt; ActionController::TestCase @@ -578,4 +578,22 @@ class ApplicationControllerTest &lt; ActionController::TestCase
578 assert_response :success 578 assert_response :success
579 end 579 end
580 580
  581 + should "redirect to 404 if profile is '~' and user is not logged in" do
  582 + get :index, :profile => '~'
  583 + assert_response :missing
  584 + end
  585 +
  586 + should "redirect to action when profile is '~' " do
  587 + login_as('ze')
  588 + get :index, :profile => '~'
  589 + assert_response 302
  590 + end
  591 +
  592 + should "substitute '~' by current user and redirect properly " do
  593 + login_as('ze')
  594 + profile = Profile.where(:identifier => 'ze').first
  595 + get :index, :profile => '~'
  596 + assert_redirected_to :controller => 'test', :action => 'index', :profile => profile.identifier
  597 + end
  598 +
581 end 599 end
test/functional/content_viewer_controller_test.rb
@@ -175,7 +175,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -175,7 +175,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
175 admin = fast_create(Person) 175 admin = fast_create(Person)
176 community.add_member(admin) 176 community.add_member(admin)
177 177
178 - folder = fast_create(Folder, :profile_id => community.id, :published => false) 178 + folder = fast_create(Folder, :profile_id => community.id, :published => false, :show_to_followers => false)
179 community.add_member(profile) 179 community.add_member(profile)
180 login_as(profile.identifier) 180 login_as(profile.identifier)
181 181
@@ -278,7 +278,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase @@ -278,7 +278,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
278 should 'not give access to private articles if logged in and only member' do 278 should 'not give access to private articles if logged in and only member' do
279 person = create_user('test_user').person 279 person = create_user('test_user').person
280 profile = Profile.create!(:name => 'test profile', :identifier => 'test_profile') 280 profile = Profile.create!(:name => 'test profile', :identifier => 'test_profile')
281 - intranet = Folder.create!(:name => 'my_intranet', :profile => profile, :published => false) 281 + intranet = Folder.create!(:name => 'my_intranet', :profile => profile, :published => false, :show_to_followers => false)
282 profile.affiliate(person, Profile::Roles.member(profile.environment.id)) 282 profile.affiliate(person, Profile::Roles.member(profile.environment.id))
283 login_as('test_user') 283 login_as('test_user')
284 284
test/functional/profile_design_controller_test.rb
@@ -681,9 +681,9 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase @@ -681,9 +681,9 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
681 end 681 end
682 end 682 end
683 683
684 - test 'should forbid POST to save for fixed blocks' do 684 + test 'should forbid POST to save for uneditable blocks' do
685 block = profile.blocks.last 685 block = profile.blocks.last
686 - block.fixed = true 686 + block.edit_modes = "none"
687 block.save! 687 block.save!
688 688
689 post :save, id: block.id, profile: profile.identifier 689 post :save, id: block.id, profile: profile.identifier
@@ -692,7 +692,7 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase @@ -692,7 +692,7 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
692 692
693 test 'should forbid POST to move_block for fixed blocks' do 693 test 'should forbid POST to move_block for fixed blocks' do
694 block = profile.blocks.last 694 block = profile.blocks.last
695 - block.fixed = true 695 + block.move_modes = "none"
696 block.save! 696 block.save!
697 697
698 post :move_block, id: block.id, profile: profile.identifier, target: "end-of-box-#{@box3.id}" 698 post :move_block, id: block.id, profile: profile.identifier, target: "end-of-box-#{@box3.id}"
test/functional/profile_roles_controller_test.rb 0 → 100644
@@ -0,0 +1,106 @@ @@ -0,0 +1,106 @@
  1 +require_relative "../test_helper"
  2 +require 'profile_roles_controller'
  3 +
  4 +class ProfileRolesControllerTest < ActionController::TestCase
  5 +
  6 + def setup
  7 + @controller = ProfileRolesController.new
  8 + @request = ActionController::TestRequest.new
  9 + @response = ActionController::TestResponse.new
  10 + @role = Role.find(:first)
  11 + end
  12 +
  13 + should 'create a custom role' do
  14 + community = fast_create(Community)
  15 + admin = create_user_with_permission('admin_user', 'manage_custom_roles', community)
  16 + login_as :admin_user
  17 + post :create, :profile => community.identifier, :role => {:name => "some_role", :permissions => ["edit_profile"] }
  18 + role = Role.where(:name => 'some_role').first
  19 +
  20 + assert_not_nil role
  21 + assert_equal community.id, role.profile_id
  22 + end
  23 +
  24 + should 'not create a custom role without permission' do
  25 + community = fast_create(Community)
  26 + moderator = create_user_with_permission('profile_admin', 'edit_profile', community)
  27 + login_as :profile_admin
  28 + post :create, :profile => community.identifier, :role => {:name => "new_admin", :permissions => ["edit_profile"] }
  29 +
  30 + assert_response 403
  31 + assert_template 'access_denied'
  32 +
  33 + role = Role.where(:name => 'new_admin')
  34 +
  35 + assert_empty role
  36 + end
  37 +
  38 +
  39 + should 'delete a custom role not used' do
  40 + community = fast_create(Community)
  41 + admin = create_user_with_permission('admin_user', 'manage_custom_roles', community)
  42 + login_as :admin_user
  43 + role = Role.create!({:name => 'delete_article', :key => 'profile_delete_article', :profile_id => community.id, :environment => Environment.default}, :without_protection => true)
  44 + post :remove , :profile => community.identifier, :id => role.id
  45 +
  46 + assert_response :redirect
  47 + assert_redirected_to :action => 'index'
  48 +
  49 + assert_not_includes Role.all, role
  50 + end
  51 +
  52 + should 'delete a custom role being used' do
  53 + community = fast_create(Community)
  54 + admin = create_user_with_permission('admin_user', 'manage_custom_roles', community)
  55 + login_as :admin_user
  56 + role = Role.create!({:name => 'delete_article', :key => 'profile_delete_article', :profile_id => community.id, :environment => Environment.default}, :without_protection => true)
  57 + admin.add_role(role, community)
  58 + moderator_role = Role.find_by_name("moderator")
  59 +
  60 + assert_not_includes community.members_by_role(moderator_role), admin
  61 +
  62 + post :remove , :profile => community.identifier, :id => role.id, :roles => [moderator_role.id]
  63 +
  64 + assert_response :redirect
  65 + assert_redirected_to :action => 'index'
  66 +
  67 + assert_not_includes Role.all, role
  68 + assert_includes community.members_by_role(moderator_role), admin
  69 + end
  70 +
  71 + should 'assign a custom role to single user' do
  72 + community = fast_create(Community)
  73 + admin = create_user_with_permission('admin_user', 'manage_custom_roles', community)
  74 + login_as :admin_user
  75 + role = Role.create!({:name => 'delete_article', :key => 'profile_delete_article', :profile_id => community.id, :environment => Environment.default}, :without_protection => true)
  76 +
  77 + assert_not_includes community.members_by_role(role), admin
  78 +
  79 + post :define, :profile => community.identifier, :id => role.id, :assign_role_by => "members", :person_id => admin.id
  80 +
  81 + assert_includes community.members_by_role(role), admin
  82 + end
  83 +
  84 + should 'replace a role with a custom role' do
  85 + community = fast_create(Community)
  86 + admin = create_user_with_permission('admin_user', 'manage_custom_roles', community)
  87 + moderator = create_user_with_permission('profile_admin', 'edit_profile', community)
  88 + login_as :admin_user
  89 + role = Role.create!({:name => 'delete_article', :key => 'profile_delete_article', :profile_id => community.id, :environment => Environment.default}, :without_protection => true)
  90 + moderator_role = Role.find_by_name("moderator")
  91 + admin.add_role(moderator_role, community)
  92 +
  93 + assert_not_includes community.members_by_role(role), admin
  94 +
  95 + assert_not_includes community.members_by_role(role), moderator
  96 + assert_not_includes community.members_by_role(moderator_role), moderator
  97 +
  98 + post :define, :profile => community.identifier, :id => role.id, :assign_role_by => "roles", :selected_role => moderator_role.id
  99 +
  100 + assert_not_includes community.members_by_role(moderator_role), admin
  101 + assert_includes community.members_by_role(role), admin
  102 +
  103 + assert_not_includes community.members_by_role(role), moderator
  104 + assert_not_includes community.members_by_role(moderator_role), moderator
  105 + end
  106 +end
test/integration/routing_test.rb
@@ -272,4 +272,8 @@ class RoutingTest &lt; ActionController::IntegrationTest @@ -272,4 +272,8 @@ class RoutingTest &lt; ActionController::IntegrationTest
272 assert_routing('/embed/block/12345', :controller => 'embed', :action => 'block', :id => '12345') 272 assert_routing('/embed/block/12345', :controller => 'embed', :action => 'block', :id => '12345')
273 end 273 end
274 274
  275 + should 'accept ~ as placeholder for current user' do
  276 + assert_routing('/profile/~', :controller => 'profile', :profile => '~', :action => 'index')
  277 + end
  278 +
275 end 279 end
test/unit/block_test.rb
@@ -39,6 +39,24 @@ class BlockTest &lt; ActiveSupport::TestCase @@ -39,6 +39,24 @@ class BlockTest &lt; ActiveSupport::TestCase
39 assert Block.new.editable? 39 assert Block.new.editable?
40 end 40 end
41 41
  42 + should 'be editable if edit modes is all' do
  43 + block = Block.new
  44 + block.edit_modes = 'all'
  45 +
  46 + assert block.editable?
  47 + end
  48 +
  49 + should 'be movable by default' do
  50 + assert Block.new.movable?
  51 + end
  52 +
  53 + should 'be movable if move modes is all' do
  54 + block = Block.new
  55 + block.move_modes = 'all'
  56 +
  57 + assert block.movable?
  58 + end
  59 +
42 should 'have default titles' do 60 should 'have default titles' do
43 b = Block.new 61 b = Block.new
44 b.expects(:default_title).returns('my title') 62 b.expects(:default_title).returns('my title')
test/unit/boxes_helper_test.rb
@@ -123,24 +123,24 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -123,24 +123,24 @@ class BoxesHelperTest &lt; ActionView::TestCase
123 display_box_content(box, '') 123 display_box_content(box, '')
124 end 124 end
125 125
126 - should 'not show move options on block when block is fixed' do 126 + should 'not show move options on block when block has no permission to edit' do
127 p = create_user_with_blocks 127 p = create_user_with_blocks
128 128
129 b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] 129 b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0]
130 - b.fixed = true 130 + b.move_modes = "none"
131 b.save! 131 b.save!
132 132
133 stubs(:environment).returns(p.environment) 133 stubs(:environment).returns(p.environment)
134 stubs(:user).returns(p) 134 stubs(:user).returns(p)
135 135
136 - assert_equal false, modifiable?(b) 136 + assert_equal false, movable?(b)
137 end 137 end
138 138
139 - should 'show move options on block when block is fixed and user is admin' do 139 + should 'show move options on block when block has no permission to edit and user is admin' do
140 p = create_user_with_blocks 140 p = create_user_with_blocks
141 141
142 b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0] 142 b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0]
143 - b.fixed = true 143 + b.edit_modes = "none"
144 b.save! 144 b.save!
145 145
146 p.environment.add_admin(p) 146 p.environment.add_admin(p)
@@ -148,7 +148,7 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -148,7 +148,7 @@ class BoxesHelperTest &lt; ActionView::TestCase
148 stubs(:environment).returns(p.environment) 148 stubs(:environment).returns(p.environment)
149 stubs(:user).returns(p) 149 stubs(:user).returns(p)
150 150
151 - assert_equal true, modifiable?(b) 151 + assert_equal true, movable?(b)
152 end 152 end
153 153
154 should 'consider boxes_limit without custom_design' do 154 should 'consider boxes_limit without custom_design' do
@@ -198,4 +198,16 @@ class BoxesHelperTest &lt; ActionView::TestCase @@ -198,4 +198,16 @@ class BoxesHelperTest &lt; ActionView::TestCase
198 assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '} 198 assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '}
199 end 199 end
200 200
  201 + should 'only show edit option on block' do
  202 + p = create_user_with_blocks
  203 +
  204 + b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0]
  205 + b.edit_modes = "only_edit"
  206 + b.save!
  207 +
  208 + stubs(:environment).returns(p.environment)
  209 + stubs(:user).returns(p)
  210 +
  211 + assert_equal false, b.editable?
  212 + end
201 end 213 end
test/unit/enterprise_test.rb
@@ -188,7 +188,7 @@ class EnterpriseTest &lt; ActiveSupport::TestCase @@ -188,7 +188,7 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
188 inactive_template.save! 188 inactive_template.save!
189 189
190 active_template = create(Enterprise, :name => 'enteprise template', :identifier => 'enterprise_template') 190 active_template = create(Enterprise, :name => 'enteprise template', :identifier => 'enterprise_template')
191 - assert_equal 3, active_template.boxes.size 191 + assert_equal 4, active_template.boxes.size
192 192
193 e = Environment.default 193 e = Environment.default
194 e.inactive_enterprise_template = inactive_template 194 e.inactive_enterprise_template = inactive_template
@@ -400,7 +400,7 @@ class EnterpriseTest &lt; ActiveSupport::TestCase @@ -400,7 +400,7 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
400 e.save! 400 e.save!
401 401
402 ent = create(Enterprise, :name => 'test enteprise', :identifier => 'test_ent') 402 ent = create(Enterprise, :name => 'test enteprise', :identifier => 'test_ent')
403 - assert_equal 3, ent.boxes.size 403 + assert_equal 4, ent.boxes.size
404 end 404 end
405 405
406 should 'collect the highlighted products with image' do 406 should 'collect the highlighted products with image' do
test/unit/profile_test.rb
@@ -901,6 +901,8 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -901,6 +901,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
901 901
902 should 'copy set of articles from a template' do 902 should 'copy set of articles from a template' do
903 template = create_user('test_template').person 903 template = create_user('test_template').person
  904 + template.is_template = true
  905 + template.save
904 template.articles.destroy_all 906 template.articles.destroy_all
905 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article') 907 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
906 a2 = fast_create(Article, :profile_id => template.id, :name => 'some child article', :parent_id => a1.id) 908 a2 = fast_create(Article, :profile_id => template.id, :name => 'some child article', :parent_id => a1.id)
@@ -934,6 +936,8 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -934,6 +936,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
934 936
935 should 'copy homepage from template' do 937 should 'copy homepage from template' do
936 template = create_user('test_template').person 938 template = create_user('test_template').person
  939 + template.is_template = true
  940 + template.save
937 template.articles.destroy_all 941 template.articles.destroy_all
938 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article') 942 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
939 template.home_page = a1 943 template.home_page = a1
@@ -949,6 +953,8 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -949,6 +953,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
949 953
950 should 'not advertise the articles copied from templates' do 954 should 'not advertise the articles copied from templates' do
951 template = create_user('test_template').person 955 template = create_user('test_template').person
  956 + template.is_template = true
  957 + template.save
952 template.articles.destroy_all 958 template.articles.destroy_all
953 a = fast_create(Article, :profile_id => template.id, :name => 'some xyz article') 959 a = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
954 960
@@ -962,7 +968,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -962,7 +968,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
962 end 968 end
963 969
964 should 'copy set of boxes from profile template' do 970 should 'copy set of boxes from profile template' do
965 - template = fast_create(Profile) 971 + template = fast_create(Profile, :is_template => true)
966 template.boxes.destroy_all 972 template.boxes.destroy_all
967 template.boxes << Box.new 973 template.boxes << Box.new
968 template.boxes[0].blocks << Block.new 974 template.boxes[0].blocks << Block.new
@@ -977,7 +983,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -977,7 +983,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
977 end 983 end
978 984
979 should 'copy layout template when applying template' do 985 should 'copy layout template when applying template' do
980 - template = fast_create(Profile) 986 + template = fast_create(Profile, :is_template => true)
981 template.layout_template = 'leftbar' 987 template.layout_template = 'leftbar'
982 template.save! 988 template.save!
983 989
@@ -989,7 +995,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -989,7 +995,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
989 end 995 end
990 996
991 should 'copy blocks when applying template' do 997 should 'copy blocks when applying template' do
992 - template = fast_create(Profile) 998 + template = fast_create(Profile, :is_template => true)
993 template.boxes.destroy_all 999 template.boxes.destroy_all
994 template.boxes << Box.new 1000 template.boxes << Box.new
995 template.boxes[0].blocks << Block.new 1001 template.boxes[0].blocks << Block.new
@@ -1004,7 +1010,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1004,7 +1010,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1004 end 1010 end
1005 1011
1006 should 'copy articles when applying template' do 1012 should 'copy articles when applying template' do
1007 - template = fast_create(Profile) 1013 + template = fast_create(Profile, :is_template => true)
1008 template.articles.create(:name => 'template article') 1014 template.articles.create(:name => 'template article')
1009 template.save! 1015 template.save!
1010 1016
@@ -1016,7 +1022,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1016,7 +1022,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1016 end 1022 end
1017 1023
1018 should 'rename existing articles when applying template' do 1024 should 'rename existing articles when applying template' do
1019 - template = fast_create(Profile) 1025 + template = fast_create(Profile, :is_template => true)
1020 template.boxes.destroy_all 1026 template.boxes.destroy_all
1021 template.boxes << Box.new 1027 template.boxes << Box.new
1022 template.boxes[0].blocks << Block.new 1028 template.boxes[0].blocks << Block.new
@@ -1033,7 +1039,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1033,7 +1039,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1033 end 1039 end
1034 1040
1035 should 'copy header when applying template' do 1041 should 'copy header when applying template' do
1036 - template = fast_create(Profile) 1042 + template = fast_create(Profile, :is_template => true)
1037 template[:custom_header] = '{name}' 1043 template[:custom_header] = '{name}'
1038 template.save! 1044 template.save!
1039 1045
@@ -1047,7 +1053,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1047,7 +1053,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1047 end 1053 end
1048 1054
1049 should 'copy footer when applying template' do 1055 should 'copy footer when applying template' do
1050 - template = create(Profile, :address => 'Template address', :custom_footer => '{address}') 1056 + template = create(Profile, :address => 'Template address', :custom_footer => '{address}', :is_template => true)
1051 1057
1052 p = create(Profile, :address => 'Profile address') 1058 p = create(Profile, :address => 'Profile address')
1053 p.apply_template(template) 1059 p.apply_template(template)
@@ -1058,7 +1064,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1058,7 +1064,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1058 end 1064 end
1059 1065
1060 should 'ignore failing validation when applying template' do 1066 should 'ignore failing validation when applying template' do
1061 - template = create(Profile, :layout_template => 'leftbar', :custom_footer => 'my custom footer', :custom_header => 'my custom header') 1067 + template = create(Profile, :layout_template => 'leftbar', :custom_footer => 'my custom footer', :custom_header => 'my custom header', :is_template => true)
1062 1068
1063 p = create(Profile) 1069 p = create(Profile)
1064 def p.validate 1070 def p.validate
@@ -1074,7 +1080,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1074,7 +1080,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1074 end 1080 end
1075 1081
1076 should 'copy homepage when applying template' do 1082 should 'copy homepage when applying template' do
1077 - template = fast_create(Profile) 1083 + template = fast_create(Profile, :is_template => true)
1078 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article') 1084 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
1079 template.home_page = a1 1085 template.home_page = a1
1080 template.save! 1086 template.save!
@@ -1161,7 +1167,7 @@ class ProfileTest &lt; ActiveSupport::TestCase @@ -1161,7 +1167,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1161 end 1167 end
1162 1168
1163 should 'copy public/private setting from template' do 1169 should 'copy public/private setting from template' do
1164 - template = fast_create(Profile, :public_profile => false) 1170 + template = fast_create(Profile, :public_profile => false, :is_template => true)
1165 p = fast_create(Profile) 1171 p = fast_create(Profile)
1166 p.apply_template(template) 1172 p.apply_template(template)
1167 assert_equal false, p.public_profile 1173 assert_equal false, p.public_profile
test/unit/user_test.rb
@@ -554,6 +554,7 @@ class UserTest &lt; ActiveSupport::TestCase @@ -554,6 +554,7 @@ class UserTest &lt; ActiveSupport::TestCase
554 554
555 should 'delay activation check with custom time' do 555 should 'delay activation check with custom time' do
556 NOOSFERO_CONF.stubs(:[]).with('hours_until_user_activation_check').returns(240) 556 NOOSFERO_CONF.stubs(:[]).with('hours_until_user_activation_check').returns(240)
  557 + NOOSFERO_CONF.stubs(:[]).with('exclude_profile_identifier_pattern')
557 user = new_user 558 user = new_user
558 job = Delayed::Job.last 559 job = Delayed::Job.last
559 assert_match /UserActivationJob/, job.handler 560 assert_match /UserActivationJob/, job.handler
util/debian-install/Vagrantfile
@@ -13,9 +13,11 @@ else @@ -13,9 +13,11 @@ else
13 local_debs = Dir.glob('*.deb') 13 local_debs = Dir.glob('*.deb')
14 debs.each do |f| 14 debs.each do |f|
15 fn = File.basename(f) 15 fn = File.basename(f)
16 - if local_debs.include?(fn)  
17 - local_debs.delete(fn)  
18 - else 16 +
  17 + local_debs.delete(fn)
  18 +
  19 + if File.stat(f) != File.stat(fn)
  20 + FileUtils::Verbose.rm_f(fn)
19 FileUtils::Verbose.ln f, '.' 21 FileUtils::Verbose.ln f, '.'
20 end 22 end
21 end 23 end
util/debian-install/install
@@ -61,19 +61,35 @@ deb http://download.noosfero.org/debian/wheezy-test ./ @@ -61,19 +61,35 @@ deb http://download.noosfero.org/debian/wheezy-test ./
61 deb-src http://download.noosfero.org/debian/wheezy-test ./ 61 deb-src http://download.noosfero.org/debian/wheezy-test ./
62 EOF 62 EOF
63 63
  64 +sed -e 's/wheezy/&-backports/' \
  65 + /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list
  66 +
64 export DEBIAN_FRONTEND=noninteractive 67 export DEBIAN_FRONTEND=noninteractive
65 68
  69 +# local debs
  70 +if [ -n "$(find /vagrant -name '*.deb')" ]; then
  71 + apt-get install -qy apt-utils bzip2
  72 + (
  73 + rm -rf /opt/noosfero
  74 + mkdir /opt/noosfero
  75 + cp /vagrant/*.deb /opt/noosfero
  76 + cd /opt/noosfero
  77 + apt-ftparchive packages . > Packages
  78 + cat Packages | gzip - > Packages.gz
  79 + cat Packages | bzip2 - > Packages.bz2
  80 + apt-ftparchive release . > Release
  81 + echo 'deb [trusted=yes] file:///opt/noosfero ./' > /etc/apt/sources.list.d/local.list
  82 + )
  83 +else
  84 + rm -f /etc/apt/sources.list.d/local.list
  85 +fi
  86 +
66 apt-get update 87 apt-get update
67 apt-get dist-upgrade -qy 88 apt-get dist-upgrade -qy
68 -apt-get install -qy postgresql ruby1.8 89 +apt-get install -qy postgresql
69 90
70 -if dpkg --unpack /vagrant/noosfero_*.deb /vagrant/noosfero-apache_*.deb; then  
71 - apt-cache policy noosfero  
72 - apt-get install -qyf  
73 -else  
74 - apt-cache policy noosfero  
75 - apt-get install -qy noosfero noosfero-apache  
76 -fi 91 +apt-cache policy noosfero
  92 +apt-get install -qy noosfero noosfero-apache
77 93
78 a2dissite 000-default 94 a2dissite 000-default
79 service apache2 reload 95 service apache2 reload
vendor/plugins/access_control/lib/role.rb
@@ -4,6 +4,7 @@ class Role &lt; ActiveRecord::Base @@ -4,6 +4,7 @@ class Role &lt; ActiveRecord::Base
4 4
5 has_many :role_assignments, :dependent => :destroy 5 has_many :role_assignments, :dependent => :destroy
6 belongs_to :environment 6 belongs_to :environment
  7 + belongs_to :organization
7 serialize :permissions, Array 8 serialize :permissions, Array
8 validates_presence_of :name 9 validates_presence_of :name
9 validates_uniqueness_of :name, :scope => :environment_id 10 validates_uniqueness_of :name, :scope => :environment_id