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
AUTHORS.md
... ... @@ -92,6 +92,7 @@ Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
92 92 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
93 93 Daniel Bucher <daniel.bucher88@gmail.com>
94 94 Daniel Cunha <daniel@colivre.coop.br>
  95 +daniel <dtygel@eita.org.br>
95 96 David Carlos <ddavidcarlos1392@gmail.com>
96 97 diegoamc <diegoamc90@gmail.com>
97 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 121 Diego + Jefferson <diegoamc90@gmail.com>
121 122 Diego Martinez <diegoamc90@gmail.com>
122 123 Diego + Renan <renanteruoc@gmail.com>
  124 +dtygel <dtygel@gmail.com>
123 125 DylanGuedes <djmgguedes@gmail.com>
124 126 Eduardo Passos <eduardo@risa.localdomain.localhost>
125 127 Eduardo Passos <eduardosteps@gmail.com>
... ... @@ -144,6 +146,7 @@ Italo Valcy &lt;italo@dcc.ufba.br&gt;
144 146 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
145 147 Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
146 148 Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>
  149 +Jérôme Jutteau <j.jutteau@gmail.com>
147 150 João da Silva + Eduardo Morais + Rafael Manzo <rr.manzo@gmail.com>
148 151 João da Silva <jaodsilv@linux.ime.usp.br>
149 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 250 Tallys Martins <tallysmartins@yahoo.com.br>
248 251 tallys <tallys@tallys>
249 252 tallys <tallys@tallys.(none)>
  253 +Thiago Casotti <thiago.casotti@uol.com.br>
250 254 Thiago Zoroastro <thiago.zoroastro@bol.com.br>
251 255 Tuux <tuxa@galaxie.eu.org>
  256 +TWS <tablettws@gmail.com>
252 257 Valessio Brito <contato@valessiobrito.com.br>
253 258 Valessio Brito <contato@valessiobrito.info>
254 259 Valessio Brito <valessio@gmail.com>
... ...
Gemfile
... ... @@ -27,23 +27,17 @@ gem &#39;api-pagination&#39;, &#39;~&gt; 4.1.1&#39;
27 27 gem 'rack-cors'
28 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 32 gem 'sass-rails'
36   -group :assets do
37   - gem 'uglifier', '>= 1.0.3'
38   -end
39 33  
40 34 group :production do
41 35 gem 'dalli', '~> 2.7.0'
42 36 end
43 37  
44 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 41 gem 'mocha', '~> 1.1.0', :require => false
48 42 end
49 43  
... ...
app/controllers/admin/role_controller.rb
... ... @@ -2,7 +2,7 @@ class RoleController &lt; AdminController
2 2 protect 'manage_environment_roles', :environment
3 3  
4 4 def index
5   - @roles = environment.roles.find(:all)
  5 + @roles = environment.roles.find(:all, :conditions => {:profile_id => nil})
6 6 end
7 7  
8 8 def new
... ...
app/controllers/application_controller.rb
... ... @@ -14,6 +14,7 @@ class ApplicationController &lt; ActionController::Base
14 14 def log_user
15 15 Rails.logger.info "Logged in: #{user.identifier}" if user
16 16 end
  17 + before_filter :redirect_to_current_user
17 18  
18 19 def verify_members_whitelist
19 20 render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
... ... @@ -197,4 +198,15 @@ class ApplicationController &lt; ActionController::Base
197 198 def private_environment?
198 199 @environment.enabled?(:restrict_to_members)
199 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 212 end
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -4,12 +4,20 @@ class ProfileDesignController &lt; BoxOrganizerController
4 4  
5 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 17 def protect_fixed_block
10 18 return if params[:id].blank?
11 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 21 render_access_denied
14 22 end
15 23 end
... ...
app/controllers/my_profile/profile_members_controller.rb
... ... @@ -58,6 +58,7 @@ class ProfileMembersController &lt; MyProfileController
58 58  
59 59 def change_role
60 60 @roles = Profile::Roles.organization_member_roles(environment.id)
  61 + @custom_roles = profile.custom_roles
61 62 begin
62 63 @member = profile.members.find(params[:id])
63 64 rescue ActiveRecord::RecordNotFound
... ...
app/controllers/my_profile/profile_roles_controller.rb 0 → 100644
... ... @@ -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 717 javascript_include_tag script if script
718 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 738 def file_field_or_thumbnail(label, image, i)
721 739 display_form_field label, (
722 740 render :partial => (image && image.valid? ? 'shared/show_thumbnail' : 'shared/change_image'),
... ...
app/helpers/boxes_helper.rb
... ... @@ -190,7 +190,7 @@ module BoxesHelper
190 190 else
191 191 "before-block-#{block.id}"
192 192 end
193   - if block.nil? or modifiable?(block)
  193 + if block.nil? || movable?(block)
194 194 url = url_for(:action => 'move_block', :target => id)
195 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 196 else
... ... @@ -200,7 +200,7 @@ module BoxesHelper
200 200  
201 201 # makes the given block draggable so it can be moved away.
202 202 def block_handle(block)
203   - return "" unless modifiable?(block)
  203 + return "" unless movable?(block)
204 204 icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>"
205 205 block_draggable("block-#{block.id}",
206 206 :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}")
... ... @@ -225,7 +225,7 @@ module BoxesHelper
225 225 buttons = []
226 226 nowhere = 'javascript: return false;'
227 227  
228   - if modifiable?(block)
  228 + if movable?(block)
229 229 if block.first?
230 230 buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere)
231 231 else
... ... @@ -248,15 +248,15 @@ module BoxesHelper
248 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 249 end
250 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 260 end
261 261  
262 262 if block.respond_to?(:help)
... ... @@ -292,7 +292,11 @@ module BoxesHelper
292 292 classes
293 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 301 end
298 302 end
... ...
app/helpers/layout_helper.rb
... ... @@ -38,6 +38,8 @@ module LayoutHelper
38 38 output += theme_javascript_ng.to_s
39 39 output += javascript_tag 'render_all_jquery_ui_widgets()'
40 40  
  41 + output += templete_javascript_ng.to_s
  42 +
41 43 output
42 44 end
43 45  
... ... @@ -70,11 +72,7 @@ module LayoutHelper
70 72 end
71 73  
72 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 76 end
79 77  
80 78  
... ...
app/models/block.rb
1 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 7 # to be able to generate HTML
6 8 include ActionView::Helpers::UrlHelper
... ... @@ -110,8 +112,13 @@ class Block &lt; ActiveRecord::Base
110 112 # * <tt>'all'</tt>: the block is always displayed
111 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 123 # returns the description of the block, used when the user sees a list of
117 124 # blocks to choose one to include in the design.
... ... @@ -178,7 +185,11 @@ class Block &lt; ActiveRecord::Base
178 185  
179 186 # Is this block editable? (Default to <tt>false</tt>)
180 187 def editable?
181   - true
  188 + self.edit_modes == "all"
  189 + end
  190 +
  191 + def movable?
  192 + self.move_modes == "all"
182 193 end
183 194  
184 195 # must always return false, except on MainBlock clas.
... ... @@ -258,6 +269,21 @@ class Block &lt; ActiveRecord::Base
258 269 }
259 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 287 def duplicate
262 288 duplicated_block = self.dup
263 289 duplicated_block.display = 'never'
... ...
app/models/environment.rb
... ... @@ -19,6 +19,8 @@ class Environment &lt; ActiveRecord::Base
19 19 filename
20 20 end
21 21  
  22 + NUMBER_OF_BOXES = 4
  23 +
22 24 PERMISSIONS['Environment'] = {
23 25 'view_environment_admin_panel' => N_('View environment admin panel'),
24 26 'edit_environment_features' => N_('Edit environment features'),
... ... @@ -172,7 +174,7 @@ class Environment &lt; ActiveRecord::Base
172 174 acts_as_having_boxes
173 175  
174 176 after_create do |env|
175   - 3.times do
  177 + NUMBER_OF_BOXES.times do
176 178 env.boxes << Box.new
177 179 end
178 180  
... ... @@ -737,8 +739,8 @@ class Environment &lt; ActiveRecord::Base
737 739 end
738 740  
739 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 744 is_default = is_default || template == enterprise_default_template
743 745 is_default
744 746 end
... ...
app/models/organization.rb
... ... @@ -36,6 +36,8 @@ class Organization &lt; Profile
36 36  
37 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 41 scope :more_popular, :order => 'members_count DESC'
40 42  
41 43 validate :presence_of_required_fieds, :unless => :is_template
... ...
app/models/profile.rb
... ... @@ -50,6 +50,8 @@ class Profile &lt; ActiveRecord::Base
50 50 self.template.custom_fields[field][:title]
51 51 end
52 52  
  53 + NUMBER_OF_BOXES = 4
  54 +
53 55 def self.default_search_display
54 56 'compact'
55 57 end
... ... @@ -71,7 +73,7 @@ class Profile &lt; ActiveRecord::Base
71 73 find_role('editor', env_id)
72 74 end
73 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 77 end
76 78 def self.all_roles(env_id)
77 79 Role.all :conditions => { :environment_id => env_id }
... ... @@ -103,6 +105,7 @@ class Profile &lt; ActiveRecord::Base
103 105 'publish_content' => N_('Publish content'),
104 106 'invite_members' => N_('Invite members'),
105 107 'send_mail_to_members' => N_('Send e-Mail to members'),
  108 + 'manage_custom_roles' => N_('Manage custom roles'),
106 109 }
107 110  
108 111 acts_as_accessible
... ... @@ -399,7 +402,7 @@ class Profile &lt; ActiveRecord::Base
399 402 if template
400 403 apply_template(template, :copy_articles => false)
401 404 else
402   - 3.times do
  405 + NUMBER_OF_BOXES.times do
403 406 self.boxes << Box.new
404 407 end
405 408  
... ... @@ -442,6 +445,7 @@ class Profile &lt; ActiveRecord::Base
442 445 alias_method_chain :template, :default
443 446  
444 447 def apply_template(template, options = {:copy_articles => true})
  448 + self.template = template
445 449 copy_blocks_from(template)
446 450 copy_articles_from(template) if options[:copy_articles]
447 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 2 <% if logged_in? %>
3 3 <% if profile.members.include?(user) %>
4 4 <%= button(:delete, content_tag('span', _('Leave community')), profile.leave_url,
... ...
app/views/box_organizer/edit.html.erb
... ... @@ -5,12 +5,6 @@
5 5  
6 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 8 <%= render :partial => partial_for_class(@block.class) %>
15 9  
16 10 <div class="display">
... ... @@ -25,6 +19,15 @@
25 19  
26 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 31 <% button_bar do %>
29 32 <%= submit_button(:save, _('Save')) %>
30 33 <%= modal_close_button(_('Cancel')) %>
... ...
app/views/profile_editor/index.html.erb
... ... @@ -28,6 +28,8 @@
28 28  
29 29 <%= control_panel_button(_('Manage Content'), 'cms', :controller => 'cms') %>
30 30  
  31 + <%= control_panel_button(_('Manage Roles'), 'roles', :controller => 'profile_roles') %>
  32 +
31 33 <% unless profile.enterprise? %>
32 34 <%= case profile.blogs.count
33 35 when 0
... ...
app/views/profile_members/change_role.html.erb
1 1 <h3> <%= _('Changing role of %s') % @member.name %> </h3>
2 2  
3 3 <%= labelled_form_for :member, :url => {:action => 'update_roles'} do |f| %>
4   -
5   - <%= _('Roles:') %> <br>
  4 +
  5 + <h4><%= _('Roles:') %></h4>
6 6 <% @roles.each do |r| %>
7 7 <%= labelled_check_box(r.name, 'roles[]', r.id, @associations.map(&:role).include?(r) ) %><br/>
8 8 <ul class="role-permissions">
... ... @@ -11,6 +11,17 @@
11 11 <% end %>
12 12 </ul>
13 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 25 <%= hidden_field_tag 'person', @member.id %>
15 26  
16 27 <% button_bar do %>
... ...
app/views/profile_roles/_form.html.erb 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 @@
  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 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 3 roles.each do |role|
4 4 content += labelled_check_box(role.name, "tasks[#{task.id}][task][roles][]", role.id, false)+"<br />"
5 5 end
6 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 35 config.assets.debug = true
36 36  
37 37 config.consider_all_requests_local = true
  38 +
  39 + # send emails to /tmp/mails
  40 + config.action_mailer.delivery_method = :file
  41 +
38 42 end
... ...
config/routes.rb
... ... @@ -56,37 +56,37 @@ Noosfero::Application.routes.draw do
56 56 match 'search(/:action(/*category_path))', :controller => 'search'
57 57  
58 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 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 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 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 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 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 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 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 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 91 # map balloon
92 92 match 'map_balloon/:action/:id', :controller => 'map_balloon', :id => /.*/
... ... @@ -98,8 +98,8 @@ Noosfero::Application.routes.draw do
98 98 ## Controllers that are profile-specific (for profile admins )
99 99 ######################################################
100 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 127 # cache stuff - hack
128 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 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 134 match '*page/versions_diff', :controller => 'content_viewer', :action => 'versions_diff'
135 135  
136 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 139 # match requests for content in domains hosted for profiles
140 140 match '/(*page)', :controller => 'content_viewer', :action => 'view_page'
... ...
db/migrate/20150203143051_add_reference_to_role.rb 0 → 100644
... ... @@ -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 @@
  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 @@
  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
... ...
db/schema.rb
... ... @@ -593,6 +593,7 @@ ActiveRecord::Schema.define(:version =&gt; 20150408231524) do
593 593 t.boolean "system", :default => false
594 594 t.text "permissions"
595 595 t.integer "environment_id"
  596 + t.integer "profile_id"
596 597 end
597 598  
598 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 13 noosfero (1.1~rc4) wheezy; urgency=medium
2 14  
3 15 * Fourth release candidate for Noosfero 1.1
... ...
debian/control
... ... @@ -14,8 +14,8 @@ Build-Depends: cucumber,
14 14 ruby-database-cleaner,
15 15 ruby-gettext,
16 16 ruby-mocha,
17   - ruby-rspec,
18   - ruby-rspec-rails,
  17 + ruby-rspec (>= 2.14),
  18 + ruby-rspec-rails (>= 2.14),
19 19 ruby-selenium-webdriver,
20 20 ruby-sqlite3,
21 21 ruby-tidy,
... ... @@ -59,7 +59,9 @@ Depends: adduser,
59 59 ruby-redcloth,
60 60 ruby-rest-client,
61 61 ruby-rmagick,
  62 + ruby-sass-rails,
62 63 ruby-tzinfo (>= 1.1.0-2~),
  64 + ruby-uglifier,
63 65 ruby-whenever,
64 66 ruby-will-paginate (>= 2.3.12-1~),
65 67 tango-icon-theme,
... ...
features/change_appearance.feature 0 → 100644
... ... @@ -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 94 owner.boxes<< Box.new
95 95 owner.boxes.first.blocks << MainBlock.new
96 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 99 end
100 100 end
101 101  
... ...
lib/authenticated_system.rb
... ... @@ -60,7 +60,11 @@ module AuthenticatedSystem
60 60 if logged_in? && authorized?
61 61 true
62 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 68 end
65 69 end
66 70  
... ...
lib/noosfero.rb
... ... @@ -57,6 +57,12 @@ module Noosfero
57 57 '(?!index)[a-z0-9][a-z0-9~.]*([_\-][a-z0-9~.]+)*'
58 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 66 def self.default_hostname
61 67 Environment.table_exists? && Environment.default ? Environment.default.default_hostname : 'localhost'
62 68 end
... ...
lib/noosfero/version.rb
1 1 module Noosfero
2 2 PROJECT = 'noosfero'
3   - VERSION = '1.1~rc4'
  3 + VERSION = '1.2~0'
4 4 end
5 5  
6 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 109 end
... ...
lib/tasks/doc.rake
... ... @@ -12,9 +12,8 @@ namespace :noosfero do
12 12 end
13 13 end
14 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 17 end
19 18 input = Dir.glob('doc/noosfero/**/*.textile') + plugins_textiles.map{|i| "doc/noosfero/plugins/#{File.basename(i)}"}
20 19 topics_xhtml = input.map { |item| item.sub('.textile', '.en.xhtml') }.uniq
... ...
lib/tasks/error_messages.rake
... ... @@ -4,7 +4,7 @@ targets = []
4 4 templates.each do |template|
5 5 target = template.gsub(/.erb$/, '')
6 6 targets << target
7   - file target => [:makemo, template] do
  7 + file target => [:makemo, template, :environment] do
8 8 require 'erb'
9 9 erb = ERB.new(File.read(template))
10 10 File.open(target, 'w') do |file|
... ...
plugins/ldap/lib/ldap_plugin.rb
... ... @@ -18,7 +18,8 @@ class LdapPlugin &lt; Noosfero::Plugin
18 18 # - login received by ldap
19 19 # - params from current context
20 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 23 end
23 24  
24 25 # -> Custom ldap plugin hotspot to update user object
... ... @@ -55,19 +56,22 @@ class LdapPlugin &lt; Noosfero::Plugin
55 56  
56 57 if attrs
57 58 user.login = login
58   - user.email = attrs[:mail]
  59 + user.email = get_email(attrs, login)
59 60 user.name = attrs[:fullname]
60 61 user.password = password
61 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 64 user.activated_at = Time.now.utc
65 65 user.activation_code = nil
66 66  
67 67 ldap = LdapAuthentication.new(context.environment.ldap_plugin_attributes)
68 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 75 rescue
72 76 #User not saved
73 77 end
... ... @@ -90,6 +94,16 @@ class LdapPlugin &lt; Noosfero::Plugin
90 94 user
91 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 107 def login_extra_contents
94 108 proc do
95 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 @@
  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 21 end
22 22  
23 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 34 end
26 35  
27 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 38 end
30 39  
31 40 def body_beginning
... ...
plugins/require_auth_to_comment/public/comment_require_login.js 0 → 100644
... ... @@ -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 5 def setup
6 6 @plugin = RequireAuthToCommentPlugin.new
7 7 @comment = Comment.new
  8 + @environment = fast_create(Environment)
8 9 end
9 10  
10   - attr_reader :plugin, :comment
  11 + attr_reader :plugin, :comment, :environment
11 12  
12 13 should 'reject comments for unauthenticated users' do
13 14 plugin.context = logged_in(false)
... ... @@ -29,6 +30,35 @@ class RequireAuthToCommentPluginTest &lt; ActiveSupport::TestCase
29 30 assert !comment.rejected?
30 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 62 protected
33 63  
34 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 @@
  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 @@
  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 1 class SubOrganizationsPlugin::Relation < Noosfero::Plugin::ActiveRecord
2   - record_timestamps = false
3   -
4 2 belongs_to :parent, :polymorphic => true
5 3 belongs_to :child, :polymorphic => true
6 4  
... ...
plugins/vote/public/style.css
1 1 .vote-actions {
2   - position: absolute;
3 2 top: 40px;
4 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 5  
6 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 10 <% if !voters.blank? %>
11 11 <span class="vote-detail">
... ...
public/designs/templates/lefttopright/config.yml 0 → 100644
... ... @@ -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 @@
  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 @@
  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 @@
  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 20  
21 21 .box-3 {
22 22 position: relative;
23   - display: table-footer-group;
  23 + display: table-header-group;
24 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 @@
  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 31 *= require select-or-die/_src/selectordie.js
32 32 *= require block-store.js
33 33 *= require jquery.typewatch.js
  34 +*= require require_login.js
34 35 */
35 36  
36 37 // scope for noosfero stuff
... ...
public/javascripts/assign_role.js 0 → 100644
... ... @@ -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 @@
  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 1817 background-repeat: no-repeat;
1818 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 1832 #box-organizer .block {
1821 1833 cursor: move;
1822 1834 }
... ... @@ -4675,6 +4687,12 @@ h1#agenda-title {
4675 4687 .controller-profile_editor a.control-panel-welcome-page {
4676 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 4696 /* ==> public/stylesheets/controller_profile_members.css <== */
4679 4697 .controller-profile_members .no-boxes {
4680 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 3 source_packages=$(echo "$binary_packages" | sed -e 's/^deb/deb-src/')
4 4  
... ... @@ -53,6 +53,13 @@ FPQAoNmiMgP6zGF9rgOEWMEiFEryayrz
53 53 EOF
54 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 63 if test -f tmp/debian/Release.gpg; then
57 64 echo "deb file://$(pwd)/tmp/debian/ ./" | sudo tee /etc/apt/sources.list.d/local.list
58 65 sudo apt-key add tmp/debian/signing-key.asc
... ... @@ -65,6 +72,9 @@ run sudo apt-get -qy dist-upgrade
65 72  
66 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 78 # needed to run noosfero
69 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 80 run sudo apt-get -y install $packages
... ...
test/functional/application_controller_test.rb
... ... @@ -578,4 +578,22 @@ class ApplicationControllerTest &lt; ActionController::TestCase
578 578 assert_response :success
579 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 599 end
... ...
test/functional/content_viewer_controller_test.rb
... ... @@ -175,7 +175,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
175 175 admin = fast_create(Person)
176 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 179 community.add_member(profile)
180 180 login_as(profile.identifier)
181 181  
... ... @@ -278,7 +278,7 @@ class ContentViewerControllerTest &lt; ActionController::TestCase
278 278 should 'not give access to private articles if logged in and only member' do
279 279 person = create_user('test_user').person
280 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 282 profile.affiliate(person, Profile::Roles.member(profile.environment.id))
283 283 login_as('test_user')
284 284  
... ...
test/functional/profile_design_controller_test.rb
... ... @@ -681,9 +681,9 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
681 681 end
682 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 685 block = profile.blocks.last
686   - block.fixed = true
  686 + block.edit_modes = "none"
687 687 block.save!
688 688  
689 689 post :save, id: block.id, profile: profile.identifier
... ... @@ -692,7 +692,7 @@ class ProfileDesignControllerTest &lt; ActionController::TestCase
692 692  
693 693 test 'should forbid POST to move_block for fixed blocks' do
694 694 block = profile.blocks.last
695   - block.fixed = true
  695 + block.move_modes = "none"
696 696 block.save!
697 697  
698 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 @@
  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 272 assert_routing('/embed/block/12345', :controller => 'embed', :action => 'block', :id => '12345')
273 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 279 end
... ...
test/unit/block_test.rb
... ... @@ -39,6 +39,24 @@ class BlockTest &lt; ActiveSupport::TestCase
39 39 assert Block.new.editable?
40 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 60 should 'have default titles' do
43 61 b = Block.new
44 62 b.expects(:default_title).returns('my title')
... ...
test/unit/boxes_helper_test.rb
... ... @@ -123,24 +123,24 @@ class BoxesHelperTest &lt; ActionView::TestCase
123 123 display_box_content(box, '')
124 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 127 p = create_user_with_blocks
128 128  
129 129 b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0]
130   - b.fixed = true
  130 + b.move_modes = "none"
131 131 b.save!
132 132  
133 133 stubs(:environment).returns(p.environment)
134 134 stubs(:user).returns(p)
135 135  
136   - assert_equal false, modifiable?(b)
  136 + assert_equal false, movable?(b)
137 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 140 p = create_user_with_blocks
141 141  
142 142 b = p.blocks.select{|bk| !bk.kind_of?(MainBlock) }[0]
143   - b.fixed = true
  143 + b.edit_modes = "none"
144 144 b.save!
145 145  
146 146 p.environment.add_admin(p)
... ... @@ -148,7 +148,7 @@ class BoxesHelperTest &lt; ActionView::TestCase
148 148 stubs(:environment).returns(p.environment)
149 149 stubs(:user).returns(p)
150 150  
151   - assert_equal true, modifiable?(b)
  151 + assert_equal true, movable?(b)
152 152 end
153 153  
154 154 should 'consider boxes_limit without custom_design' do
... ... @@ -198,4 +198,16 @@ class BoxesHelperTest &lt; ActionView::TestCase
198 198 assert_no_tag_in_string block_edit_buttons(block), :tag => 'a', :attributes => {:class => 'button icon-button icon-embed '}
199 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 213 end
... ...
test/unit/enterprise_test.rb
... ... @@ -188,7 +188,7 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
188 188 inactive_template.save!
189 189  
190 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 193 e = Environment.default
194 194 e.inactive_enterprise_template = inactive_template
... ... @@ -400,7 +400,7 @@ class EnterpriseTest &lt; ActiveSupport::TestCase
400 400 e.save!
401 401  
402 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 404 end
405 405  
406 406 should 'collect the highlighted products with image' do
... ...
test/unit/profile_test.rb
... ... @@ -901,6 +901,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
901 901  
902 902 should 'copy set of articles from a template' do
903 903 template = create_user('test_template').person
  904 + template.is_template = true
  905 + template.save
904 906 template.articles.destroy_all
905 907 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
906 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 936  
935 937 should 'copy homepage from template' do
936 938 template = create_user('test_template').person
  939 + template.is_template = true
  940 + template.save
937 941 template.articles.destroy_all
938 942 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
939 943 template.home_page = a1
... ... @@ -949,6 +953,8 @@ class ProfileTest &lt; ActiveSupport::TestCase
949 953  
950 954 should 'not advertise the articles copied from templates' do
951 955 template = create_user('test_template').person
  956 + template.is_template = true
  957 + template.save
952 958 template.articles.destroy_all
953 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 968 end
963 969  
964 970 should 'copy set of boxes from profile template' do
965   - template = fast_create(Profile)
  971 + template = fast_create(Profile, :is_template => true)
966 972 template.boxes.destroy_all
967 973 template.boxes << Box.new
968 974 template.boxes[0].blocks << Block.new
... ... @@ -977,7 +983,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
977 983 end
978 984  
979 985 should 'copy layout template when applying template' do
980   - template = fast_create(Profile)
  986 + template = fast_create(Profile, :is_template => true)
981 987 template.layout_template = 'leftbar'
982 988 template.save!
983 989  
... ... @@ -989,7 +995,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
989 995 end
990 996  
991 997 should 'copy blocks when applying template' do
992   - template = fast_create(Profile)
  998 + template = fast_create(Profile, :is_template => true)
993 999 template.boxes.destroy_all
994 1000 template.boxes << Box.new
995 1001 template.boxes[0].blocks << Block.new
... ... @@ -1004,7 +1010,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1004 1010 end
1005 1011  
1006 1012 should 'copy articles when applying template' do
1007   - template = fast_create(Profile)
  1013 + template = fast_create(Profile, :is_template => true)
1008 1014 template.articles.create(:name => 'template article')
1009 1015 template.save!
1010 1016  
... ... @@ -1016,7 +1022,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1016 1022 end
1017 1023  
1018 1024 should 'rename existing articles when applying template' do
1019   - template = fast_create(Profile)
  1025 + template = fast_create(Profile, :is_template => true)
1020 1026 template.boxes.destroy_all
1021 1027 template.boxes << Box.new
1022 1028 template.boxes[0].blocks << Block.new
... ... @@ -1033,7 +1039,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1033 1039 end
1034 1040  
1035 1041 should 'copy header when applying template' do
1036   - template = fast_create(Profile)
  1042 + template = fast_create(Profile, :is_template => true)
1037 1043 template[:custom_header] = '{name}'
1038 1044 template.save!
1039 1045  
... ... @@ -1047,7 +1053,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1047 1053 end
1048 1054  
1049 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 1058 p = create(Profile, :address => 'Profile address')
1053 1059 p.apply_template(template)
... ... @@ -1058,7 +1064,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1058 1064 end
1059 1065  
1060 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 1069 p = create(Profile)
1064 1070 def p.validate
... ... @@ -1074,7 +1080,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1074 1080 end
1075 1081  
1076 1082 should 'copy homepage when applying template' do
1077   - template = fast_create(Profile)
  1083 + template = fast_create(Profile, :is_template => true)
1078 1084 a1 = fast_create(Article, :profile_id => template.id, :name => 'some xyz article')
1079 1085 template.home_page = a1
1080 1086 template.save!
... ... @@ -1161,7 +1167,7 @@ class ProfileTest &lt; ActiveSupport::TestCase
1161 1167 end
1162 1168  
1163 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 1171 p = fast_create(Profile)
1166 1172 p.apply_template(template)
1167 1173 assert_equal false, p.public_profile
... ...
test/unit/user_test.rb
... ... @@ -554,6 +554,7 @@ class UserTest &lt; ActiveSupport::TestCase
554 554  
555 555 should 'delay activation check with custom time' do
556 556 NOOSFERO_CONF.stubs(:[]).with('hours_until_user_activation_check').returns(240)
  557 + NOOSFERO_CONF.stubs(:[]).with('exclude_profile_identifier_pattern')
557 558 user = new_user
558 559 job = Delayed::Job.last
559 560 assert_match /UserActivationJob/, job.handler
... ...
util/debian-install/Vagrantfile
... ... @@ -13,9 +13,11 @@ else
13 13 local_debs = Dir.glob('*.deb')
14 14 debs.each do |f|
15 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 21 FileUtils::Verbose.ln f, '.'
20 22 end
21 23 end
... ...
util/debian-install/install
... ... @@ -61,19 +61,35 @@ deb http://download.noosfero.org/debian/wheezy-test ./
61 61 deb-src http://download.noosfero.org/debian/wheezy-test ./
62 62 EOF
63 63  
  64 +sed -e 's/wheezy/&-backports/' \
  65 + /etc/apt/sources.list > /etc/apt/sources.list.d/backports.list
  66 +
64 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 87 apt-get update
67 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 94 a2dissite 000-default
79 95 service apache2 reload
... ...
vendor/plugins/access_control/lib/role.rb
... ... @@ -4,6 +4,7 @@ class Role &lt; ActiveRecord::Base
4 4  
5 5 has_many :role_assignments, :dependent => :destroy
6 6 belongs_to :environment
  7 + belongs_to :organization
7 8 serialize :permissions, Array
8 9 validates_presence_of :name
9 10 validates_uniqueness_of :name, :scope => :environment_id
... ...