Commit 45b484729bb6aa46e4902e0deadb2df9b480eaa1
Exists in
master
and in
29 other branches
Merge commit 'refs/merge-requests/248' of git://gitorious.org/noosfero/noosfero …
…into merge-requests/248 Conflicts: app/models/person.rb app/views/catalog/index.rhtml public/stylesheets/application.css test/functional/catalog_controller_test.rb
Showing
223 changed files
with
74020 additions
and
62087 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 223 files displayed.
app/controllers/admin/admin_panel_controller.rb
... | ... | @@ -8,6 +8,9 @@ class AdminPanelController < AdminController |
8 | 8 | |
9 | 9 | def site_info |
10 | 10 | if request.post? |
11 | + if params[:environment][:languages] | |
12 | + params[:environment][:languages] = params[:environment][:languages].map {|lang, value| lang if value=='true'}.compact | |
13 | + end | |
11 | 14 | if @environment.update_attributes(params[:environment]) |
12 | 15 | session[:notice] = _('Environment settings updated') |
13 | 16 | redirect_to :action => 'index' | ... | ... |
app/controllers/application_controller.rb
... | ... | @@ -42,9 +42,9 @@ class ApplicationController < ActionController::Base |
42 | 42 | |
43 | 43 | before_filter :set_locale |
44 | 44 | def set_locale |
45 | - FastGettext.available_locales = Noosfero.available_locales | |
46 | - FastGettext.default_locale = Noosfero.default_locale | |
47 | - FastGettext.locale = (params[:lang] || session[:lang] || Noosfero.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') | |
45 | + FastGettext.available_locales = environment.available_locales | |
46 | + FastGettext.default_locale = environment.default_locale | |
47 | + FastGettext.locale = (params[:lang] || session[:lang] || environment.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') | |
48 | 48 | I18n.locale = FastGettext.locale |
49 | 49 | if params[:lang] |
50 | 50 | session[:lang] = params[:lang] | ... | ... |
app/controllers/box_organizer_controller.rb
... | ... | @@ -68,7 +68,8 @@ class BoxOrganizerController < ApplicationController |
68 | 68 | raise ArgumentError.new("Type %s is not allowed. Go away." % type) |
69 | 69 | end |
70 | 70 | else |
71 | - @block_types = available_blocks | |
71 | + @center_block_types = Box.acceptable_center_blocks & available_blocks | |
72 | + @side_block_types = Box.acceptable_side_blocks & available_blocks | |
72 | 73 | @boxes = boxes_holder.boxes |
73 | 74 | render :action => 'add_block', :layout => false |
74 | 75 | end | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -116,11 +116,11 @@ class CmsController < MyProfileController |
116 | 116 | @parent_id = parent.id |
117 | 117 | end |
118 | 118 | |
119 | - translations if @article.translatable? | |
120 | - | |
121 | 119 | @article.profile = profile |
122 | 120 | @article.last_changed_by = user |
123 | 121 | |
122 | + translations if @article.translatable? | |
123 | + | |
124 | 124 | continue = params[:continue] |
125 | 125 | if request.post? |
126 | 126 | if @article.save |
... | ... | @@ -149,7 +149,6 @@ class CmsController < MyProfileController |
149 | 149 | @uploaded_files = [] |
150 | 150 | @article = @parent = check_parent(params[:parent_id]) |
151 | 151 | @target = @parent ? ('/%s/%s' % [profile.identifier, @parent.full_name]) : '/%s' % profile.identifier |
152 | - @folders = Folder.find(:all, :conditions => { :profile_id => profile }) | |
153 | 152 | if @article |
154 | 153 | record_coming |
155 | 154 | end |
... | ... | @@ -345,7 +344,7 @@ class CmsController < MyProfileController |
345 | 344 | end |
346 | 345 | |
347 | 346 | def translations |
348 | - @locales = Noosfero.locales.invert.reject { |name, lang| !@article.possible_translations.include?(lang) } | |
347 | + @locales = environment.locales.invert.reject { |name, lang| !@article.possible_translations.include?(lang) } | |
349 | 348 | @selected_locale = @article.language || FastGettext.locale |
350 | 349 | end |
351 | 350 | ... | ... |
app/controllers/my_profile/profile_design_controller.rb
... | ... | @@ -5,7 +5,7 @@ class ProfileDesignController < BoxOrganizerController |
5 | 5 | protect 'edit_profile_design', :profile |
6 | 6 | |
7 | 7 | def available_blocks |
8 | - blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock ] | |
8 | + blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ] | |
9 | 9 | |
10 | 10 | # blocks exclusive for organizations |
11 | 11 | if profile.has_members? | ... | ... |
app/controllers/my_profile/profile_editor_controller.rb
... | ... | @@ -14,6 +14,7 @@ class ProfileEditorController < MyProfileController |
14 | 14 | @profile_data = profile |
15 | 15 | @possible_domains = profile.possible_domains |
16 | 16 | if request.post? |
17 | + params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash) | |
17 | 18 | begin |
18 | 19 | Profile.transaction do |
19 | 20 | Image.transaction do | ... | ... |
app/controllers/my_profile/profile_members_controller.rb
... | ... | @@ -156,18 +156,4 @@ class ProfileMembersController < MyProfileController |
156 | 156 | end |
157 | 157 | end |
158 | 158 | |
159 | - def send_mail | |
160 | - @mailing = profile.mailings.build(params[:mailing]) | |
161 | - if request.post? | |
162 | - @mailing.locale = locale | |
163 | - @mailing.person = user | |
164 | - if @mailing.save | |
165 | - session[:notice] = _('The e-mails are being sent') | |
166 | - redirect_to :action => 'index' | |
167 | - else | |
168 | - session[:notice] = _('Could not create the e-mail') | |
169 | - end | |
170 | - end | |
171 | - end | |
172 | - | |
173 | 159 | end | ... | ... |
app/controllers/public/account_controller.rb
... | ... | @@ -25,11 +25,13 @@ class AccountController < ApplicationController |
25 | 25 | |
26 | 26 | # action to perform login to the application |
27 | 27 | def login |
28 | - @user = User.new | |
29 | - @person = @user.build_person | |
30 | 28 | store_location(request.referer) unless session[:return_to] |
31 | 29 | return unless request.post? |
32 | - self.current_user = User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user] | |
30 | + | |
31 | + self.current_user = plugins_alternative_authentication | |
32 | + | |
33 | + self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user] | |
34 | + | |
33 | 35 | if logged_in? |
34 | 36 | if params[:remember_me] == "1" |
35 | 37 | self.current_user.remember_me |
... | ... | @@ -41,7 +43,6 @@ class AccountController < ApplicationController |
41 | 43 | end |
42 | 44 | else |
43 | 45 | session[:notice] = _('Incorrect username or password') if redirect? |
44 | - redirect_to :back if redirect? | |
45 | 46 | end |
46 | 47 | end |
47 | 48 | |
... | ... | @@ -56,6 +57,11 @@ class AccountController < ApplicationController |
56 | 57 | |
57 | 58 | # action to register an user to the application |
58 | 59 | def signup |
60 | + if @plugins.dispatch(:allow_user_registration).include?(false) | |
61 | + redirect_back_or_default(:controller => 'home') | |
62 | + session[:notice] = _("This environment doesn't allow user registration.") | |
63 | + end | |
64 | + | |
59 | 65 | @invitation_code = params[:invitation_code] |
60 | 66 | begin |
61 | 67 | if params[:user] |
... | ... | @@ -125,6 +131,10 @@ class AccountController < ApplicationController |
125 | 131 | # |
126 | 132 | # Posts back. |
127 | 133 | def forgot_password |
134 | + if @plugins.dispatch(:allow_password_recovery).include?(false) | |
135 | + redirect_back_or_default(:controller => 'home') | |
136 | + session[:notice] = _("This environment doesn't allow password recovery.") | |
137 | + end | |
128 | 138 | @change_password = ChangePassword.new(params[:change_password]) |
129 | 139 | |
130 | 140 | if request.post? |
... | ... | @@ -303,10 +313,27 @@ class AccountController < ApplicationController |
303 | 313 | end |
304 | 314 | |
305 | 315 | def go_to_initial_page |
306 | - if environment == current_user.environment | |
307 | - redirect_back_or_default(user.admin_url) | |
316 | + if environment.enabled?('allow_change_of_redirection_after_login') | |
317 | + case user.preferred_login_redirection | |
318 | + when 'keep_on_same_page' | |
319 | + redirect_back_or_default(user.admin_url) | |
320 | + when 'site_homepage' | |
321 | + redirect_to :controller => :home | |
322 | + when 'user_profile_page' | |
323 | + redirect_to user.public_profile_url | |
324 | + when 'user_homepage' | |
325 | + redirect_to user.url | |
326 | + when 'user_control_panel' | |
327 | + redirect_to user.admin_url | |
328 | + else | |
329 | + redirect_back_or_default(user.admin_url) | |
330 | + end | |
308 | 331 | else |
309 | - redirect_back_or_default(:controller => 'home') | |
332 | + if environment == current_user.environment | |
333 | + redirect_back_or_default(user.admin_url) | |
334 | + else | |
335 | + redirect_back_or_default(:controller => 'home') | |
336 | + end | |
310 | 337 | end |
311 | 338 | end |
312 | 339 | |
... | ... | @@ -316,4 +343,13 @@ class AccountController < ApplicationController |
316 | 343 | end |
317 | 344 | end |
318 | 345 | |
346 | + def plugins_alternative_authentication | |
347 | + user = nil | |
348 | + @plugins.each do |plugin| | |
349 | + user = plugin.alternative_authentication | |
350 | + break unless user.nil? | |
351 | + end | |
352 | + user | |
353 | + end | |
354 | + | |
319 | 355 | end | ... | ... |
app/controllers/public/not_found_controller.rb
app/controllers/public/profile_controller.rb
... | ... | @@ -2,11 +2,13 @@ class ProfileController < PublicController |
2 | 2 | |
3 | 3 | needs_profile |
4 | 4 | before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] |
5 | - before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse] | |
6 | - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity] | |
5 | + before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail] | |
6 | + before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail] | |
7 | 7 | |
8 | 8 | helper TagsHelper |
9 | 9 | |
10 | + protect 'send_mail_to_members', :profile, :only => [:send_mail] | |
11 | + | |
10 | 12 | def index |
11 | 13 | @network_activities = !@profile.is_a?(Person) ? @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) : [] |
12 | 14 | if logged_in? && current_person.follows?(@profile) |
... | ... | @@ -49,36 +51,36 @@ class ProfileController < PublicController |
49 | 51 | |
50 | 52 | def communities |
51 | 53 | if is_cache_expired?(profile.communities_cache_key(params)) |
52 | - @communities = profile.communities.paginate(:per_page => per_page, :page => params[:npage]) | |
54 | + @communities = profile.communities.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage]) | |
53 | 55 | end |
54 | 56 | end |
55 | 57 | |
56 | 58 | def enterprises |
57 | - @enterprises = profile.enterprises | |
59 | + @enterprises = profile.enterprises.includes(relations_to_include) | |
58 | 60 | end |
59 | 61 | |
60 | 62 | def friends |
61 | 63 | if is_cache_expired?(profile.friends_cache_key(params)) |
62 | - @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage]) | |
64 | + @friends = profile.friends.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage]) | |
63 | 65 | end |
64 | 66 | end |
65 | 67 | |
66 | 68 | def members |
67 | 69 | if is_cache_expired?(profile.members_cache_key(params)) |
68 | - @members = profile.members.paginate(:per_page => members_per_page, :page => params[:npage]) | |
70 | + @members = profile.members.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage]) | |
69 | 71 | end |
70 | 72 | end |
71 | 73 | |
72 | 74 | def fans |
73 | - @fans = profile.fans | |
75 | + @fans = profile.fans.includes(relations_to_include) | |
74 | 76 | end |
75 | 77 | |
76 | 78 | def favorite_enterprises |
77 | - @favorite_enterprises = profile.favorite_enterprises | |
79 | + @favorite_enterprises = profile.favorite_enterprises.includes(relations_to_include) | |
78 | 80 | end |
79 | 81 | |
80 | 82 | def sitemap |
81 | - @articles = profile.top_level_articles | |
83 | + @articles = profile.top_level_articles.includes([:profile, :parent]) | |
82 | 84 | end |
83 | 85 | |
84 | 86 | def join |
... | ... | @@ -327,6 +329,20 @@ class ProfileController < PublicController |
327 | 329 | end |
328 | 330 | end |
329 | 331 | |
332 | + def send_mail | |
333 | + @mailing = profile.mailings.build(params[:mailing]) | |
334 | + if request.post? | |
335 | + @mailing.locale = locale | |
336 | + @mailing.person = user | |
337 | + if @mailing.save | |
338 | + session[:notice] = _('The e-mails are being sent') | |
339 | + redirect_to_previous_location | |
340 | + else | |
341 | + session[:notice] = _('Could not create the e-mail') | |
342 | + end | |
343 | + end | |
344 | + end | |
345 | + | |
330 | 346 | protected |
331 | 347 | |
332 | 348 | def check_access_to_profile |
... | ... | @@ -378,4 +394,8 @@ class ProfileController < PublicController |
378 | 394 | @can_edit_profile ||= user && user.has_permission?('edit_profile', profile) |
379 | 395 | end |
380 | 396 | helper_method :can_edit_profile |
397 | + | |
398 | + def relations_to_include | |
399 | + [:image, :domains, :preferred_domain, :environment] | |
400 | + end | |
381 | 401 | end | ... | ... |
app/controllers/public/search_controller.rb
... | ... | @@ -46,7 +46,7 @@ class SearchController < PublicController |
46 | 46 | if !@empty_query |
47 | 47 | full_text_search ['public:true'] |
48 | 48 | else |
49 | - @results[@asset] = @environment.people.visible.send(@filter).paginate(paginate_options) | |
49 | + @results[@asset] = visible_profiles(Person).send(@filter).paginate(paginate_options) | |
50 | 50 | end |
51 | 51 | end |
52 | 52 | |
... | ... | @@ -76,7 +76,7 @@ class SearchController < PublicController |
76 | 76 | full_text_search ['public:true'] |
77 | 77 | else |
78 | 78 | @filter_title = _('Enterprises from network') |
79 | - @results[@asset] = @environment.enterprises.visible.paginate(paginate_options) | |
79 | + @results[@asset] = visible_profiles(Enterprise, [{:products => :product_category}]).paginate(paginate_options) | |
80 | 80 | end |
81 | 81 | end |
82 | 82 | |
... | ... | @@ -84,7 +84,7 @@ class SearchController < PublicController |
84 | 84 | if !@empty_query |
85 | 85 | full_text_search ['public:true'] |
86 | 86 | else |
87 | - @results[@asset] = @environment.communities.visible.send(@filter).paginate(paginate_options) | |
87 | + @results[@asset] = visible_profiles(Community).send(@filter).paginate(paginate_options) | |
88 | 88 | end |
89 | 89 | end |
90 | 90 | |
... | ... | @@ -310,4 +310,12 @@ class SearchController < PublicController |
310 | 310 | @all_facets = ret[:all_facets] |
311 | 311 | end |
312 | 312 | |
313 | + private | |
314 | + | |
315 | + def visible_profiles(klass, *extra_relations) | |
316 | + relations = [:image, :domains, :environment, :preferred_domain] | |
317 | + relations += extra_relations | |
318 | + @environment.send(klass.name.underscore.pluralize).visible.includes(relations) | |
319 | + end | |
320 | + | |
313 | 321 | end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -265,9 +265,9 @@ module ApplicationHelper |
265 | 265 | |
266 | 266 | VIEW_EXTENSIONS = %w[.rhtml .html.erb] |
267 | 267 | |
268 | - def partial_for_class_in_view_path(klass, view_path) | |
268 | + def partial_for_class_in_view_path(klass, view_path, suffix = nil) | |
269 | 269 | return nil if klass.nil? |
270 | - name = klass.name.underscore | |
270 | + name = [klass.name.underscore, suffix].compact.map(&:to_s).join('_') | |
271 | 271 | |
272 | 272 | search_name = String.new(name) |
273 | 273 | if search_name.include?("/") |
... | ... | @@ -282,31 +282,20 @@ module ApplicationHelper |
282 | 282 | return name if File.exists?(File.join(path)) |
283 | 283 | end |
284 | 284 | |
285 | - partial_for_class_in_view_path(klass.superclass, view_path) | |
285 | + partial_for_class_in_view_path(klass.superclass, view_path, suffix) | |
286 | 286 | end |
287 | 287 | |
288 | - def partial_for_class(klass) | |
288 | + def partial_for_class(klass, suffix=nil) | |
289 | 289 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? |
290 | 290 | name = klass.name.underscore |
291 | 291 | @controller.view_paths.each do |view_path| |
292 | - partial = partial_for_class_in_view_path(klass, view_path) | |
292 | + partial = partial_for_class_in_view_path(klass, view_path, suffix) | |
293 | 293 | return partial if partial |
294 | 294 | end |
295 | 295 | |
296 | 296 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' |
297 | 297 | end |
298 | 298 | |
299 | - def partial_for_task_class(klass, action) | |
300 | - raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? | |
301 | - | |
302 | - name = "#{klass.name.underscore}_#{action.to_s}" | |
303 | - VIEW_EXTENSIONS.each do |ext| | |
304 | - return name if File.exists?(File.join(RAILS_ROOT, 'app', 'views', params[:controller], '_'+name+ext)) | |
305 | - end | |
306 | - | |
307 | - partial_for_task_class(klass.superclass, action) | |
308 | - end | |
309 | - | |
310 | 299 | def view_for_profile_actions(klass) |
311 | 300 | raise ArgumentError, 'No profile actions view for this class.' if klass.nil? |
312 | 301 | |
... | ... | @@ -664,19 +653,6 @@ module ApplicationHelper |
664 | 653 | content_tag('div', result) |
665 | 654 | end |
666 | 655 | |
667 | - def select_folder(label, object, method, collection, html_options = {}, js_options = {}) | |
668 | - root = profile ? profile.identifier : _("root") | |
669 | - labelled_form_field(label, select(object, method, | |
670 | - collection.map {|f| [ root + '/' + f.full_name, f.id ]}, | |
671 | - {:include_blank => root}, html_options.merge(js_options))) | |
672 | - end | |
673 | - | |
674 | - def select_profile_folder(label, object, method, profile, html_options = {}, js_options = {}) | |
675 | - labelled_form_field(label, select(object, method, | |
676 | - profile.folders.map {|f| [ profile.identifier + '/' + f.full_name, f.id ]}, | |
677 | - {:include_blank => profile.identifier}, html_options.merge(js_options))) | |
678 | - end | |
679 | - | |
680 | 656 | def theme_option(opt = nil) |
681 | 657 | conf = RAILS_ROOT.to_s() + |
682 | 658 | '/public' + theme_path + |
... | ... | @@ -877,7 +853,7 @@ module ApplicationHelper |
877 | 853 | end |
878 | 854 | else |
879 | 855 | if profile.active_fields.include?(name) |
880 | - result = field_html | |
856 | + result = content_tag('div', field_html + profile_field_privacy_selector(profile, name), :class => 'field-with-privacy-selector') | |
881 | 857 | end |
882 | 858 | end |
883 | 859 | |
... | ... | @@ -892,6 +868,11 @@ module ApplicationHelper |
892 | 868 | result |
893 | 869 | end |
894 | 870 | |
871 | + def profile_field_privacy_selector(profile, name) | |
872 | + return '' unless profile.public? | |
873 | + content_tag('div', labelled_check_box(_('Public'), 'profile_data[fields_privacy]['+name+']', 'public', profile.public_fields.include?(name)), :class => 'field-privacy-selector') | |
874 | + end | |
875 | + | |
895 | 876 | def template_stylesheet_path |
896 | 877 | if profile.nil? |
897 | 878 | "/designs/templates/#{environment.layout_template}/stylesheets/style.css" | ... | ... |
app/helpers/article_helper.rb
... | ... | @@ -2,14 +2,19 @@ module ArticleHelper |
2 | 2 | |
3 | 3 | def custom_options_for_article(article) |
4 | 4 | @article = article |
5 | + content_tag('h4', _('Visibility')) + | |
6 | + content_tag('div', | |
7 | + content_tag('div', | |
8 | + radio_button(:article, :published, true) + | |
9 | + content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | |
10 | + ) + | |
11 | + content_tag('div', | |
12 | + radio_button(:article, :published, false) + | |
13 | + content_tag('label', _('Private'), :for => 'article_published_false') | |
14 | + ) | |
15 | + ) + | |
5 | 16 | content_tag('h4', _('Options')) + |
6 | 17 | content_tag('div', |
7 | - content_tag( | |
8 | - 'div', | |
9 | - check_box(:article, :published) + | |
10 | - content_tag('label', _('This article must be published (visible to other people)'), :for => 'article_published') | |
11 | - ) + | |
12 | - | |
13 | 18 | (article.profile.has_members? ? |
14 | 19 | content_tag( |
15 | 20 | 'div', | ... | ... |
app/helpers/boxes_helper.rb
... | ... | @@ -66,7 +66,7 @@ module BoxesHelper |
66 | 66 | |
67 | 67 | def display_box_content(box, main_content) |
68 | 68 | context = { :article => @page, :request_path => request.path, :locale => locale } |
69 | - box_decorator.select_blocks(box.blocks, context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box) | |
69 | + box_decorator.select_blocks(box.blocks.includes(:box), context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box) | |
70 | 70 | end |
71 | 71 | |
72 | 72 | def select_blocks(arr, context) |
... | ... | @@ -162,9 +162,6 @@ module BoxesHelper |
162 | 162 | # |
163 | 163 | # +box+ is always needed |
164 | 164 | def block_target(box, block = nil) |
165 | - # FIXME hardcoded | |
166 | - return '' if box.position == 1 | |
167 | - | |
168 | 165 | id = |
169 | 166 | if block.nil? |
170 | 167 | "end-of-box-#{box.id}" |
... | ... | @@ -172,14 +169,11 @@ module BoxesHelper |
172 | 169 | "before-block-#{block.id}" |
173 | 170 | end |
174 | 171 | |
175 | - content_tag('div', ' ', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => 'block', :hoverclass => 'block-target-hover') | |
172 | + content_tag('div', ' ', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover') | |
176 | 173 | end |
177 | 174 | |
178 | 175 | # makes the given block draggable so it can be moved away. |
179 | 176 | def block_handle(block) |
180 | - # FIXME hardcoded | |
181 | - return '' if block.box.position == 1 | |
182 | - | |
183 | 177 | draggable_element("block-#{block.id}", :revert => true) |
184 | 178 | end |
185 | 179 | |
... | ... | @@ -211,7 +205,7 @@ module BoxesHelper |
211 | 205 | end |
212 | 206 | |
213 | 207 | if block.editable? |
214 | - buttons << lightbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id }) | |
208 | + buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id }) | |
215 | 209 | end |
216 | 210 | |
217 | 211 | if !block.main? | ... | ... |
app/helpers/colorbox_helper.rb
... | ... | @@ -8,6 +8,10 @@ module ColorboxHelper |
8 | 8 | button(type, label, url, colorbox_options(options)) |
9 | 9 | end |
10 | 10 | |
11 | + def colorbox_icon_button(type, label, url, options = {}) | |
12 | + icon_button(type, label, url, colorbox_options(options)) | |
13 | + end | |
14 | + | |
11 | 15 | # options must be an HTML options hash as passed to link_to etc. |
12 | 16 | # |
13 | 17 | # returns a new hash with colorbox class added. Keeps existing classes. | ... | ... |
app/helpers/content_viewer_helper.rb
... | ... | @@ -42,7 +42,7 @@ module ContentViewerHelper |
42 | 42 | def article_translations(article) |
43 | 43 | unless article.native_translation.translations.empty? |
44 | 44 | links = (article.native_translation.translations + [article.native_translation]).map do |translation| |
45 | - { Noosfero.locales[translation.language] => { :href => url_for(translation.url) } } | |
45 | + { article.environment.locales[translation.language] => { :href => url_for(translation.url) } } | |
46 | 46 | end |
47 | 47 | content_tag(:div, link_to(_('Translations'), '#', |
48 | 48 | :onclick => "toggleSubmenu(this, '#{_('Translations')}', #{links.to_json}); return false", | ... | ... |
app/helpers/display_helper.rb
... | ... | @@ -8,6 +8,14 @@ module DisplayHelper |
8 | 8 | opts |
9 | 9 | end |
10 | 10 | |
11 | + def themed_path(file) | |
12 | + if File.exists?(File.join(Rails.root, 'public', theme_path, file)) | |
13 | + File.join(theme_path, file) | |
14 | + else | |
15 | + file | |
16 | + end | |
17 | + end | |
18 | + | |
11 | 19 | def image_link_to_product(product, opts={}) |
12 | 20 | return _('No product') unless product |
13 | 21 | target = product_path(product) | ... | ... |
app/helpers/folder_helper.rb
... | ... | @@ -58,18 +58,18 @@ module FolderHelper |
58 | 58 | |
59 | 59 | def custom_options_for_article(article) |
60 | 60 | @article = article |
61 | - content_tag('h4', _('Options')) + | |
61 | + content_tag('h4', _('Visibility')) + | |
62 | + content_tag('div', | |
63 | + content_tag('div', | |
64 | + radio_button(:article, :published, true) + | |
65 | + content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true') | |
66 | + ) + | |
67 | + content_tag('div', | |
68 | + radio_button(:article, :published, false) + | |
69 | + content_tag('label', _('Private'), :for => 'article_published_false') | |
70 | + ) | |
71 | + ) + | |
62 | 72 | content_tag('div', |
63 | - content_tag( | |
64 | - 'div', | |
65 | - check_box(:article, :published) + | |
66 | - content_tag('label', _('This article must be published (visible to other people)'), :for => 'article_published') | |
67 | - ) + (article.can_display_hits? ? | |
68 | - content_tag( | |
69 | - 'div', | |
70 | - check_box(:article, :display_hits) + | |
71 | - content_tag('label', _('I want this article to display the number of hits it received'), :for => 'article_display_hits') | |
72 | - ) : '') + | |
73 | 73 | hidden_field_tag('article[accept_comments]', 0) |
74 | 74 | ) |
75 | 75 | end | ... | ... |
app/helpers/forms_helper.rb
... | ... | @@ -123,6 +123,170 @@ module FormsHelper |
123 | 123 | options_for_select.join("\n") |
124 | 124 | end |
125 | 125 | |
126 | + def balanced_table(items, per_row=3) | |
127 | + items = items.map {|item| content_tag('td', item, :style => 'border: none; background: transparent;')} | |
128 | + rows = [] | |
129 | + row = [] | |
130 | + counter = 0 | |
131 | + items.each do |item| | |
132 | + counter += 1 | |
133 | + row << item | |
134 | + if counter % per_row == 0 | |
135 | + rows << content_tag('tr', row.join("\n")) | |
136 | + counter = 0 | |
137 | + row = [] | |
138 | + end | |
139 | + end | |
140 | + rows << content_tag('tr', row.join("\n")) | |
141 | + | |
142 | + content_tag('table',rows.join("\n")) | |
143 | + end | |
144 | + | |
145 | + def date_field(name, value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) | |
146 | + datepicker_options[:disabled] ||= false | |
147 | + datepicker_options[:alt_field] ||= '' | |
148 | + datepicker_options[:alt_format] ||= '' | |
149 | + datepicker_options[:append_text] ||= '' | |
150 | + datepicker_options[:auto_size] ||= false | |
151 | + datepicker_options[:button_image] ||= '' | |
152 | + datepicker_options[:button_image_only] ||= false | |
153 | + datepicker_options[:button_text] ||= '...' | |
154 | + datepicker_options[:calculate_week] ||= 'jQuery.datepicker.iso8601Week' | |
155 | + datepicker_options[:change_month] ||= false | |
156 | + datepicker_options[:change_year] ||= false | |
157 | + datepicker_options[:close_text] ||= _('Done') | |
158 | + datepicker_options[:constrain_input] ||= true | |
159 | + datepicker_options[:current_text] ||= _('Today') | |
160 | + datepicker_options[:date_format] ||= 'mm/dd/yy' | |
161 | + datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')] | |
162 | + datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')] | |
163 | + datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')] | |
164 | + datepicker_options[:default_date] ||= nil | |
165 | + datepicker_options[:duration] ||= 'normal' | |
166 | + datepicker_options[:first_day] ||= 0 | |
167 | + datepicker_options[:goto_current] ||= false | |
168 | + datepicker_options[:hide_if_no_prev_next] ||= false | |
169 | + datepicker_options[:is_rtl] ||= false | |
170 | + datepicker_options[:max_date] ||= nil | |
171 | + datepicker_options[:min_date] ||= nil | |
172 | + datepicker_options[:month_names] ||= [_('January'), _('February'), _('March'), _('April'), _('May'), _('June'), _('July'), _('August'), _('September'), _('October'), _('November'), _('December')] | |
173 | + datepicker_options[:month_names_short] ||= [_('Jan'), _('Feb'), _('Mar'), _('Apr'), _('May'), _('Jun'), _('Jul'), _('Aug'), _('Sep'), _('Oct'), _('Nov'), _('Dec')] | |
174 | + datepicker_options[:navigation_as_date_format] ||= false | |
175 | + datepicker_options[:next_text] ||= _('Next') | |
176 | + datepicker_options[:number_of_months] ||= 1 | |
177 | + datepicker_options[:prev_text] ||= _('Prev') | |
178 | + datepicker_options[:select_other_months] ||= false | |
179 | + datepicker_options[:short_year_cutoff] ||= '+10' | |
180 | + datepicker_options[:show_button_panel] ||= false | |
181 | + datepicker_options[:show_current_at_pos] ||= 0 | |
182 | + datepicker_options[:show_month_after_year] ||= false | |
183 | + datepicker_options[:show_on] ||= 'focus' | |
184 | + datepicker_options[:show_options] ||= {} | |
185 | + datepicker_options[:show_other_months] ||= false | |
186 | + datepicker_options[:show_week] ||= false | |
187 | + datepicker_options[:step_months] ||= 1 | |
188 | + datepicker_options[:week_header] ||= _('Wk') | |
189 | + datepicker_options[:year_range] ||= 'c-10:c+10' | |
190 | + datepicker_options[:year_suffix] ||= '' | |
191 | + | |
192 | + element_id = html_options[:id] || 'datepicker-date' | |
193 | + value = value.strftime(format) if value.present? | |
194 | + method = datepicker_options[:time] ? 'datetimepicker' : 'datepicker' | |
195 | + result = text_field_tag(name, value, html_options) | |
196 | + result += | |
197 | + " | |
198 | + <script type='text/javascript'> | |
199 | + jQuery('##{element_id}').#{method}({ | |
200 | + disabled: #{datepicker_options[:disabled].to_json}, | |
201 | + altField: #{datepicker_options[:alt_field].to_json}, | |
202 | + altFormat: #{datepicker_options[:alt_format].to_json}, | |
203 | + appendText: #{datepicker_options[:append_text].to_json}, | |
204 | + autoSize: #{datepicker_options[:auto_size].to_json}, | |
205 | + buttonImage: #{datepicker_options[:button_image].to_json}, | |
206 | + buttonImageOnly: #{datepicker_options[:button_image_only].to_json}, | |
207 | + buttonText: #{datepicker_options[:button_text].to_json}, | |
208 | + calculateWeek: #{datepicker_options[:calculate_week].to_json}, | |
209 | + changeMonth: #{datepicker_options[:change_month].to_json}, | |
210 | + changeYear: #{datepicker_options[:change_year].to_json}, | |
211 | + closeText: #{datepicker_options[:close_text].to_json}, | |
212 | + constrainInput: #{datepicker_options[:constrain_input].to_json}, | |
213 | + currentText: #{datepicker_options[:current_text].to_json}, | |
214 | + dateFormat: #{datepicker_options[:date_format].to_json}, | |
215 | + dayNames: #{datepicker_options[:day_names].to_json}, | |
216 | + dayNamesMin: #{datepicker_options[:day_names_min].to_json}, | |
217 | + dayNamesShort: #{datepicker_options[:day_names_short].to_json}, | |
218 | + defaultDate: #{datepicker_options[:default_date].to_json}, | |
219 | + duration: #{datepicker_options[:duration].to_json}, | |
220 | + firstDay: #{datepicker_options[:first_day].to_json}, | |
221 | + gotoCurrent: #{datepicker_options[:goto_current].to_json}, | |
222 | + hideIfNoPrevNext: #{datepicker_options[:hide_if_no_prev_next].to_json}, | |
223 | + isRTL: #{datepicker_options[:is_rtl].to_json}, | |
224 | + maxDate: #{datepicker_options[:max_date].to_json}, | |
225 | + minDate: #{datepicker_options[:min_date].to_json}, | |
226 | + monthNames: #{datepicker_options[:month_names].to_json}, | |
227 | + monthNamesShort: #{datepicker_options[:month_names_short].to_json}, | |
228 | + navigationAsDateFormat: #{datepicker_options[:navigation_as_date_format].to_json}, | |
229 | + nextText: #{datepicker_options[:next_text].to_json}, | |
230 | + numberOfMonths: #{datepicker_options[:number_of_months].to_json}, | |
231 | + prevText: #{datepicker_options[:prev_text].to_json}, | |
232 | + selectOtherMonths: #{datepicker_options[:select_other_months].to_json}, | |
233 | + shortYearCutoff: #{datepicker_options[:short_year_cutoff].to_json}, | |
234 | + showButtonPanel: #{datepicker_options[:show_button_panel].to_json}, | |
235 | + showCurrentAtPos: #{datepicker_options[:show_current_at_pos].to_json}, | |
236 | + showMonthAfterYear: #{datepicker_options[:show_month_after_year].to_json}, | |
237 | + showOn: #{datepicker_options[:show_on].to_json}, | |
238 | + showOptions: #{datepicker_options[:show_options].to_json}, | |
239 | + showOtherMonths: #{datepicker_options[:show_other_months].to_json}, | |
240 | + showWeek: #{datepicker_options[:show_week].to_json}, | |
241 | + stepMonths: #{datepicker_options[:step_months].to_json}, | |
242 | + weekHeader: #{datepicker_options[:week_header].to_json}, | |
243 | + yearRange: #{datepicker_options[:year_range].to_json}, | |
244 | + yearSuffix: #{datepicker_options[:year_suffix].to_json} | |
245 | + }) | |
246 | + </script> | |
247 | + " | |
248 | + result | |
249 | + end | |
250 | + | |
251 | + def date_range_field(from_name, to_name, from_value, to_value, format = '%Y-%m-%d', datepicker_options = {}, html_options = {}) | |
252 | + from_id = html_options[:from_id] || 'datepicker-from-date' | |
253 | + to_id = html_options[:to_id] || 'datepicker-to-date' | |
254 | + return _('From') +' '+ date_field(from_name, from_value, format, datepicker_options, html_options.merge({:id => from_id})) + | |
255 | + ' ' + _('until') +' '+ date_field(to_name, to_value, format, datepicker_options, html_options.merge({:id => to_id})) | |
256 | + end | |
257 | + | |
258 | + def select_folder(label_text, field_id, collection, default_value=nil, html_options = {}, js_options = {}) | |
259 | + root = profile ? profile.identifier : _("root") | |
260 | + labelled_form_field( | |
261 | + label_text, | |
262 | + select_tag( | |
263 | + field_id, | |
264 | + options_for_select( | |
265 | + [[root, '']] + | |
266 | + collection.collect {|f| [ root + '/' + f.full_name, f.id ] }, | |
267 | + default_value | |
268 | + ), | |
269 | + html_options.merge(js_options) | |
270 | + ) | |
271 | + ) | |
272 | + end | |
273 | + | |
274 | + def select_profile_folder(label_text, field_id, profile, default_value='', html_options = {}, js_options = {}) | |
275 | + result = labelled_form_field( | |
276 | + label_text, | |
277 | + select_tag( | |
278 | + field_id, | |
279 | + options_for_select( | |
280 | + [[profile.identifier, '']] + | |
281 | + profile.folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] }, | |
282 | + default_value | |
283 | + ), | |
284 | + html_options.merge(js_options) | |
285 | + ) | |
286 | + ) | |
287 | + return result | |
288 | + end | |
289 | + | |
126 | 290 | protected |
127 | 291 | def self.next_id_number |
128 | 292 | if defined? @@id_num | ... | ... |
app/helpers/language_helper.rb
... | ... | @@ -13,18 +13,19 @@ module LanguageHelper |
13 | 13 | |
14 | 14 | alias :calendar_date_select_language :tinymce_language |
15 | 15 | |
16 | - def language_chooser(options = {}) | |
16 | + def language_chooser(environment, options = {}) | |
17 | + return if environment.locales.size < 2 | |
17 | 18 | current = language |
18 | 19 | separator = options[:separator] || ' — ' |
19 | 20 | |
20 | 21 | if options[:element] == 'dropdown' |
21 | 22 | select_tag('lang', |
22 | - options_for_select(Noosfero.locales.map{|code,name| [name, code]}, current), | |
23 | + options_for_select(environment.locales.map{|code,name| [name, code]}, current), | |
23 | 24 | :onchange => "document.location.href= #{url_for(params.merge(:lang => 'LANGUAGE')).inspect}.replace(/LANGUAGE/, this.value) ;", |
24 | 25 | :help => _('The language you choose here is the language used for options, buttons, etc. It does not affect the language of the content created by other users.') |
25 | 26 | ) |
26 | 27 | else |
27 | - languages = Noosfero.locales.map do |code,name| | |
28 | + languages = environment.locales.map do |code,name| | |
28 | 29 | if code == current |
29 | 30 | content_tag('strong', name) |
30 | 31 | else | ... | ... |
app/helpers/profile_editor_helper.rb
... | ... | @@ -145,4 +145,12 @@ module ProfileEditorHelper |
145 | 145 | link_to title, url, :class => 'control-panel-%s' % icon |
146 | 146 | end |
147 | 147 | |
148 | + def unchangeable_privacy_field(profile) | |
149 | + if profile.public? | |
150 | + labelled_check_box(_('Public'), '', '', true, :disabled => true, :title => _('This field must be public'), :class => 'disabled') | |
151 | + else | |
152 | + '' | |
153 | + end | |
154 | + end | |
155 | + | |
148 | 156 | end | ... | ... |
app/helpers/profile_helper.rb
1 | 1 | module ProfileHelper |
2 | 2 | |
3 | 3 | def display_field(title, profile, field, force = false) |
4 | - if !force && !profile.active_fields.include?(field.to_s) | |
4 | + if (!force && !profile.active_fields.include?(field.to_s)) || | |
5 | + (profile.active_fields.include?(field.to_s) && !profile.public_fields.include?(field.to_s) && (!user || (user != profile && !user.is_a_friend?(profile)))) | |
5 | 6 | return '' |
6 | 7 | end |
7 | 8 | value = profile.send(field) |
... | ... | @@ -15,4 +16,26 @@ module ProfileHelper |
15 | 16 | end |
16 | 17 | end |
17 | 18 | |
19 | + def display_contact(profile) | |
20 | + address = display_field(_('Address:'), profile, :address) | |
21 | + zip = display_field(_('ZIP code:'), profile, :zip_code) | |
22 | + phone = display_field(_('Contact phone:'), profile, :contact_phone) | |
23 | + email = display_field(_('e-Mail:'), profile, :email) { |email| link_to_email(email) } | |
24 | + if address.blank? && zip.blank? && phone.blank? && email.blank? | |
25 | + '' | |
26 | + else | |
27 | + content_tag('tr', content_tag('th', _('Contact'), { :colspan => 2 })) + address + zip + phone + email | |
28 | + end | |
29 | + end | |
30 | + | |
31 | + def display_work_info(profile) | |
32 | + organization = display_field(_('Organization:'), profile, :organization) | |
33 | + organization_site = display_field(_('Organization website:'), profile, :organization_website) { |url| link_to(url, url) } | |
34 | + if organization.blank? && organization_site.blank? | |
35 | + '' | |
36 | + else | |
37 | + content_tag('tr', content_tag('th', _('Work'), { :colspan => 2 })) + organization + organization_site | |
38 | + end | |
39 | + end | |
40 | + | |
18 | 41 | end | ... | ... |
app/models/article.rb
... | ... | @@ -79,6 +79,25 @@ class Article < ActiveRecord::Base |
79 | 79 | validate :native_translation_must_have_language |
80 | 80 | validate :translation_must_have_language |
81 | 81 | |
82 | + validate :no_self_reference | |
83 | + validate :no_cyclical_reference, :if => 'parent_id.present?' | |
84 | + | |
85 | + def no_self_reference | |
86 | + errors.add(:parent_id, _('self-reference is not allowed.')) if id && parent_id == id | |
87 | + end | |
88 | + | |
89 | + def no_cyclical_reference | |
90 | + current_parent = Article.find(parent_id) | |
91 | + while current_parent | |
92 | + if current_parent == self | |
93 | + errors.add(:parent_id, _('cyclical reference is not allowed.')) | |
94 | + break | |
95 | + end | |
96 | + current_parent = current_parent.parent | |
97 | + end | |
98 | + end | |
99 | + | |
100 | + | |
82 | 101 | def is_trackable? |
83 | 102 | self.published? && self.notifiable? && self.advertise? && self.profile.public_profile |
84 | 103 | end |
... | ... | @@ -154,6 +173,12 @@ class Article < ActiveRecord::Base |
154 | 173 | article.advertise = true |
155 | 174 | end |
156 | 175 | |
176 | + before_save do |article| | |
177 | + article.parent = article.parent_id ? Article.find(article.parent_id) : nil | |
178 | + parent_path = article.parent ? article.parent.path : nil | |
179 | + article.path = [parent_path, article.slug].compact.join('/') | |
180 | + end | |
181 | + | |
157 | 182 | # retrieves all articles belonging to the given +profile+ that are not |
158 | 183 | # sub-articles of any other article. |
159 | 184 | named_scope :top_level_for, lambda { |profile| |
... | ... | @@ -179,37 +204,23 @@ class Article < ActiveRecord::Base |
179 | 204 | end |
180 | 205 | |
181 | 206 | named_scope :more_popular, :order => 'hits DESC' |
182 | - | |
183 | - # retrieves the latest +limit+ articles, sorted from the most recent to the | |
184 | - # oldest. | |
185 | - # | |
186 | - # Only includes articles where advertise == true | |
187 | - def self.recent(limit = nil, extra_conditions = {}) | |
188 | - # FIXME this method is a horrible hack | |
189 | - options = { :page => 1, :per_page => limit, | |
190 | - :conditions => [ | |
191 | - "advertise = ? AND | |
192 | - published = ? AND | |
193 | - profiles.visible = ? AND | |
194 | - profiles.public_profile = ? AND | |
195 | - ((articles.type != ? and articles.type != ? and articles.type != ?) OR articles.type is NULL)", true, true, true, true, 'UploadedFile', 'RssFeed', 'Blog' | |
196 | - ], | |
197 | - :include => 'profile', | |
198 | - :order => 'articles.published_at desc, articles.id desc' | |
199 | - } | |
200 | - if ( scoped_methods && scoped_methods.last && | |
201 | - scoped_methods.last[:find] && | |
202 | - scoped_methods.last[:find][:joins] && | |
203 | - scoped_methods.last[:find][:joins].index('profiles') ) | |
204 | - options.delete(:include) | |
205 | - end | |
206 | - if extra_conditions == {} | |
207 | - self.paginate(options) | |
208 | - else | |
209 | - with_scope :find => {:conditions => extra_conditions} do | |
210 | - self.paginate(options) | |
211 | - end | |
207 | + named_scope :relevant_as_recent, :conditions => ["(articles.type != 'UploadedFile' and articles.type != 'RssFeed' and articles.type != 'Blog') OR articles.type is NULL"] | |
208 | + | |
209 | + def self.recent(limit = nil, extra_conditions = {}, pagination = true) | |
210 | + result = scoped({:conditions => extra_conditions}). | |
211 | + public. | |
212 | + relevant_as_recent. | |
213 | + limit(limit). | |
214 | + order(['articles.published_at desc', 'articles.id desc']) | |
215 | + | |
216 | + if !( scoped_methods && scoped_methods.last && | |
217 | + scoped_methods.last[:find] && | |
218 | + scoped_methods.last[:find][:joins] && | |
219 | + scoped_methods.last[:find][:joins].index('profiles') ) | |
220 | + result = result.includes(:profile) | |
212 | 221 | end |
222 | + | |
223 | + pagination ? result.paginate({:page => 1, :per_page => limit}) : result | |
213 | 224 | end |
214 | 225 | |
215 | 226 | # produces the HTML code that is to be displayed as this article's contents. |
... | ... | @@ -325,14 +336,14 @@ class Article < ActiveRecord::Base |
325 | 336 | end |
326 | 337 | |
327 | 338 | def possible_translations |
328 | - possibilities = Noosfero.locales.keys - self.native_translation.translations(:select => :language).map(&:language) - [self.native_translation.language] | |
339 | + possibilities = environment.locales.keys - self.native_translation.translations(:select => :language).map(&:language) - [self.native_translation.language] | |
329 | 340 | possibilities << self.language unless self.language_changed? |
330 | 341 | possibilities |
331 | 342 | end |
332 | 343 | |
333 | 344 | def known_language |
334 | 345 | unless self.language.blank? |
335 | - errors.add(:language, N_('Language not supported by Noosfero')) unless Noosfero.locales.key?(self.language) | |
346 | + errors.add(:language, N_('Language not supported by the environment.')) unless environment.locales.key?(self.language) | |
336 | 347 | end |
337 | 348 | end |
338 | 349 | |
... | ... | @@ -665,7 +676,7 @@ class Article < ActiveRecord::Base |
665 | 676 | self.categories.collect(&:name) |
666 | 677 | end |
667 | 678 | |
668 | - delegate :region, :region_id, :environment, :environment_id, :to => :profile | |
679 | + delegate :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true | |
669 | 680 | def name_sortable # give a different name for solr |
670 | 681 | name |
671 | 682 | end | ... | ... |
app/models/block.rb
app/models/box.rb
... | ... | @@ -2,4 +2,80 @@ class Box < ActiveRecord::Base |
2 | 2 | belongs_to :owner, :polymorphic => true |
3 | 3 | acts_as_list :scope => 'owner_id = #{owner_id} and owner_type = \'#{owner_type}\'' |
4 | 4 | has_many :blocks, :dependent => :destroy, :order => 'position' |
5 | + | |
6 | + def environment | |
7 | + owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil | |
8 | + end | |
9 | + | |
10 | + def acceptable_blocks | |
11 | + to_css_class_name central? ? Box.acceptable_center_blocks : Box.acceptable_side_blocks | |
12 | + end | |
13 | + | |
14 | + def central? | |
15 | + position == 1 | |
16 | + end | |
17 | + | |
18 | + def self.acceptable_center_blocks | |
19 | + [ ArticleBlock, | |
20 | + BlogArchivesBlock, | |
21 | + CategoriesBlock, | |
22 | + CommunitiesBlock, | |
23 | + EnterprisesBlock, | |
24 | + EnvironmentStatisticsBlock, | |
25 | + FansBlock, | |
26 | + FavoriteEnterprisesBlock, | |
27 | + FeedReaderBlock, | |
28 | + FriendsBlock, | |
29 | + HighlightsBlock, | |
30 | + LinkListBlock, | |
31 | + LoginBlock, | |
32 | + MainBlock, | |
33 | + MembersBlock, | |
34 | + MyNetworkBlock, | |
35 | + PeopleBlock, | |
36 | + ProfileImageBlock, | |
37 | + RawHTMLBlock, | |
38 | + RecentDocumentsBlock, | |
39 | + SellersSearchBlock, | |
40 | + TagsBlock ] | |
41 | + end | |
42 | + | |
43 | + def self.acceptable_side_blocks | |
44 | + [ ArticleBlock, | |
45 | + BlogArchivesBlock, | |
46 | + CategoriesBlock, | |
47 | + CommunitiesBlock, | |
48 | + DisabledEnterpriseMessageBlock, | |
49 | + EnterprisesBlock, | |
50 | + EnvironmentStatisticsBlock, | |
51 | + FansBlock, | |
52 | + FavoriteEnterprisesBlock, | |
53 | + FeaturedProductsBlock, | |
54 | + FeedReaderBlock, | |
55 | + FriendsBlock, | |
56 | + HighlightsBlock, | |
57 | + LinkListBlock, | |
58 | + LocationBlock, | |
59 | + LoginBlock, | |
60 | + MembersBlock, | |
61 | + MyNetworkBlock, | |
62 | + PeopleBlock, | |
63 | + ProductsBlock, | |
64 | + ProfileImageBlock, | |
65 | + ProfileInfoBlock, | |
66 | + ProfileSearchBlock, | |
67 | + RawHTMLBlock, | |
68 | + RecentDocumentsBlock, | |
69 | + SellersSearchBlock, | |
70 | + SlideshowBlock, | |
71 | + TagsBlock | |
72 | + ] | |
73 | + end | |
74 | + | |
75 | + private | |
76 | + | |
77 | + def to_css_class_name(blocks) | |
78 | + blocks.map{ |block| block.to_s.underscore.tr('_', '-') } | |
79 | + end | |
80 | + | |
5 | 81 | end | ... | ... |
app/models/change_password.rb
... | ... | @@ -7,7 +7,7 @@ class ChangePassword < Task |
7 | 7 | when :login: |
8 | 8 | _('Username') |
9 | 9 | when :email |
10 | - _('e-Mail') | |
10 | + _('e-mail') | |
11 | 11 | when :password |
12 | 12 | _('Password') |
13 | 13 | when :password_confirmation |
... | ... | @@ -20,9 +20,7 @@ class ChangePassword < Task |
20 | 20 | ################################################### |
21 | 21 | # validations for creating a ChangePassword task |
22 | 22 | |
23 | - validates_presence_of :login, :email, :environment_id, :on => :create | |
24 | - | |
25 | - validates_presence_of :requestor_id | |
23 | + validates_presence_of :login, :email, :environment_id, :on => :create, :message => _('must be filled in') | |
26 | 24 | |
27 | 25 | validates_format_of :email, :on => :create, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |obj| !obj.email.blank? }) |
28 | 26 | |
... | ... | @@ -30,10 +28,10 @@ class ChangePassword < Task |
30 | 28 | unless data.login.blank? || data.email.blank? |
31 | 29 | user = User.find_by_login_and_environment_id(data.login, data.environment_id) |
32 | 30 | if user.nil? |
33 | - data.errors.add(:login, _('%{fn} is not a valid username.').fix_i18n) | |
31 | + data.errors.add(:login, _('is invalid or user does not exists.')) | |
34 | 32 | else |
35 | 33 | if user.email != data.email |
36 | - data.errors.add(:email) | |
34 | + data.errors.add(:email, _('does not match the username you filled in')) | |
37 | 35 | end |
38 | 36 | end |
39 | 37 | end | ... | ... |
app/models/enterprise.rb
... | ... | @@ -17,7 +17,7 @@ class Enterprise < Organization |
17 | 17 | after_save_reindex [:products], :with => :delayed_job |
18 | 18 | extra_data_for_index :product_categories |
19 | 19 | def product_categories |
20 | - products.map{|p| p.category_full_name}.compact | |
20 | + products.includes(:product_category).map{|p| p.category_full_name}.compact | |
21 | 21 | end |
22 | 22 | |
23 | 23 | N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code') | ... | ... |
app/models/environment.rb
... | ... | @@ -123,10 +123,23 @@ class Environment < ActiveRecord::Base |
123 | 123 | 'xmpp_chat' => _('XMPP/Jabber based chat'), |
124 | 124 | 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'), |
125 | 125 | 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'), |
126 | - 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users') | |
126 | + 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'), | |
127 | + 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'), | |
128 | + 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login') | |
127 | 129 | } |
128 | 130 | end |
129 | 131 | |
132 | + def self.login_redirection_options | |
133 | + { | |
134 | + 'keep_on_same_page' => _('Stays on the same page the user was before login.'), | |
135 | + 'site_homepage' => _('Redirects the user to the environment homepage.'), | |
136 | + 'user_profile_page' => _('Redirects the user to his profile page.'), | |
137 | + 'user_homepage' => _('Redirects the user to his homepage.'), | |
138 | + 'user_control_panel' => _('Redirects the user to his control panel.') | |
139 | + } | |
140 | + end | |
141 | + validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true | |
142 | + | |
130 | 143 | # ################################################# |
131 | 144 | # Relationships and applied behaviour |
132 | 145 | # ################################################# |
... | ... | @@ -530,6 +543,31 @@ class Environment < ActiveRecord::Base |
530 | 543 | signup_fields |
531 | 544 | end |
532 | 545 | |
546 | + serialize :signup_welcome_text, Hash | |
547 | + def signup_welcome_text | |
548 | + self[:signup_welcome_text] ||= {} | |
549 | + end | |
550 | + | |
551 | + def signup_welcome_text_subject | |
552 | + self.signup_welcome_text[:subject] | |
553 | + end | |
554 | + | |
555 | + def signup_welcome_text_subject=(subject) | |
556 | + self.signup_welcome_text[:subject] = subject | |
557 | + end | |
558 | + | |
559 | + def signup_welcome_text_body | |
560 | + self.signup_welcome_text[:body] | |
561 | + end | |
562 | + | |
563 | + def signup_welcome_text_body=(body) | |
564 | + self.signup_welcome_text[:body] = body | |
565 | + end | |
566 | + | |
567 | + def has_signup_welcome_text? | |
568 | + signup_welcome_text && !signup_welcome_text_body.blank? | |
569 | + end | |
570 | + | |
533 | 571 | # ################################################# |
534 | 572 | # Validations |
535 | 573 | # ################################################# |
... | ... | @@ -591,8 +629,8 @@ class Environment < ActiveRecord::Base |
591 | 629 | end |
592 | 630 | |
593 | 631 | has_many :articles, :through => :profiles |
594 | - def recent_documents(limit = 10) | |
595 | - self.articles.recent(limit) | |
632 | + def recent_documents(limit = 10, options = {}, pagination = true) | |
633 | + self.articles.recent(limit, options, pagination) | |
596 | 634 | end |
597 | 635 | |
598 | 636 | has_many :events, :through => :profiles, :source => :articles, :class_name => 'Event' |
... | ... | @@ -766,4 +804,53 @@ class Environment < ActiveRecord::Base |
766 | 804 | def image_galleries |
767 | 805 | portal_community ? portal_community.image_galleries : [] |
768 | 806 | end |
807 | + | |
808 | + serialize :languages | |
809 | + | |
810 | + before_validation do |environment| | |
811 | + environment.default_language = nil if environment.default_language.blank? | |
812 | + end | |
813 | + | |
814 | + validate :default_language_available | |
815 | + validate :languages_available | |
816 | + | |
817 | + def locales | |
818 | + if languages.present? | |
819 | + languages.inject({}) {|r, l| r.merge({l => Noosfero.locales[l]})} | |
820 | + else | |
821 | + Noosfero.locales | |
822 | + end | |
823 | + end | |
824 | + | |
825 | + def default_locale | |
826 | + default_language || Noosfero.default_locale | |
827 | + end | |
828 | + | |
829 | + def available_locales | |
830 | + locales_list = locales.keys | |
831 | + # move English to the beginning | |
832 | + if locales_list.include?('en') | |
833 | + locales_list = ['en'] + (locales_list - ['en']).sort | |
834 | + end | |
835 | + locales_list | |
836 | + end | |
837 | + | |
838 | + private | |
839 | + | |
840 | + def default_language_available | |
841 | + if default_language.present? && !available_locales.include?(default_language) | |
842 | + errors.add(:default_language, _('is not available.')) | |
843 | + end | |
844 | + end | |
845 | + | |
846 | + def languages_available | |
847 | + if languages.present? | |
848 | + languages.each do |language| | |
849 | + if !Noosfero.available_locales.include?(language) | |
850 | + errors.add(:languages, _('have unsupported languages.')) | |
851 | + break | |
852 | + end | |
853 | + end | |
854 | + end | |
855 | + end | |
769 | 856 | end | ... | ... |
app/models/external_feed.rb
... | ... | @@ -19,9 +19,15 @@ class ExternalFeed < ActiveRecord::Base |
19 | 19 | article.valid? |
20 | 20 | end |
21 | 21 | |
22 | + def address=(new_address) | |
23 | + self.fetched_at = nil unless address == new_address | |
24 | + super(new_address) | |
25 | + end | |
26 | + | |
22 | 27 | def clear |
23 | 28 | # do nothing |
24 | 29 | end |
30 | + | |
25 | 31 | def finish_fetch |
26 | 32 | if self.only_once && self.update_errors.zero? |
27 | 33 | self.enabled = false | ... | ... |
app/models/person.rb
... | ... | @@ -71,10 +71,7 @@ class Person < Profile |
71 | 71 | Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy } |
72 | 72 | end |
73 | 73 | |
74 | - after_destroy :destroy_user | |
75 | - def destroy_user | |
76 | - self.user.destroy if self.user | |
77 | - end | |
74 | + belongs_to :user, :dependent => :delete | |
78 | 75 | |
79 | 76 | def can_control_scrap?(scrap) |
80 | 77 | begin |
... | ... | @@ -183,7 +180,8 @@ class Person < Profile |
183 | 180 | include MaybeAddHttp |
184 | 181 | |
185 | 182 | def active_fields |
186 | - environment ? environment.active_person_fields : [] | |
183 | + fields = environment ? environment.active_person_fields : [] | |
184 | + fields << 'email' | |
187 | 185 | end |
188 | 186 | |
189 | 187 | def required_fields |
... | ... | @@ -253,7 +251,7 @@ class Person < Profile |
253 | 251 | |
254 | 252 | def is_admin?(environment = nil) |
255 | 253 | environment ||= self.environment |
256 | - role_assignments.select { |ra| ra.resource == environment }.map{|ra|ra.role.permissions}.any? do |ps| | |
254 | + role_assignments.includes([:role, :resource]).select { |ra| ra.resource == environment }.map{|ra|ra.role.permissions}.any? do |ps| | |
257 | 255 | ps.any? do |p| |
258 | 256 | ActiveRecord::Base::PERMISSIONS['Environment'].keys.include?(p) |
259 | 257 | end |
... | ... | @@ -461,6 +459,10 @@ class Person < Profile |
461 | 459 | Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} and action_tracker.verb != 'leave_scrap_to_self' and action_tracker.verb != 'add_member_in_community' ORDER BY updated_at DESC") |
462 | 460 | end |
463 | 461 | |
462 | + def public_fields | |
463 | + self.fields_privacy.nil? ? self.active_fields : self.fields_privacy.reject{ |k, v| v != 'public' }.keys.map(&:to_s) | |
464 | + end | |
465 | + | |
464 | 466 | protected |
465 | 467 | |
466 | 468 | def followed_by?(profile) | ... | ... |
app/models/profile.rb
... | ... | @@ -57,6 +57,7 @@ class Profile < ActiveRecord::Base |
57 | 57 | 'view_private_content' => N_('View private content'), |
58 | 58 | 'publish_content' => N_('Publish content'), |
59 | 59 | 'invite_members' => N_('Invite members'), |
60 | + 'send_mail_to_members' => N_('Send e-Mail to members'), | |
60 | 61 | } |
61 | 62 | |
62 | 63 | acts_as_accessible |
... | ... | @@ -147,6 +148,7 @@ class Profile < ActiveRecord::Base |
147 | 148 | settings_items :redirect_l10n, :type => :boolean, :default => false |
148 | 149 | settings_items :public_content, :type => :boolean, :default => true |
149 | 150 | settings_items :description |
151 | + settings_items :fields_privacy, :type => :hash, :default => {} | |
150 | 152 | |
151 | 153 | validates_length_of :description, :maximum => 550, :allow_nil => true |
152 | 154 | |
... | ... | @@ -402,8 +404,8 @@ class Profile < ActiveRecord::Base |
402 | 404 | # |
403 | 405 | # +limit+ is the maximum number of documents to be returned. It defaults to |
404 | 406 | # 10. |
405 | - def recent_documents(limit = 10, options = {}) | |
406 | - self.articles.recent(limit, options) | |
407 | + def recent_documents(limit = 10, options = {}, pagination = true) | |
408 | + self.articles.recent(limit, options, pagination) | |
407 | 409 | end |
408 | 410 | |
409 | 411 | def last_articles(limit = 10, options = {}) |
... | ... | @@ -879,6 +881,15 @@ private :generate_url, :url_options |
879 | 881 | [] |
880 | 882 | end |
881 | 883 | |
884 | + # field => privacy (e.g.: "address" => "public") | |
885 | + def fields_privacy | |
886 | + self.data[:fields_privacy] | |
887 | + end | |
888 | + | |
889 | + def public_fields | |
890 | + self.active_fields | |
891 | + end | |
892 | + | |
882 | 893 | private |
883 | 894 | def self.f_categories_label_proc(environment) |
884 | 895 | ids = environment.top_level_category_as_facet_ids |
... | ... | @@ -975,4 +986,8 @@ private :generate_url, :url_options |
975 | 986 | end |
976 | 987 | end |
977 | 988 | |
989 | + validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true | |
990 | + def preferred_login_redirection | |
991 | + redirection_after_login.blank? ? environment.redirection_after_login : redirection_after_login | |
992 | + end | |
978 | 993 | end | ... | ... |
app/models/profile_list_block.rb
... | ... | @@ -14,12 +14,13 @@ class ProfileListBlock < Block |
14 | 14 | |
15 | 15 | def profile_list |
16 | 16 | result = nil |
17 | + visible_profiles = profiles.visible.includes([:image,:domains,:preferred_domain,:environment]) | |
17 | 18 | if !prioritize_profiles_with_image |
18 | - result = profiles.visible.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand } | |
19 | - elsif profiles.visible.with_image.count >= limit | |
20 | - result = profiles.visible.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } | |
19 | + result = visible_profiles.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand } | |
20 | + elsif visible_profiles.with_image.count >= limit | |
21 | + result = visible_profiles.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } | |
21 | 22 | else |
22 | - result = profiles.visible.with_image.sort_by{ rand } + profiles.visible.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } | |
23 | + result = visible_profiles.with_image.sort_by{ rand } + visible_profiles.without_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } | |
23 | 24 | end |
24 | 25 | result.slice(0..limit-1) |
25 | 26 | end | ... | ... |
app/models/recent_documents_block.rb
... | ... | @@ -16,11 +16,9 @@ class RecentDocumentsBlock < Block |
16 | 16 | |
17 | 17 | include ActionController::UrlWriter |
18 | 18 | def content(args={}) |
19 | - docs = self.limit.nil? ? owner.recent_documents : owner.recent_documents(self.limit) | |
20 | - | |
19 | + docs = self.limit.nil? ? owner.recent_documents(nil, {}, false) : owner.recent_documents(self.limit, {}, false) | |
21 | 20 | block_title(title) + |
22 | 21 | content_tag('ul', docs.map {|item| content_tag('li', link_to(h(item.title), item.url))}.join("\n")) |
23 | - | |
24 | 22 | end |
25 | 23 | |
26 | 24 | def footer | ... | ... |
app/models/task.rb
... | ... | @@ -31,7 +31,7 @@ class Task < ActiveRecord::Base |
31 | 31 | end |
32 | 32 | end |
33 | 33 | |
34 | - belongs_to :requestor, :class_name => 'Person', :foreign_key => :requestor_id | |
34 | + belongs_to :requestor, :class_name => 'Profile', :foreign_key => :requestor_id | |
35 | 35 | belongs_to :target, :foreign_key => :target_id, :polymorphic => true |
36 | 36 | |
37 | 37 | validates_uniqueness_of :code, :on => :create | ... | ... |
app/models/user.rb
... | ... | @@ -30,7 +30,7 @@ class User < ActiveRecord::Base |
30 | 30 | |
31 | 31 | after_create do |user| |
32 | 32 | user.person ||= Person.new |
33 | - user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id) | |
33 | + user.person.attributes = user.person_data.merge(:identifier => user.login, :user => user, :environment_id => user.environment_id) | |
34 | 34 | user.person.name ||= user.login |
35 | 35 | user.person.visible = false unless user.activated? |
36 | 36 | user.person.save! |
... | ... | @@ -73,6 +73,18 @@ class User < ActiveRecord::Base |
73 | 73 | :environment => user.environment.name, |
74 | 74 | :url => user.environment.top_url |
75 | 75 | end |
76 | + | |
77 | + def signup_welcome_email(user) | |
78 | + email_body = user.environment.signup_welcome_text_body.gsub('{user_name}', user.name) | |
79 | + email_subject = user.environment.signup_welcome_text_subject | |
80 | + | |
81 | + content_type 'text/html' | |
82 | + recipients user.email | |
83 | + | |
84 | + from "#{user.environment.name} <#{user.environment.contact_email}>" | |
85 | + subject email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject | |
86 | + body email_body | |
87 | + end | |
76 | 88 | end |
77 | 89 | |
78 | 90 | def signup! |
... | ... | @@ -88,13 +100,13 @@ class User < ActiveRecord::Base |
88 | 100 | attr_protected :activated_at |
89 | 101 | |
90 | 102 | # Virtual attribute for the unencrypted password |
91 | - attr_accessor :password | |
103 | + attr_accessor :password, :name | |
92 | 104 | |
93 | 105 | validates_presence_of :login, :email |
94 | 106 | validates_format_of :login, :with => Profile::IDENTIFIER_FORMAT, :if => (lambda {|user| !user.login.blank?}) |
95 | 107 | validates_presence_of :password, :if => :password_required? |
96 | - validates_presence_of :password_confirmation, :if => :password_required?, :if => (lambda {|user| !user.password.blank?}) | |
97 | - validates_length_of :password, :within => 4..40, :if => :password_required?, :if => (lambda {|user| !user.password.blank?}) | |
108 | + validates_presence_of :password_confirmation, :if => :password_required? | |
109 | + validates_length_of :password, :within => 4..40, :if => :password_required? | |
98 | 110 | validates_confirmation_of :password, :if => :password_required? |
99 | 111 | validates_length_of :login, :within => 2..40, :if => (lambda {|user| !user.login.blank?}) |
100 | 112 | validates_length_of :email, :within => 3..100, :if => (lambda {|user| !user.email.blank?}) |
... | ... | @@ -117,7 +129,17 @@ class User < ActiveRecord::Base |
117 | 129 | self.activated_at = Time.now.utc |
118 | 130 | self.activation_code = nil |
119 | 131 | self.person.visible = true |
120 | - self.person.save! && self.save! | |
132 | + begin | |
133 | + self.person.save! && self.save! | |
134 | + rescue Exception => exception | |
135 | + logger.error(exception.to_s) | |
136 | + false | |
137 | + else | |
138 | + if environment.enabled?('send_welcome_email_to_new_users') && environment.has_signup_welcome_text? | |
139 | + User::Mailer.delay.deliver_signup_welcome_email(self) | |
140 | + end | |
141 | + true | |
142 | + end | |
121 | 143 | end |
122 | 144 | |
123 | 145 | def activated? |
... | ... | @@ -228,7 +250,12 @@ class User < ActiveRecord::Base |
228 | 250 | end |
229 | 251 | |
230 | 252 | def name |
231 | - person ? person.name : login | |
253 | + name = (self[:name] || login) | |
254 | + person.nil? ? name : (person.name || name) | |
255 | + end | |
256 | + | |
257 | + def name= name | |
258 | + self[:name] = name | |
232 | 259 | end |
233 | 260 | |
234 | 261 | def enable_email! |
... | ... | @@ -274,6 +301,11 @@ class User < ActiveRecord::Base |
274 | 301 | 15 # in minutes |
275 | 302 | end |
276 | 303 | |
304 | + | |
305 | + def not_require_password! | |
306 | + @is_password_required = false | |
307 | + end | |
308 | + | |
277 | 309 | protected |
278 | 310 | # before filter |
279 | 311 | def encrypt_password |
... | ... | @@ -282,9 +314,13 @@ class User < ActiveRecord::Base |
282 | 314 | self.password_type ||= User.system_encryption_method.to_s |
283 | 315 | self.crypted_password = encrypt(password) |
284 | 316 | end |
285 | - | |
317 | + | |
286 | 318 | def password_required? |
287 | - crypted_password.blank? || !password.blank? | |
319 | + (crypted_password.blank? || !password.blank?) && is_password_required? | |
320 | + end | |
321 | + | |
322 | + def is_password_required? | |
323 | + @is_password_required.nil? ? true : @is_password_required | |
288 | 324 | end |
289 | 325 | |
290 | 326 | def make_activation_code | ... | ... |
app/sweepers/article_sweeper.rb
... | ... | @@ -10,17 +10,24 @@ class ArticleSweeper < ActiveRecord::Observer |
10 | 10 | expire_caches(article) |
11 | 11 | end |
12 | 12 | |
13 | + def before_update(article) | |
14 | + if article.parent_id_change | |
15 | + Article.find(article.parent_id_was).touch if article.parent_id_was | |
16 | + end | |
17 | + end | |
18 | + | |
13 | 19 | protected |
14 | 20 | |
15 | 21 | def expire_caches(article) |
16 | - article.hierarchy.each { |a| a.touch if a != article } | |
22 | + return if !article.environment | |
23 | + article.hierarchy(true).each { |a| a.touch if a != article } | |
17 | 24 | blocks = article.profile.blocks |
18 | 25 | blocks += article.profile.environment.blocks if article.profile.environment |
19 | 26 | blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}} |
20 | 27 | BlockSweeper.expire_blocks(blocks) |
21 | 28 | env = article.profile.environment |
22 | 29 | if env && (env.portal_community == article.profile) |
23 | - Noosfero.locales.keys.each do |locale| | |
30 | + article.environment.locales.keys.each do |locale| | |
24 | 31 | expire_fragment(env.portal_news_cache_key(locale)) |
25 | 32 | end |
26 | 33 | end | ... | ... |
app/sweepers/block_sweeper.rb
... | ... | @@ -7,10 +7,11 @@ class BlockSweeper < ActiveRecord::Observer |
7 | 7 | |
8 | 8 | # Expire block's all languages cache |
9 | 9 | def expire_block(block) |
10 | + return if !block.environment | |
10 | 11 | regex = '-[a-z]*$' |
11 | 12 | clean_ck = block.cache_key.gsub(/#{regex}/,'') |
12 | 13 | |
13 | - Noosfero.locales.keys.each do |locale| | |
14 | + block.environment.locales.keys.each do |locale| | |
14 | 15 | expire_timeout_fragment("#{clean_ck}-#{locale}") |
15 | 16 | end |
16 | 17 | end | ... | ... |
app/views/account/forgot_password.rhtml
1 | 1 | <h1><%= _('Forgot your password?') %></h1> |
2 | 2 | |
3 | -<%= error_messages_for :change_password %> | |
3 | +<%= error_messages_for :change_password, :header_message => _('Instructions to password recovery could not be sent'), :message => nil %> | |
4 | 4 | |
5 | 5 | <% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %> |
6 | 6 | ... | ... |
app/views/account/login.rhtml
... | ... | @@ -13,6 +13,8 @@ |
13 | 13 | |
14 | 14 | <%= f.password_field :password %> |
15 | 15 | |
16 | + <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }.join("") %> | |
17 | + | |
16 | 18 | <% button_bar do %> |
17 | 19 | <%= submit_button( 'login', _('Log in') )%> |
18 | 20 | <% if is_thickbox %> |
... | ... | @@ -23,8 +25,13 @@ |
23 | 25 | <% end %> |
24 | 26 | |
25 | 27 | <% button_bar do %> |
26 | - <%= button :add, _("New user"), :controller => 'account', :action => 'signup' %> | |
27 | - <%= button :help, _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> | |
28 | + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %> | |
29 | + <%= button :add, _("New user"), :controller => 'account', :action => 'signup' %> | |
30 | + <% end %> | |
31 | + | |
32 | + <% unless @plugins.dispatch(:allow_password_recovery).include?(false) %> | |
33 | + <%= button :help, _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> | |
34 | + <% end %> | |
28 | 35 | <% end %> |
29 | 36 | |
30 | 37 | </div><!-- end class="login-box" --> | ... | ... |
app/views/account/login_block.rhtml
... | ... | @@ -9,25 +9,30 @@ |
9 | 9 | @user ||= User.new |
10 | 10 | %> |
11 | 11 | |
12 | - <% labelled_form_for :user, @user, | |
13 | - :url => login_url do |f| %> | |
12 | + <% labelled_form_for :user, @user, :url => login_url do |f| %> | |
14 | 13 | |
15 | - <%= f.text_field :login, :onchange => 'this.value = convToValidLogin( this.value )' %> | |
14 | + <%= f.text_field :login, :onchange => 'this.value = convToValidLogin( this.value )' %> | |
16 | 15 | |
17 | - <%= f.password_field :password %> | |
16 | + <%= f.password_field :password %> | |
17 | + | |
18 | + <%= @plugins.dispatch(:login_extra_contents).collect { |content| instance_eval(&content) }.join("") %> | |
18 | 19 | |
19 | 20 | <% button_bar do %> |
20 | 21 | <%= submit_button( 'login', _('Log in') )%> |
21 | - <%= link_to content_tag( 'span', _('New user') ), | |
22 | - { :controller => 'account', :action => 'signup' }, | |
23 | - :class => 'button with-text icon-add' %> | |
22 | + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %> | |
23 | + <%= link_to content_tag( 'span', _('New user') ), | |
24 | + { :controller => 'account', :action => 'signup' }, | |
25 | + :class => 'button with-text icon-add' %> | |
26 | + <% end %> | |
24 | 27 | <% end %> |
25 | 28 | |
26 | 29 | <% end %> |
27 | 30 | |
28 | - <p class="forgot-passwd"> | |
29 | - <%= link_to _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> | |
30 | - </p> | |
31 | + <% unless @plugins.dispatch(:allow_password_recovery).include?(false) %> | |
32 | + <p class="forgot-passwd"> | |
33 | + <%= link_to _("I forgot my password!"), :controller => 'account', :action => 'forgot_password' %> | |
34 | + </p> | |
35 | + <% end %> | |
31 | 36 | |
32 | 37 | </div> |
33 | 38 | ... | ... |
... | ... | @@ -0,0 +1,7 @@ |
1 | +<div class='description'> | |
2 | + <%= _('This text will be sent to new users if the feature "Send welcome e-mail to new users" is enabled on environment.') %><br/><br/> | |
3 | + <%= _('Including %s on body, it will be replaced by the real name of the e-mail recipient.') % content_tag('code', '{user_name}') %> | |
4 | +</div> | |
5 | + | |
6 | +<%= labelled_form_field(_('Subject'), text_field(:environment, :signup_welcome_text_subject, :style => 'width:100%')) %> | |
7 | +<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_text_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %> | ... | ... |
app/views/admin_panel/_site_info.rhtml
1 | 1 | <%= required labelled_form_field(_('Site name'), text_field(:environment, :name)) %> |
2 | +<%= labelled_form_field(_('Contact email'), text_field(:environment, :contact_email)) %> | |
3 | +<% themes_options = Theme.system_themes.map {|theme| [theme.name, theme.id] }.sort %> | |
4 | +<%= labelled_form_field(_('Theme'), select(:environment, :theme, options_for_select(themes_options, environment.theme))) %> | |
2 | 5 | <%= required f.text_field(:reports_lower_bound, :size => 3) %> |
6 | +<%= labelled_form_field(_('Default language'), select(:environment, :default_language, environment.locales.invert, { :selected => environment.default_locale, :include_blank => true })) %> | |
7 | +<%= label_tag :languages, _('Available languages') %> | |
8 | +<br /> | |
9 | + | |
10 | +<% | |
11 | + fields = Noosfero.locales.map do |value, name| | |
12 | + labelled_check_box(name, "environment[languages][#{value}]", true, environment.available_locales.include?(value)) | |
13 | + end | |
14 | +%> | |
15 | +<%= balanced_table(fields)%> | |
16 | + | |
17 | +<br /> | |
3 | 18 | <%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => 'mceEditor') %> | ... | ... |
app/views/admin_panel/site_info.rhtml
... | ... | @@ -10,6 +10,8 @@ |
10 | 10 | :content => (render :partial => 'site_info', :locals => {:f => f})} %> |
11 | 11 | <% tabs << {:title => _('Terms of use'), :id => 'terms-of-use', |
12 | 12 | :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %> |
13 | + <% tabs << {:title => _('Signup welcome text'), :id => 'signup-welcome-text', | |
14 | + :content => (render :partial => 'signup_welcome_text', :locals => {:f => f})} %> | |
13 | 15 | <%= render_tabs(tabs) %> |
14 | 16 | <% button_bar do %> |
15 | 17 | <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %> | ... | ... |
app/views/blocks/profile_info_actions/community.rhtml
... | ... | @@ -32,7 +32,7 @@ |
32 | 32 | { :profile => profile.identifier, |
33 | 33 | :controller => 'contact', |
34 | 34 | :action => 'new' }, |
35 | - :class => 'button with-text icon-menu-mail' %> | |
35 | + {:class => 'button with-text icon-menu-mail', :title => _('Send an e-mail to the administrators')} %> | |
36 | 36 | </li> |
37 | 37 | <% end %> |
38 | 38 | ... | ... |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<% block_types.in_groups_of(2) do |block1, block2| %> | |
2 | + <div style='float: left; width: 48%; padding-top: 2px;'> | |
3 | + <%= labelled_radio_button(block1.description, :type, block1.name) %> | |
4 | + </div> | |
5 | + <% if block2 %> | |
6 | + <div style='float: left; width: 48%; padding-top: 2px;'> | |
7 | + <%= labelled_radio_button(block2.description, :type, block2.name) %> | |
8 | + </div> | |
9 | + <% end %> | |
10 | +<% end %> | ... | ... |
app/views/box_organizer/_highlights_block.rhtml
1 | 1 | <strong><%= _('Highlights') %></strong> |
2 | -<div id='edit-highlights-block'> | |
2 | +<div id='edit-highlights-block' style='width:450px'> | |
3 | 3 | <table id='highlights' class='noborder'> |
4 | 4 | <tr><th><%= _('Image') %></th><th><%= _('Address') %></th><th><%= _('Position') %></th><th><%= _('Title') %></th></tr> |
5 | 5 | <% for image in @block.images do %> | ... | ... |
app/views/box_organizer/_link_list_block.rhtml
1 | 1 | <strong><%= _('Links') %></strong> |
2 | -<div id='edit-link-list-block'> | |
2 | +<div id='edit-link-list-block' style='width:450px'> | |
3 | 3 | <table id='links' class='noborder'> |
4 | 4 | <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th></tr> |
5 | 5 | <% for link in @block.links do %> | ... | ... |
app/views/box_organizer/_raw_html_block.rhtml
app/views/box_organizer/add_block.rhtml
1 | -<% form_tag do %> | |
2 | - | |
3 | - <p><%= _('In what area do you want to put your new block?') %></p> | |
4 | - | |
5 | - <%# FIXME hardcoded stuff %> | |
6 | - <%= select_tag('box_id', options_for_select(@boxes.select { |item| item.position != 1 }.map {|item| [ _("Area %d") % item.position, item.id]})) %> | |
7 | - | |
8 | - <p><%= _('Select the type of block you want to add to your page.') %></p> | |
9 | - | |
10 | - <% @block_types.in_groups_of(2) do |block1, block2| %> | |
11 | - <div style='float: left; width: 48%; padding-top: 2px;'> | |
12 | - <%= radio_button_tag('type', block1.name) %> | |
13 | - <%= label_tag "type_#{block1.name.downcase}", block1.description %> | |
1 | +<div style='height:350px'> | |
2 | + <% form_tag do %> | |
3 | + | |
4 | + <p><%= _('In what area do you want to put your new block?') %></p> | |
5 | + | |
6 | + <% @boxes.each do |box| %> | |
7 | + <%= labelled_radio_button(_("Area %d") % box.position, :box_id, box.id, box.central?, { :class => 'box-position', 'data-position' => box.position }) %> | |
8 | + <% end %> | |
9 | + | |
10 | + <script type="text/javascript"> | |
11 | + (function ($) { | |
12 | + $(document).ready(function () { | |
13 | + $(".box-position").live('change', function () { | |
14 | + if ($(this).attr('data-position') == '1') { | |
15 | + $('#center-block-types').show(); | |
16 | + $('#side-block-types').hide(); | |
17 | + } else { | |
18 | + $('#center-block-types').hide(); | |
19 | + $('#side-block-types').show(); | |
20 | + }; | |
21 | + }); | |
22 | + })})(jQuery); | |
23 | + </script> | |
24 | + | |
25 | + <p><%= _('Select the type of block you want to add to your page.') %></p> | |
26 | + | |
27 | + <div id='center-block-types'> | |
28 | + <%= render :partial => 'block_types', :locals => { :block_types => @center_block_types } %> | |
14 | 29 | </div> |
15 | - <% if block2 %> | |
16 | - <div style='float: left; width: 48%; padding-top: 2px;'> | |
17 | - <%= radio_button_tag('type', block2.name) %> | |
18 | - <%= label_tag "type_#{block2.name.downcase}", block2.description %> | |
19 | - </div> | |
30 | + | |
31 | + <div id='side-block-types' style='display:none'> | |
32 | + <%= render :partial => 'block_types', :locals => { :block_types => @side_block_types } %> | |
33 | + </div> | |
34 | + | |
35 | + <br style='clear: both'/> | |
36 | + | |
37 | + <% button_bar do %> | |
38 | + <%= submit_button(:add, _("Add")) %> | |
39 | + <%= colorbox_close_button(_('Close')) %> | |
20 | 40 | <% end %> |
21 | - <% end %> | |
22 | - <br style='clear: both'/> | |
23 | - | |
24 | - <% button_bar do %> | |
25 | - <%= submit_button(:add, _("Add")) %> | |
26 | - <%= lightbox_close_button(_('Close')) %> | |
27 | - <% end %> | |
28 | 41 | |
29 | -<% end %> | |
42 | + <% end %> | |
43 | +</div> | ... | ... |
app/views/box_organizer/edit.rhtml
1 | -<h2><%= _('Editing block') %></h2> | |
1 | +<div style='width: 500px;'> | |
2 | + <h2><%= _('Editing block') %></h2> | |
2 | 3 | |
3 | -<% form_tag(:action => 'save', :id => @block.id) do %> | |
4 | + <% form_tag(:action => 'save', :id => @block.id) do %> | |
4 | 5 | |
5 | - <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %> | |
6 | + <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %> | |
6 | 7 | |
7 | - <%= render :partial => partial_for_class(@block.class) %> | |
8 | + <%= render :partial => partial_for_class(@block.class) %> | |
8 | 9 | |
9 | - <%= labelled_form_field _('Display this block:'), '' %> | |
10 | - <div style='margin-left: 10px'> | |
11 | - <%= radio_button(:block, :display, 'always') %> | |
12 | - <%= label_tag('block_display_always', _('In all pages')) %> | |
13 | - <br/> | |
14 | - <%= radio_button(:block, :display, 'home_page_only') %> | |
15 | - <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %> | |
16 | - <br/> | |
17 | - <%= radio_button(:block, :display, 'except_home_page') %> | |
18 | - <%= label_tag('block_display_except_home_page', _('In all pages, except in the homepage')) %> | |
19 | - <br/> | |
20 | - <%= radio_button(:block, :display, 'never') %> | |
21 | - <%= label_tag('block_display_never', _("Don't display")) %> | |
22 | - </div> | |
10 | + <%= labelled_form_field _('Display this block:'), '' %> | |
11 | + <div style='margin-left: 10px'> | |
12 | + <%= radio_button(:block, :display, 'always') %> | |
13 | + <%= label_tag('block_display_always', _('In all pages')) %> | |
14 | + <br/> | |
15 | + <%= radio_button(:block, :display, 'home_page_only') %> | |
16 | + <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %> | |
17 | + <br/> | |
18 | + <%= radio_button(:block, :display, 'except_home_page') %> | |
19 | + <%= label_tag('block_display_except_home_page', _('In all pages, except in the homepage')) %> | |
20 | + <br/> | |
21 | + <%= radio_button(:block, :display, 'never') %> | |
22 | + <%= label_tag('block_display_never', _("Don't display")) %> | |
23 | + </div> | |
23 | 24 | |
24 | - <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + Noosfero.locales.map {|key, value| [value, key]} )) %> | |
25 | + <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + environment.locales.map {|key, value| [value, key]} )) %> | |
25 | 26 | |
26 | - <% button_bar do %> | |
27 | - <%= submit_button(:save, _('Save')) %> | |
28 | - <%= lightbox_close_button(_('Cancel')) %> | |
29 | - <% end %> | |
27 | + <% button_bar do %> | |
28 | + <%= submit_button(:save, _('Save')) %> | |
29 | + <%= colorbox_close_button(_('Cancel')) %> | |
30 | + <% end %> | |
30 | 31 | |
31 | -<% end %> | |
32 | + <% end %> | |
33 | +</div> | ... | ... |
app/views/box_organizer/index.rhtml
1 | 1 | <h1><%= _('Editing sideboxes')%></h1> |
2 | 2 | |
3 | 3 | <% button_bar do %> |
4 | - <%= lightbox_button('add', _('Add a block'), { :action => 'add_block' }) %> | |
4 | + <%= colorbox_button('add', _('Add a block'), { :action => 'add_block' }) %> | |
5 | 5 | <%= button(:back, _('Back to control panel'), :controller => (profile.nil? ? 'admin_panel': 'profile_editor')) %> |
6 | 6 | <% end %> | ... | ... |
app/views/catalog/index.rhtml
... | ... | @@ -30,6 +30,9 @@ |
30 | 30 | <li class="product <%= status.join(' ') %>"> |
31 | 31 | <ul> |
32 | 32 | <li class="product-image-link"> |
33 | + <% if product.highlighted? %> | |
34 | + <%= link_to image_tag(themed_path('/images/star.png'), :class => 'star', :alt => _('Highlighted product')), product_path(product) %> | |
35 | + <% end %> | |
33 | 36 | <% if product.image %> |
34 | 37 | <div class="zoomable-image"> |
35 | 38 | <%= link_to_product product, :class => 'product-big', :style => "background-image: url(#{product.default_image(:big)})" %> | ... | ... |
app/views/cms/_blog.rhtml
... | ... | @@ -62,7 +62,7 @@ |
62 | 62 | |
63 | 63 | <% f.fields_for 'feed', @article.feed do |feed| %> |
64 | 64 | <%= labelled_form_field(_('Limit of posts in RSS Feed'), feed.select(:limit, [5, 10, 20, 50])) %> |
65 | - <%= labelled_form_field(_('Include in RSS Feed only posts from language:'), feed.select(:language, [[_('All'), nil ]] + Noosfero.locales.map { |k,v| [v, k]})) %> | |
65 | + <%= labelled_form_field(_('Include in RSS Feed only posts from language:'), feed.select(:language, [[_('All'), nil ]] + environment.locales.map { |k,v| [v, k]})) %> | |
66 | 66 | <% end %> |
67 | 67 | |
68 | 68 | <% f.fields_for 'external_feed_builder', @article.external_feed do |efeed| %> | ... | ... |
app/views/cms/_general_fields.html.erb
1 | +<%= select_profile_folder(_('Parent folder:'), 'article[parent_id]', profile, @article.parent_id) %> | |
1 | 2 | <%= labelled_form_field(_('License'), select(:article, :license_id, options_for_select_with_title([[_('None'), nil]] + profile.environment.licenses.map {|license| [license.name, license.id]}, @article.license ? @article.license.id : nil))) %> | ... | ... |
app/views/cms/_rss_feed.rhtml
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | |
7 | 7 | <%= required labelled_form_field(_('Limit of articles'), text_field(:article, :limit)) %> |
8 | 8 | |
9 | -<%= labelled_form_field(_('Include in RSS Feed only posts from language:'), f.select(:language, [[_('All'), nil ]] + Noosfero.locales.map { |k,v| [v, k]})) %> | |
9 | +<%= labelled_form_field(_('Include in RSS Feed only posts from language:'), f.select(:language, [[_('All'), nil ]] + environment.locales.map { |k,v| [v, k]})) %> | |
10 | 10 | |
11 | 11 | <%= labelled_form_field(_('Use as item description:'), select(:article, :feed_item_description, [ [ _('Article abstract'), 'abstract'], [ _('Article body'), 'body']])) %> |
12 | 12 | ... | ... |
app/views/cms/_text_editor_sidebar.rhtml
... | ... | @@ -9,8 +9,7 @@ |
9 | 9 | <div id='media-upload-form'> |
10 | 10 | <% form_tag({ :action => 'media_upload' }, :multipart => true) do %> |
11 | 11 | <div class='formfield'> |
12 | - <%# TODO duplicated from partial upload_file_form %> | |
13 | - <%= labelled_form_field(_('Choose folder to upload files:'), select_tag('parent_id', options_for_select([[profile.identifier, '']] + profile.folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] }))) %> | |
12 | + <%= select_profile_folder(_('Choose folder to upload files:'), :parent_id, profile) %> | |
14 | 13 | </div> |
15 | 14 | <p><%= file_field_tag('file1') %></p> |
16 | 15 | <p><%= file_field_tag('file2') %></p> | ... | ... |
app/views/cms/_upload_file_form.rhtml
1 | 1 | <% if @parent %> |
2 | 2 | <%= hidden_field_tag('parent_id', @parent.id) %> |
3 | 3 | <% else %> |
4 | - <%= labelled_form_field(_('Choose folder to upload files:'), select_tag('parent_id', options_for_select([[profile.identifier, '']] + @folders.collect {|f| [ profile.identifier + '/' + f.full_name, f.id ] }))) %> | |
4 | + <%= select_profile_folder(_('Choose folder to upload files:'), :parent_id, profile) %> | |
5 | 5 | <% end %> |
6 | 6 | |
7 | 7 | <div id='uploaded_files'> | ... | ... |
app/views/cms/_uploaded_file.rhtml
1 | 1 | <%= labelled_form_field(_('Title'), text_field(:article, :title, :maxlength => 60)) %> |
2 | + | |
3 | +<%= render :partial => 'general_fields' %> | |
4 | + | |
2 | 5 | <%= labelled_form_field(_('Description'), text_area(:article, :abstract, :rows => 3, :cols => 64)) %> |
3 | 6 | <% if @article.image? %> |
4 | 7 | <%= f.text_field(:external_link, :size => 64) %> | ... | ... |
app/views/contact/new.rhtml
1 | -<h1><%= _('Send an e-mail to %s') % profile.name %></h1> | |
1 | +<% if profile.person? %> | |
2 | + <h1><%= _('Send an e-mail to %s') % profile.name %></h1> | |
3 | +<% else %> | |
4 | + <h1><%= _('Send an e-mail to administrators') %></h1> | |
2 | 5 | |
3 | -<%= error_messages_for 'contact' %> | |
6 | + <div class='tooltip'><%= _("The e-mail will be sent to the administrators of '%s'") % profile.name %></div> | |
7 | +<% end %> | |
4 | 8 | |
9 | +<%= error_messages_for 'contact' %> | |
5 | 10 | |
6 | 11 | <% labelled_form_for :contact, @contact do |f| %> |
7 | 12 | <%= hidden_field_tag(:confirm, 'false') %> | ... | ... |
app/views/features/index.rhtml
... | ... | @@ -26,17 +26,12 @@ Check all the features you want to enable for your environment, uncheck all the |
26 | 26 | |
27 | 27 | <h2><%= _('Configure features') %></h2> |
28 | 28 | |
29 | -<table> | |
30 | - <tr> | |
31 | - <th><%= _('Option') %></th> | |
32 | - <th><%= _('Choice') %></th> | |
33 | - </tr> | |
34 | - <tr> | |
35 | - <td><%= _('Organization Approval Method') %></td> | |
36 | - <td><%= select_organization_approval_method('environment', 'organization_approval_method') %></td> | |
37 | - </tr> | |
38 | -</table> | |
39 | - | |
29 | +<h3><%= _('Page to redirect after login') %></h3> | |
30 | + <%= select 'environment', 'redirection_after_login', Environment.login_redirection_options.map{|key,value|[value,key]} %> | |
31 | +<hr/> | |
32 | +<h3><%= _('Organization Approval Method') %></h3> | |
33 | + <%= select_organization_approval_method('environment', 'organization_approval_method') %> | |
34 | +<hr/> | |
40 | 35 | |
41 | 36 | <div> |
42 | 37 | <% button_bar do %> | ... | ... |
app/views/layouts/_javascript.rhtml
... | ... | @@ -2,7 +2,8 @@ |
2 | 2 | 'jquery.noconflict.js', 'jquery.cycle.all.min.js', 'thickbox.js', 'lightbox', 'colorbox', |
3 | 3 | 'jquery-ui-1.8.2.custom.min', 'jquery.scrollTo', 'jquery.form.js', 'jquery-validation/jquery.validate', |
4 | 4 | 'jquery.cookie', 'jquery.ba-bbq.min.js', 'reflection', 'jquery.tokeninput', |
5 | -'add-and-join', 'report-abuse', 'catalog', 'manage-products', :cache => 'cache-general' %> | |
5 | +'add-and-join', 'report-abuse', 'catalog', 'manage-products', | |
6 | +'jquery-ui-timepicker-addon', :cache => 'cache-general' %> | |
6 | 7 | |
7 | 8 | <% language = FastGettext.locale %> |
8 | 9 | <% %w{messages methods}.each do |type| %> | ... | ... |
app/views/layouts/application-ng.rhtml
... | ... | @@ -56,10 +56,18 @@ |
56 | 56 | <%= usermenu_logged_in %> |
57 | 57 | </span> |
58 | 58 | <span class='not-logged-in' style='display: none'> |
59 | - <%= _("<span class='login'>%s</span> <span class='or'>or</span> <span class='signup'>%s</span>") % [thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login'), link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup') ] %> | |
59 | + | |
60 | + <%= _("<span class='login'>%s</span>") % thickbox_inline_popup_link('<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>', login_url, 'inlineLoginBox', :id => 'link_login') %> | |
61 | + <%= @plugins.dispatch(:alternative_authentication_link).collect { |content| instance_eval(&content) }.join("") %> | |
62 | + | |
60 | 63 | <div id='inlineLoginBox' style='display: none;'> |
61 | 64 | <%= render :file => 'account/login', :locals => { :is_thickbox => true } %> |
62 | 65 | </div> |
66 | + | |
67 | + <% unless @plugins.dispatch(:allow_user_registration).include?(false) %> | |
68 | + <%= _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to('<strong>' + _('Sign up') + '</strong>', :controller => 'account', :action => 'signup')%> | |
69 | + <% end %> | |
70 | + | |
63 | 71 | </span> |
64 | 72 | <form action="/search" class="search_form" method="get" class="clean"> |
65 | 73 | <input name="query" size="15" title="<%=_('Search...')%>" onfocus="this.form.className='focused';" onblur="this.form.className=''" /> | ... | ... |
app/views/layouts/application.rhtml
app/views/profile/_common.rhtml
1 | - | |
2 | -<script type="text/javascript"> | |
3 | - jQuery( function() { | |
4 | - var parent_selector = '.profile-wall-description, .profile-activity-description, .profile-network-description'; | |
5 | - var child_selector = '.icon-delete, .icon-reply'; | |
6 | - jQuery(parent_selector).live('mouseover', function () { jQuery(this).find(child_selector).css('visibility', 'visible'); }); | |
7 | - jQuery(parent_selector).live('mouseout', function () { jQuery(this).find(child_selector).css('visibility', 'hidden'); }); | |
8 | - }); | |
9 | -</script> | |
10 | - | |
11 | 1 | <% unless @action %> |
12 | 2 | <% cache_timeout(profile.cache_key + '-profile-general-info', 4.hours) do %> |
13 | 3 | <tr> | ... | ... |
app/views/profile/_person_profile.rhtml
... | ... | @@ -13,31 +13,16 @@ |
13 | 13 | <td><%= show_date(profile.created_at) %></td> |
14 | 14 | </tr> |
15 | 15 | |
16 | - <% if profile == user || profile.friends.include?(user) %> | |
17 | - <tr> | |
18 | - <th colspan='2'><%= _('Contact')%></th> | |
19 | - </tr> | |
20 | - <%= display_field(_('Address:'), profile, :address) %> | |
21 | - <%= display_field(_('ZIP code:'), profile, :zip_code) %> | |
22 | - <%= display_field(_('Contact phone:'), profile, :contact_phone) %> | |
23 | - <%= display_field(_('e-Mail:'), profile, :email, true) { |email| link_to_email(email) } %> | |
24 | - <% end %> | |
16 | + <%= display_contact profile %> | |
25 | 17 | |
26 | 18 | <% cache_timeout(profile.relationships_cache_key, 4.hours) do %> |
27 | - <% if !(profile.organization.blank? && profile.organization_website.blank?) && (profile.active_fields.include?('organization') || profile.active_fields.include?('organization_website')) %> | |
28 | - <tr> | |
29 | - <th colspan='2'><%= _('Work')%></th> | |
30 | - </tr> | |
31 | - <% end %> | |
32 | - <%= display_field(_('Organization:'), profile, :organization) %> | |
33 | - <%= display_field(_('Organization website:'), profile, :organization_website) { |url| link_to(url, url) }%> | |
34 | - | |
19 | + <%= display_work_info profile %> | |
35 | 20 | |
36 | 21 | <% if !environment.enabled?('disable_asset_enterprises') && !profile.enterprises.empty? %> |
37 | 22 | <tr> |
38 | 23 | <th colspan='2'><%= __('Enterprises') %></th> |
39 | 24 | </tr> |
40 | - <% profile.enterprises.each do |item| %> | |
25 | + <% profile.enterprises.includes(:environment,:domains, :preferred_domain).each do |item| %> | |
41 | 26 | <tr> |
42 | 27 | <td></td> |
43 | 28 | <td><%= button 'menu-enterprise', item.name, item.url %></td> |
... | ... | @@ -59,6 +44,6 @@ |
59 | 44 | |
60 | 45 | <%= render :partial => 'common' %> |
61 | 46 | |
62 | - </table> | |
63 | -<% end %> | |
47 | + <% end %> | |
48 | +</table> | |
64 | 49 | ... | ... |
app/views/profile/members.rhtml
... | ... | @@ -16,8 +16,13 @@ |
16 | 16 | |
17 | 17 | <% button_bar do %> |
18 | 18 | <%= button :back, _('Go back'), { :controller => 'profile' } %> |
19 | - <% if profile.community? and user and user.has_permission?(:invite_members, profile) %> | |
20 | - <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %> | |
19 | + <% if profile.community? and user %> | |
20 | + <% if user.has_permission?(:invite_members, profile) %> | |
21 | + <%= button :search, _('Invite your friends to join %s') % profile.name, :controller => 'invite', :action => 'select_address_book' %> | |
22 | + <% end %> | |
23 | + <% if user.has_permission?(:send_mail_to_members, profile) %> | |
24 | + <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> | |
25 | + <% end %> | |
21 | 26 | <% end %> |
22 | 27 | <% end %> |
23 | 28 | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +<h1><%= h profile.short_name(50) %></h1> | |
2 | + | |
3 | +<h2><%= _('Send e-mail to members') %></h2> | |
4 | + | |
5 | +<%= error_messages_for :mailing %> | |
6 | + | |
7 | +<%= render :file => 'shared/tiny_mce' %> | |
8 | + | |
9 | +<% form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %> | |
10 | + <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %> | |
11 | + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %> | |
12 | + <%= submit_button(:send, _('Send')) %> | |
13 | + <%= button :cancel, _('Cancel e-mail'), :back %> | |
14 | +<% end %> | ... | ... |
app/views/profile_editor/_person.rhtml
... | ... | @@ -2,9 +2,19 @@ |
2 | 2 | |
3 | 3 | <%= required_fields_message %> |
4 | 4 | |
5 | - <%= required f.text_field(:name) %> | |
5 | + <div class="field-with-privacy-selector"> | |
6 | + <%= required f.text_field(:name) %> | |
7 | + <div class="field-privacy-selector"> | |
8 | + <%= unchangeable_privacy_field @profile %> | |
9 | + </div> | |
10 | + </div> | |
6 | 11 | |
7 | - <%= required f.text_field(:email) %> | |
12 | + <div class="field-with-privacy-selector"> | |
13 | + <%= required f.text_field(:email) %> | |
14 | + <div class="field-privacy-selector"> | |
15 | + <%= profile_field_privacy_selector @profile, 'email' %> | |
16 | + </div> | |
17 | + </div> | |
8 | 18 | |
9 | 19 | <%= @plugins.dispatch(:profile_info_extra_contents).collect { |content| instance_eval(&content) }.join("") %> |
10 | 20 | ... | ... |
app/views/profile_editor/_person_form.rhtml
... | ... | @@ -61,11 +61,3 @@ |
61 | 61 | <%= optional_field(@person, 'professional_activity', f.text_field(:professional_activity, :rel => _('Professional activity'))) %> |
62 | 62 | <%= optional_field(@person, 'organization', f.text_field(:organization, :rel => _('Organization'))) %> |
63 | 63 | <%= optional_field(@person, 'organization_website', f.text_field(:organization_website, :rel => _('Organization website'))) %> |
64 | - | |
65 | -<% optional_field(@person, 'image') do %> | |
66 | - <div id="profile_choose_picture"> | |
67 | - <% f.fields_for :image_builder, @person.image do |i| %> | |
68 | - <%= file_field_or_thumbnail(_('Image:'), @person.image, i) %><span class="person_image_maxsize"><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %></span> | |
69 | - <% end %> | |
70 | - </div> | |
71 | -<% end %> | ... | ... |
app/views/profile_editor/edit.rhtml
... | ... | @@ -12,73 +12,37 @@ |
12 | 12 | |
13 | 13 | <%= render :partial => partial_for_class(@profile.class), :locals => { :f => f } %> |
14 | 14 | |
15 | - <% unless @profile.person? && @environment.active_person_fields.include?('image') %> | |
16 | - <div id="profile_change_picture"> | |
15 | + <div id="profile_change_picture_title"> | |
17 | 16 | <h2><%= _('Change picture') %></h2> |
17 | + <span><%= unchangeable_privacy_field @profile %></span> | |
18 | + </div> | |
19 | + <div id="profile_change_picture"> | |
18 | 20 | <% f.fields_for :image_builder, @profile.image do |i| %> |
19 | 21 | <%= file_field_or_thumbnail(_('Image:'), @profile.image, i) %><%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %> |
20 | 22 | <% end %> |
21 | 23 | </div> |
22 | - <% end %> | |
23 | 24 | |
24 | 25 | <h2><%= _('Privacy options') %></h2> |
25 | 26 | |
26 | 27 | <% if profile.person? %> |
27 | - <table> | |
28 | - <tr> | |
29 | - <th style='text-align: right;'> | |
30 | - <%= _('This profile is:') %> | |
31 | - </th> | |
32 | - <th> | |
33 | - <%= radio_button 'profile_data', 'public_profile', 'true' %> | |
34 | - <label for="profile_data_public_profile_true"><u><%= _('Public') %></u></label> | |
35 | - </th> | |
36 | - <th style='padding: 2px 10px 2px 2px;'> | |
37 | - <%= radio_button 'profile_data', 'public_profile', 'false' %> | |
38 | - <label for="profile_data_public_profile_false"><u><%= _('Private') %></u></label> | |
39 | - </th> | |
40 | - </tr> | |
41 | - <tr> | |
42 | - <td> <%= _('Activate Intranet access (restricted area only for me)') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td> | |
43 | - </tr> | |
44 | - <tr> | |
45 | - <td> <%= _('Include my contact in directory of people') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td> | |
46 | - </tr> | |
47 | - <tr> | |
48 | - <td> <%= _('Show my contents to all internet users') %> </td><td><%= _('Yes') %></td><td><%= _('No') %></td> | |
49 | - </tr> | |
50 | - <tr> | |
51 | - <td> <%= _('Show my contents to my friends (person)') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td> | |
52 | - </tr> | |
53 | - </table> | |
28 | + <div> | |
29 | + <%= labelled_radio_button _('Public — show my contents to all internet users'), 'profile_data[public_profile]', true, @profile.public_profile? %> | |
30 | + </div> | |
31 | + <div> | |
32 | + <%= labelled_radio_button _('Private — show my contents only to friends'), 'profile_data[public_profile]', false, !@profile.public_profile? %> | |
33 | + </div> | |
54 | 34 | <% else %> |
55 | - <table> | |
56 | - <tr> | |
57 | - <th style='text-align: right;'> | |
58 | - <%= _('This profile is:') %> | |
59 | - </th> | |
60 | - <th> | |
61 | - <%= radio_button 'profile_data', 'public_profile', 'true' %> | |
62 | - <label for="profile_data_public_profile_true"><u><%= _('Public') %></u></label> | |
63 | - </th> | |
64 | - <th style='padding: 2px 10px 2px 2px;'> | |
65 | - <%= radio_button 'profile_data', 'public_profile', 'false' %> | |
66 | - <label for="profile_data_public_profile_false"><u><%= _('Private') %></u></label> | |
67 | - </th> | |
68 | - </tr> | |
69 | - <tr> | |
70 | - <td> <%= _('Activate Intranet access (restricted area only for members)') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td> | |
71 | - </tr> | |
72 | - <tr> | |
73 | - <td> <%= _('Include this group directory of groups') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td> | |
74 | - </tr> | |
75 | - <tr> | |
76 | - <td> <%= _('Show content of this group to all internet users') %> </td><td><%= _('Yes') %></td><td><%= _('No') %></td> | |
77 | - </tr> | |
78 | - <tr> | |
79 | - <td> <%= _('Show content of this group to members') %> </td><td><%= _('Yes') %></td><td><%= _('Yes') %></td> | |
80 | - </tr> | |
81 | - </table> | |
35 | + <div> | |
36 | + <%= labelled_radio_button _('Public — show content of this group to all internet users'), 'profile_data[public_profile]', true, @profile.public_profile? %> | |
37 | + </div> | |
38 | + <div> | |
39 | + <%= labelled_radio_button _('Private — show content of this group only to members'), 'profile_data[public_profile]', false, !@profile.public_profile? %> | |
40 | + </div> | |
41 | + <% end %> | |
42 | + | |
43 | + <% if environment.enabled?('allow_change_of_redirection_after_login') %> | |
44 | + <h2><%= _('Page to redirect after login') %></h2> | |
45 | + <%= select 'profile_data', 'redirection_after_login', Environment.login_redirection_options.map{|key,value|[value,key]}, { :selected => @profile.preferred_login_redirection} %> | |
82 | 46 | <% end %> |
83 | 47 | |
84 | 48 | <h2><%= _('Translations') %></h2> | ... | ... |
app/views/profile_members/_index_buttons.rhtml
... | ... | @@ -4,7 +4,9 @@ |
4 | 4 | <% if profile.community? and user.has_permission?(:invite_members, profile) %> |
5 | 5 | <%= button :search, _('Invite your friends to join %s') % profile.short_name, :controller => 'invite', :action => 'select_address_book' %> |
6 | 6 | <% end %> |
7 | - <%= button :send, _('Send e-mail to members'), :action => 'send_mail' %> | |
7 | + <% if profile.community? and user.has_permission?(:send_mail_to_members, profile) %> | |
8 | + <%= button :send, _('Send e-mail to members'), :controller => 'profile', :action => 'send_mail' %> | |
9 | + <% end %> | |
8 | 10 | <% @plugins.dispatch(:manage_members_extra_buttons).each do |plugin_button| %> |
9 | 11 | <%= button plugin_button[:icon], plugin_button[:title], plugin_button[:url] %> |
10 | 12 | <% end %> | ... | ... |
app/views/profile_members/send_mail.rhtml
... | ... | @@ -1,14 +0,0 @@ |
1 | -<h1><%= h profile.short_name(50) %></h1> | |
2 | - | |
3 | -<h2><%= _('Send e-mail to members') %></h2> | |
4 | - | |
5 | -<%= error_messages_for :mailing %> | |
6 | - | |
7 | -<%= render :file => 'shared/tiny_mce' %> | |
8 | - | |
9 | -<% form_for :mailing, :url => {:action => 'send_mail'}, :html => {:id => 'mailing-form'} do |f| %> | |
10 | - <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %> | |
11 | - <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %> | |
12 | - <%= submit_button(:send, _('Send')) %> | |
13 | - <%= button :cancel, _('Cancel e-mail'), :action => 'index' %> | |
14 | -<% end %> |
app/views/search/_product.rhtml
1 | 1 | <% extra_content = @plugins.dispatch(:asset_product_extras, product, product.enterprise).collect { |content| instance_eval(&content) } %> |
2 | 2 | <% extra_properties = @plugins.dispatch(:asset_product_properties, product)%> |
3 | 3 | |
4 | -<li class="search-product-item"> | |
4 | +<li class="search-product-item <%= 'highlighted' if product.highlighted? %>"> | |
5 | 5 | |
6 | 6 | <div class="search-product-item-first-column"> |
7 | 7 | <%= render :partial => 'search/image', :object => product %> | ... | ... |
app/views/tasks/_approve_article_accept_details.rhtml
1 | 1 | <%= render :file => 'shared/tiny_mce' %> |
2 | 2 | |
3 | 3 | <%= labelled_form_field(_('Name for publishing'), f.text_field(:name)) %> |
4 | -<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task]", 'article_parent_id', task.target) %> | |
4 | +<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article_parent_id]", task.target) %> | |
5 | 5 | <%= labelled_form_field(_('Highlight this article'), f.check_box(:highlighted)) %> |
6 | 6 | |
7 | 7 | <% tiny = task.article && task.article.tiny_mce? ? {:tiny_mce => true} : {} %> | ... | ... |
app/views/tasks/_suggest_article_accept_details.rhtml
... | ... | @@ -6,7 +6,7 @@ |
6 | 6 | <%= labelled_form_field(_('Source'), f.text_field(:source_name)) %> |
7 | 7 | <%= labelled_form_field(_("Source URL"), f.text_field(:source)) %> |
8 | 8 | |
9 | -<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task]", 'article_parent_id', task.target) %> | |
9 | +<%= select_profile_folder(_('Select the folder where the article must be published'), "tasks[#{task.id}][task][article_parent_id]", task.target) %> | |
10 | 10 | <%= labelled_form_field(_('Highlight this article'), f.check_box(:highlighted)) %> |
11 | 11 | |
12 | 12 | <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :f => f, :abstract_method => 'article_abstract', :body_method => 'article_body', :lead_id => task.id} %> | ... | ... |
app/views/tasks/_task.rhtml
... | ... | @@ -50,13 +50,13 @@ |
50 | 50 | <% fields_for "tasks[#{task.id}][task]", task do |f| %> |
51 | 51 | <% if task.accept_details %> |
52 | 52 | <div id="on-accept-information-<%=task.id%>" style="display: none"> |
53 | - <%= render :partial => partial_for_task_class(task.class, :accept_details), :locals => {:task => task, :f => f} %> | |
53 | + <%= render :partial => partial_for_class(task.class, :accept_details), :locals => {:task => task, :f => f} %> | |
54 | 54 | </div> |
55 | 55 | <% end %> |
56 | 56 | |
57 | 57 | <% if task.reject_details %> |
58 | 58 | <div id="on-reject-information-<%=task.id%>" style="display: none"> |
59 | - <%= render :partial => partial_for_task_class(task.class, :reject_details), :locals => {:task => task, :f => f} %> | |
59 | + <%= render :partial => partial_for_class(task.class, :reject_details), :locals => {:task => task, :f => f} %> | |
60 | 60 | </div> |
61 | 61 | <% end %> |
62 | 62 | <% end %> | ... | ... |
config/routes.rb
... | ... | @@ -19,16 +19,17 @@ ActionController::Routing::Routes.draw do |map| |
19 | 19 | |
20 | 20 | # -- just remember to delete public/index.html. |
21 | 21 | # You can have the root of your site routed by hooking up '' |
22 | + map.root :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } | |
22 | 23 | map.connect '', :controller => "home", :conditions => { :if => lambda { |env| !Domain.hosting_profile_at(env[:host]) } } |
23 | 24 | map.home 'site/:action', :controller => 'home' |
24 | 25 | |
25 | - map.connect 'images/*stuff', :controller => 'not_found', :action => 'index' | |
26 | - map.connect 'stylesheets/*stuff', :controller => 'not_found', :action => 'index' | |
27 | - map.connect 'designs/*stuff', :controller => 'not_found', :action => 'index' | |
28 | - map.connect 'articles/*stuff', :controller => 'not_found', :action => 'index' | |
29 | - map.connect 'javascripts/*stuff', :controller => 'not_found', :action => 'index' | |
30 | - map.connect 'thumbnails/*stuff', :controller => 'not_found', :action => 'index' | |
31 | - map.connect 'user_themes/*stuff', :controller => 'not_found', :action => 'index' | |
26 | + map.connect 'images/*stuff', :controller => 'not_found', :action => 'nothing' | |
27 | + map.connect 'stylesheets/*stuff', :controller => 'not_found', :action => 'nothing' | |
28 | + map.connect 'designs/*stuff', :controller => 'not_found', :action => 'nothing' | |
29 | + map.connect 'articles/*stuff', :controller => 'not_found', :action => 'nothing' | |
30 | + map.connect 'javascripts/*stuff', :controller => 'not_found', :action => 'nothing' | |
31 | + map.connect 'thumbnails/*stuff', :controller => 'not_found', :action => 'nothing' | |
32 | + map.connect 'user_themes/*stuff', :controller => 'not_found', :action => 'nothing' | |
32 | 33 | |
33 | 34 | # online documentation |
34 | 35 | map.doc 'doc', :controller => 'doc', :action => 'index' | ... | ... |
db/migrate/20120823215007_add_languages_and_default_language_to_environment.rb
0 → 100644
... | ... | @@ -0,0 +1,11 @@ |
1 | +class AddLanguagesAndDefaultLanguageToEnvironment < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + add_column :environments, :languages, :string | |
4 | + add_column :environments, :default_language, :string | |
5 | + end | |
6 | + | |
7 | + def self.down | |
8 | + remove_column :environments, :languages | |
9 | + remove_column :environments, :default_language | |
10 | + end | |
11 | +end | ... | ... |
db/migrate/20120824165019_add_permission_for_send_mail_to_members_to_admin_and_moderator_roles.rb
0 → 100644
... | ... | @@ -0,0 +1,23 @@ |
1 | +class AddPermissionForSendMailToMembersToAdminAndModeratorRoles < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + Environment.all.map(&:id).each do |id| | |
4 | + role = Profile::Roles.admin(id) | |
5 | + role.permissions += ['send_mail_to_members'] | |
6 | + role.save! | |
7 | + role = Profile::Roles.moderator(id) | |
8 | + role.permissions += ['send_mail_to_members'] | |
9 | + role.save! | |
10 | + end | |
11 | + end | |
12 | + | |
13 | + def self.down | |
14 | + Environment.all.map(&:id).each do |id| | |
15 | + role = Profile::Roles.admin(id) | |
16 | + role.permissions -= ['send_mail_to_members'] | |
17 | + role.save! | |
18 | + role = Profile::Roles.moderator(id) | |
19 | + role.permissions -= ['send_mail_to_members'] | |
20 | + role.save! | |
21 | + end | |
22 | + end | |
23 | +end | ... | ... |
db/migrate/20120824183534_add_redirection_after_login_to_environment.rb
0 → 100644
... | ... | @@ -0,0 +1,9 @@ |
1 | +class AddRedirectionAfterLoginToEnvironment < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + add_column :environments, :redirection_after_login, :string, :default => 'keep_on_same_page' | |
4 | + end | |
5 | + | |
6 | + def self.down | |
7 | + remove_column :environments, :redirection_after_login | |
8 | + end | |
9 | +end | ... | ... |
db/migrate/20120824184046_add_redirection_after_login_to_profiles.rb
0 → 100644
db/schema.rb
... | ... | @@ -9,7 +9,7 @@ |
9 | 9 | # |
10 | 10 | # It's strongly recommended to check this file into your version control system. |
11 | 11 | |
12 | -ActiveRecord::Schema.define(:version => 20120825185219) do | |
12 | +ActiveRecord::Schema.define(:version => 20121008185303) do | |
13 | 13 | |
14 | 14 | create_table "abuse_reports", :force => true do |t| |
15 | 15 | t.integer "reporter_id" |
... | ... | @@ -261,6 +261,10 @@ ActiveRecord::Schema.define(:version => 20120825185219) do |
261 | 261 | t.datetime "created_at" |
262 | 262 | t.datetime "updated_at" |
263 | 263 | t.integer "reports_lower_bound", :default => 0, :null => false |
264 | + t.string "redirection_after_login", :default => "keep_on_same_page" | |
265 | + t.text "signup_welcome_text" | |
266 | + t.string "languages" | |
267 | + t.string "default_language" | |
264 | 268 | end |
265 | 269 | |
266 | 270 | create_table "external_feeds", :force => true do |t| |
... | ... | @@ -438,6 +442,7 @@ ActiveRecord::Schema.define(:version => 20120825185219) do |
438 | 442 | t.string "national_region_code" |
439 | 443 | t.boolean "is_template", :default => false |
440 | 444 | t.integer "template_id" |
445 | + t.string "redirection_after_login" | |
441 | 446 | end |
442 | 447 | |
443 | 448 | add_index "profiles", ["environment_id"], :name => "index_profiles_on_environment_id" | ... | ... |
debian/changelog
... | ... | @@ -4,6 +4,12 @@ noosfero (0.39.0~1) UNRELEASED; urgency=low |
4 | 4 | |
5 | 5 | -- Antonio Terceiro <terceiro@debian.org> Thu, 30 Aug 2012 14:55:10 -0300 |
6 | 6 | |
7 | +noosfero (0.38.3) unstable; urgency=low | |
8 | + | |
9 | + * Bugfixes release | |
10 | + | |
11 | + -- Daniela Soares Feitosa <daniela@colivre.coop.br> Wed, 07 Nov 2012 20:25:51 -0200 | |
12 | + | |
7 | 13 | noosfero (0.38.2) unstable; urgency=low |
8 | 14 | |
9 | 15 | * Bugfixes release | ... | ... |
features/login.feature
... | ... | @@ -9,7 +9,8 @@ Feature: login |
9 | 9 | | joaosilva | Joao Silva | |
10 | 10 | |
11 | 11 | Scenario: login from portal homepage |
12 | - Given I am not logged in | |
12 | + Given feature "allow_change_of_redirection_after_login" is disabled on environment | |
13 | + And I am not logged in | |
13 | 14 | And I go to the homepage |
14 | 15 | And I fill in the following: |
15 | 16 | | Username | joaosilva | |
... | ... | @@ -19,7 +20,8 @@ Feature: login |
19 | 20 | And I should be logged in as "joaosilva" |
20 | 21 | |
21 | 22 | Scenario: login from some profile page |
22 | - Given I am not logged in | |
23 | + Given feature "allow_change_of_redirection_after_login" is disabled on environment | |
24 | + And I am not logged in | |
23 | 25 | And the following users |
24 | 26 | | login | name | |
25 | 27 | | mariasilva | Maria Silva | |
... | ... | @@ -35,7 +37,8 @@ Feature: login |
35 | 37 | Then I should be on Maria Silva's homepage |
36 | 38 | |
37 | 39 | Scenario: view my control panel |
38 | - Given I am not logged in | |
40 | + Given feature "allow_change_of_redirection_after_login" is disabled on environment | |
41 | + And I am not logged in | |
39 | 42 | And I go to Joao Silva's control panel |
40 | 43 | And I should be on login page |
41 | 44 | And I fill in the following: |
... | ... | @@ -48,3 +51,146 @@ Feature: login |
48 | 51 | Given I am logged in as "joaosilva" |
49 | 52 | And I go to login page |
50 | 53 | Then I should be on Joao Silva's control panel |
54 | + | |
55 | + Scenario: stay on the same page after login if this is the environment default | |
56 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
57 | + And I am not logged in | |
58 | + And the environment is configured to stay on the same page after login | |
59 | + And the following users | |
60 | + | login | name | | |
61 | + | mariasilva | Maria Silva | | |
62 | + And the following articles | |
63 | + | owner | name | homepage | | |
64 | + | mariasilva | my home page | true | | |
65 | + And I go to Maria Silva's homepage | |
66 | + And I follow "Login" | |
67 | + And I fill in the following: | |
68 | + | Username | joaosilva | | |
69 | + | Password | 123456 | | |
70 | + When I press "Log in" | |
71 | + Then I should be on Maria Silva's homepage | |
72 | + | |
73 | + Scenario: go to site homepage if this is the environment default | |
74 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
75 | + And I am not logged in | |
76 | + And the environment is configured to redirect to site homepage after login | |
77 | + And I go to Joao Silva's homepage | |
78 | + And I follow "Login" | |
79 | + And I fill in the following: | |
80 | + | Username | joaosilva | | |
81 | + | Password | 123456 | | |
82 | + When I press "Log in" | |
83 | + Then I should be on the homepage | |
84 | + | |
85 | + Scenario: go to user profile after login if this is the environment default | |
86 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
87 | + And I am not logged in | |
88 | + And the environment is configured to redirect to user profile page after login | |
89 | + And I go to the homepage | |
90 | + And I follow "Login" | |
91 | + And I fill in the following: | |
92 | + | Username | joaosilva | | |
93 | + | Password | 123456 | | |
94 | + When I press "Log in" | |
95 | + Then I should be on Joao Silva's profile | |
96 | + | |
97 | + Scenario: go to profile homepage after login if this is the environment default | |
98 | + Given the following articles | |
99 | + | owner | name | body | homepage | | |
100 | + | joaosilva | Sample Article | This is an article | true | | |
101 | + And feature "allow_change_of_redirection_after_login" is enabled on environment | |
102 | + And I am not logged in | |
103 | + And the environment is configured to redirect to profile homepage after login | |
104 | + And I go to the homepage | |
105 | + And I follow "Login" | |
106 | + And I fill in the following: | |
107 | + | Username | joaosilva | | |
108 | + | Password | 123456 | | |
109 | + When I press "Log in" | |
110 | + Then I should be on Joao Silva's homepage | |
111 | + | |
112 | + Scenario: go to profile control panel after login if this is the environment default | |
113 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
114 | + And I am not logged in | |
115 | + And the environment is configured to redirect to profile control panel after login | |
116 | + And I go to the homepage | |
117 | + And I follow "Login" | |
118 | + And I fill in the following: | |
119 | + | Username | joaosilva | | |
120 | + | Password | 123456 | | |
121 | + When I press "Log in" | |
122 | + Then I should be on Joao Silva's control panel | |
123 | + | |
124 | + Scenario: stay on the same page after login if this is the profile default | |
125 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
126 | + And I am not logged in | |
127 | + And the environment is configured to redirect to site homepage after login | |
128 | + And the profile joaosilva is configured to stay on the same page after login | |
129 | + And the following users | |
130 | + | login | name | | |
131 | + | mariasilva | Maria Silva | | |
132 | + And the following articles | |
133 | + | owner | name | homepage | | |
134 | + | mariasilva | my home page | true | | |
135 | + And I go to Maria Silva's homepage | |
136 | + And I follow "Login" | |
137 | + And I fill in the following: | |
138 | + | Username | joaosilva | | |
139 | + | Password | 123456 | | |
140 | + When I press "Log in" | |
141 | + Then I should be on Maria Silva's homepage | |
142 | + | |
143 | + Scenario: go to site homepage if this is the profile default | |
144 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
145 | + And I am not logged in | |
146 | + And the environment is configured to stay on the same page after login | |
147 | + And the profile joaosilva is configured to redirect to site homepage after login | |
148 | + And I go to Joao Silva's homepage | |
149 | + And I follow "Login" | |
150 | + And I fill in the following: | |
151 | + | Username | joaosilva | | |
152 | + | Password | 123456 | | |
153 | + When I press "Log in" | |
154 | + Then I should be on the homepage | |
155 | + | |
156 | + Scenario: go to user profile after login if this is the profile default | |
157 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
158 | + And I am not logged in | |
159 | + And the environment is configured to stay on the same page after login | |
160 | + And the profile joaosilva is configured to redirect to user profile page after login | |
161 | + And I go to the homepage | |
162 | + And I follow "Login" | |
163 | + And I fill in the following: | |
164 | + | Username | joaosilva | | |
165 | + | Password | 123456 | | |
166 | + When I press "Log in" | |
167 | + Then I should be on Joao Silva's profile | |
168 | + | |
169 | + Scenario: go to profile homepage after login if this is the profile default | |
170 | + Given the following articles | |
171 | + | owner | name | body | homepage | | |
172 | + | joaosilva | Sample Article | This is an article | true | | |
173 | + And feature "allow_change_of_redirection_after_login" is enabled on environment | |
174 | + And I am not logged in | |
175 | + And the environment is configured to stay on the same page after login | |
176 | + And the profile joaosilva is configured to redirect to profile homepage after login | |
177 | + And I go to the homepage | |
178 | + And I follow "Login" | |
179 | + And I fill in the following: | |
180 | + | Username | joaosilva | | |
181 | + | Password | 123456 | | |
182 | + When I press "Log in" | |
183 | + Then I should be on Joao Silva's homepage | |
184 | + | |
185 | + Scenario: go to profile control panel after login if this is the profile default | |
186 | + Given feature "allow_change_of_redirection_after_login" is enabled on environment | |
187 | + And I am not logged in | |
188 | + And the environment is configured to stay on the same page after login | |
189 | + And the profile joaosilva is configured to redirect to profile control panel after login | |
190 | + And I go to the homepage | |
191 | + And I follow "Login" | |
192 | + And I fill in the following: | |
193 | + | Username | joaosilva | | |
194 | + | Password | 123456 | | |
195 | + When I press "Log in" | |
196 | + Then I should be on Joao Silva's control panel | ... | ... |
features/send_email_to_organization_members.feature
1 | 1 | Feature: send emails to organization members |
2 | - As a organization administrator | |
2 | + As a organization administrator or moderator | |
3 | 3 | I want to send email to all members |
4 | 4 | |
5 | 5 | Background: |
6 | 6 | Given the following users |
7 | 7 | | login | name | |
8 | 8 | | joaosilva | Joao Silva | |
9 | + | jose | Jose Silva | | |
10 | + | manoel | Manoel Silva | | |
9 | 11 | And the following communities |
10 | 12 | | identifier | name | |
11 | 13 | | sample-community | Sample Community | |
12 | 14 | And "Joao Silva" is admin of "Sample Community" |
15 | + And "Jose Silva" is moderator of "Sample Community" | |
16 | + And "Manoel Silva" is a member of "Sample Community" | |
13 | 17 | |
14 | 18 | Scenario: Cant access if not logged in |
15 | 19 | Given I am not logged in |
16 | - When I go to /myprofile/sample-community/profile_members/send_mail | |
20 | + When I go to /profile/sample-community/send_mail | |
17 | 21 | Then I should be on login page |
18 | 22 | |
19 | 23 | Scenario: Cant access as normal user |
... | ... | @@ -21,7 +25,7 @@ Feature: send emails to organization members |
21 | 25 | | login | |
22 | 26 | | josesilva | |
23 | 27 | And I am logged in as "josesilva" |
24 | - When I go to /myprofile/sample-community/profile_members/send_mail | |
28 | + When I go to /profile/sample-community/send_mail | |
25 | 29 | Then I should see "Access denied" |
26 | 30 | |
27 | 31 | Scenario: Send e-mail to members |
... | ... | @@ -39,7 +43,7 @@ Feature: send emails to organization members |
39 | 43 | And I follow "Send e-mail to members" |
40 | 44 | And I fill in "body" with "We have some news" |
41 | 45 | When I press "Send" |
42 | - Then I should be on /myprofile/sample-community/profile_members/send_mail | |
46 | + Then I should be on /profile/sample-community/send_mail | |
43 | 47 | |
44 | 48 | Scenario: Not send e-mail to members if body is blank |
45 | 49 | Given I am logged in as "joaosilva" |
... | ... | @@ -47,7 +51,7 @@ Feature: send emails to organization members |
47 | 51 | And I follow "Send e-mail to members" |
48 | 52 | And I fill in "Subject" with "Hello, user!" |
49 | 53 | When I press "Send" |
50 | - Then I should be on /myprofile/sample-community/profile_members/send_mail | |
54 | + Then I should be on /profile/sample-community/send_mail | |
51 | 55 | |
52 | 56 | Scenario: Cancel creation of mailing |
53 | 57 | Given I am logged in as "joaosilva" |
... | ... | @@ -55,3 +59,34 @@ Feature: send emails to organization members |
55 | 59 | And I follow "Send e-mail to members" |
56 | 60 | When I follow "Cancel e-mail" |
57 | 61 | Then I should be on Sample Community's members management |
62 | + | |
63 | + Scenario: Cant access if has no send_mail_to_members permission | |
64 | + Given I am logged in as "manoel" | |
65 | + When I go to /profile/sample-community/send_mail | |
66 | + Then I should see "Access denied" | |
67 | + | |
68 | + Scenario: Show button "Send e-Mail to members" of community to an moderator | |
69 | + Given I am logged in as "jose" | |
70 | + When I go to Sample Community's members page | |
71 | + Then I should see "Send e-mail to members" link | |
72 | + | |
73 | + Scenario: Not show button "Send e-Mail to members" if user has no right permission | |
74 | + Given I am logged in as "manoel" | |
75 | + When I go to Sample Community's members page | |
76 | + Then I should not see "Send e-mail to members" link | |
77 | + | |
78 | + Scenario: Redirect back to profile members page after send mail | |
79 | + Given I am logged in as "jose" | |
80 | + When I go to Sample Community's members page | |
81 | + And I follow "Send e-mail to members" | |
82 | + And I fill in "Subject" with "Hello, member!" | |
83 | + And I fill in "body" with "We have some news" | |
84 | + When I press "Send" | |
85 | + Then I should be on Sample Community's members page | |
86 | + | |
87 | + Scenario: Back to profile members page after cancel creation of mailing | |
88 | + Given I am logged in as "jose" | |
89 | + And I go to Sample Community's members page | |
90 | + And I follow "Send e-mail to members" | |
91 | + When I follow "Cancel e-mail" | |
92 | + Then I should be on Sample Community's members page | ... | ... |
features/step_definitions/noosfero_steps.rb
... | ... | @@ -355,6 +355,12 @@ Given /^"(.+)" is admin of "(.+)"$/ do |person, organization| |
355 | 355 | org.add_admin(user) |
356 | 356 | end |
357 | 357 | |
358 | +Given /^"(.+)" is moderator of "(.+)"$/ do |person, organization| | |
359 | + org = Profile.find_by_name(organization) | |
360 | + user = Profile.find_by_name(person) | |
361 | + org.add_moderator(user) | |
362 | +end | |
363 | + | |
358 | 364 | Then /^"(.+)" should be admin of "(.+)"$/ do |person, organization| |
359 | 365 | org = Organization.find_by_name(organization) |
360 | 366 | user = Person.find_by_name(person) |
... | ... | @@ -706,3 +712,39 @@ When /^I make a AJAX request to (.*)$/ do |page| |
706 | 712 | header 'X-Requested-With', 'XMLHttpRequest' |
707 | 713 | visit(path_to(page)) |
708 | 714 | end |
715 | + | |
716 | +Given /^the environment is configured to (.*) after login$/ do |option| | |
717 | + redirection = case option | |
718 | + when 'stay on the same page' | |
719 | + 'keep_on_same_page' | |
720 | + when 'redirect to site homepage' | |
721 | + 'site_homepage' | |
722 | + when 'redirect to user profile page' | |
723 | + 'user_profile_page' | |
724 | + when 'redirect to profile homepage' | |
725 | + 'user_homepage' | |
726 | + when 'redirect to profile control panel' | |
727 | + 'user_control_panel' | |
728 | + end | |
729 | + environment = Environment.default | |
730 | + environment.redirection_after_login = redirection | |
731 | + environment.save | |
732 | +end | |
733 | + | |
734 | +Given /^the profile (.*) is configured to (.*) after login$/ do |profile, option| | |
735 | + redirection = case option | |
736 | + when 'stay on the same page' | |
737 | + 'keep_on_same_page' | |
738 | + when 'redirect to site homepage' | |
739 | + 'site_homepage' | |
740 | + when 'redirect to user profile page' | |
741 | + 'user_profile_page' | |
742 | + when 'redirect to profile homepage' | |
743 | + 'user_homepage' | |
744 | + when 'redirect to profile control panel' | |
745 | + 'user_control_panel' | |
746 | + end | |
747 | + profile = Profile.find_by_identifier(profile) | |
748 | + profile.redirection_after_login = redirection | |
749 | + profile.save | |
750 | +end | ... | ... |
features/support/paths.rb
... | ... | @@ -108,6 +108,9 @@ module NavigationHelpers |
108 | 108 | when /the user data path/ |
109 | 109 | '/account/user_data' |
110 | 110 | |
111 | + when /^(.+)'s members page/ | |
112 | + '/profile/%s/members' % Profile.find_by_name($1).identifier | |
113 | + | |
111 | 114 | # Add more mappings here. |
112 | 115 | # Here is a more fancy example: |
113 | 116 | # | ... | ... |
lib/acts_as_having_boxes.rb
lib/noosfero/plugin.rb
... | ... | @@ -320,6 +320,37 @@ class Noosfero::Plugin |
320 | 320 | nil |
321 | 321 | end |
322 | 322 | |
323 | + # -> Add an alternative authentication method. | |
324 | + # Your plugin have to make the access control and return the logged user. | |
325 | + # returns = User | |
326 | + def alternative_authentication | |
327 | + nil | |
328 | + end | |
329 | + | |
330 | + # -> Adds adicional link to make the user authentication | |
331 | + # returns = lambda block that creates html code | |
332 | + def alternative_authentication_link | |
333 | + nil | |
334 | + end | |
335 | + | |
336 | + # -> Allow or not user registration | |
337 | + # returns = boolean | |
338 | + def allow_user_registration | |
339 | + true | |
340 | + end | |
341 | + | |
342 | + # -> Allow or not password recovery by users | |
343 | + # returns = boolean | |
344 | + def allow_password_recovery | |
345 | + true | |
346 | + end | |
347 | + | |
348 | + # -> Adds fields to the login form | |
349 | + # returns = lambda block that creates html code | |
350 | + def login_extra_contents | |
351 | + nil | |
352 | + end | |
353 | + | |
323 | 354 | def method_missing(method, *args, &block) |
324 | 355 | # This is a generic hotspot for all controllers on Noosfero. |
325 | 356 | # If any plugin wants to define filters to run on any controller, the name of | ... | ... |
plugins/custom_forms/controllers/custom_forms_plugin_myprofile_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,147 @@ |
1 | +class CustomFormsPluginMyprofileController < MyProfileController | |
2 | + | |
3 | + protect 'post_content', :profile | |
4 | + def index | |
5 | + @forms = CustomFormsPlugin::Form.from(profile) | |
6 | + end | |
7 | + | |
8 | + def create | |
9 | + @form = CustomFormsPlugin::Form.new(:profile => profile) | |
10 | + @fields = [] | |
11 | + @empty_field = CustomFormsPlugin::Field.new | |
12 | + if request.post? | |
13 | + begin | |
14 | + @form.update_attributes!(params[:form]) | |
15 | + params[:fields] = format_kind(params[:fields]) | |
16 | + params[:fields] = format_choices(params[:fields]) | |
17 | + params[:fields] = set_form_id(params[:fields], @form.id) | |
18 | + create_fields(new_fields(params)) | |
19 | + session['notice'] = _('Form created') | |
20 | + redirect_to :action => 'index' | |
21 | + rescue Exception => exception | |
22 | + logger.error(exception.to_s) | |
23 | + session['notice'] = _('Form could not be created') | |
24 | + end | |
25 | + end | |
26 | + end | |
27 | + | |
28 | + def edit | |
29 | + @form = CustomFormsPlugin::Form.find(params[:id]) | |
30 | + @fields = @form.fields | |
31 | + @empty_field = CustomFormsPlugin::TextField.new | |
32 | + if request.post? | |
33 | + begin | |
34 | + @form.update_attributes!(params[:form]) | |
35 | + params[:fields] = format_kind(params[:fields]) | |
36 | + params[:fields] = format_choices(params[:fields]) | |
37 | + remove_fields(params, @form) | |
38 | + create_fields(new_fields(params)) | |
39 | + update_fields(edited_fields(params)) | |
40 | + session['notice'] = _('Form updated') | |
41 | + redirect_to :action => 'index' | |
42 | + rescue Exception => exception | |
43 | + logger.error(exception.to_s) | |
44 | + session['notice'] = _('Form could not be updated') | |
45 | + end | |
46 | + end | |
47 | + end | |
48 | + | |
49 | + def remove | |
50 | + @form = CustomFormsPlugin::Form.find(params[:id]) | |
51 | + begin | |
52 | + @form.destroy | |
53 | + session[:notice] = _('Form removed') | |
54 | + rescue | |
55 | + session[:notice] = _('Form could not be removed') | |
56 | + end | |
57 | + redirect_to :action => 'index' | |
58 | + end | |
59 | + | |
60 | + def submissions | |
61 | + @form = CustomFormsPlugin::Form.find(params[:id]) | |
62 | + @submissions = @form.submissions | |
63 | + end | |
64 | + | |
65 | + def show_submission | |
66 | + @submission = CustomFormsPlugin::Submission.find(params[:id]) | |
67 | + @form = @submission.form | |
68 | + end | |
69 | + | |
70 | + private | |
71 | + | |
72 | + def new_fields(params) | |
73 | + result = params[:fields].map {|id, hash| hash.has_key?(:real_id) ? nil : hash}.compact | |
74 | + result.delete_if {|field| field[:name].blank?} | |
75 | + result | |
76 | + end | |
77 | + | |
78 | + def edited_fields(params) | |
79 | + params[:fields].map {|id, hash| hash.has_key?(:real_id) ? hash : nil}.compact | |
80 | + end | |
81 | + | |
82 | + def create_fields(fields) | |
83 | + fields.each do |field| | |
84 | + case field[:type] | |
85 | + when 'text_field' | |
86 | + CustomFormsPlugin::TextField.create!(field) | |
87 | + when 'select_field' | |
88 | + CustomFormsPlugin::SelectField.create!(field) | |
89 | + else | |
90 | + CustomFormsPlugin::Field.create!(field) | |
91 | + end | |
92 | + end | |
93 | + end | |
94 | + | |
95 | + def update_fields(fields) | |
96 | + fields.each do |field_attrs| | |
97 | + field = CustomFormsPlugin::Field.find(field_attrs.delete(:real_id)) | |
98 | + field.attributes = field_attrs | |
99 | + field.save! if field.changed? | |
100 | + end | |
101 | + end | |
102 | + | |
103 | + def format_kind(fields) | |
104 | + fields.each do |id, field| | |
105 | + next if field[:kind].blank? | |
106 | + kind = field.delete(:kind) | |
107 | + case kind | |
108 | + when 'radio' | |
109 | + field[:list] = false | |
110 | + field[:multiple] = false | |
111 | + when 'check_box' | |
112 | + field[:list] = false | |
113 | + field[:multiple] = true | |
114 | + when 'select' | |
115 | + field[:list] = true | |
116 | + field[:multiple] = false | |
117 | + when 'multiple_select' | |
118 | + field[:list] = true | |
119 | + field[:multiple] = true | |
120 | + end | |
121 | + end | |
122 | + fields | |
123 | + end | |
124 | + | |
125 | + def format_choices(fields) | |
126 | + fields.each do |id, field| | |
127 | + next if !field.has_key?(:choices) | |
128 | + field[:choices] = field[:choices].map {|key, value| value}.inject({}) do |result, choice| | |
129 | + hash = (choice[:name].blank? || choice[:value].blank?) ? {} : {choice[:name] => choice[:value]} | |
130 | + result.merge!(hash) | |
131 | + end | |
132 | + end | |
133 | + fields | |
134 | + end | |
135 | + | |
136 | + def remove_fields(params, form) | |
137 | + present_fields = params[:fields].map{|id, value| value}.collect {|field| field[:real_id]}.compact | |
138 | + form.fields.each {|field| field.destroy if !present_fields.include?(field.id.to_s) } | |
139 | + end | |
140 | + | |
141 | + def set_form_id(fields, form_id) | |
142 | + fields.each do |id, field| | |
143 | + field[:form_id] = form_id | |
144 | + end | |
145 | + fields | |
146 | + end | |
147 | +end | ... | ... |
plugins/custom_forms/controllers/custom_forms_plugin_profile_controller.rb
0 → 100644
... | ... | @@ -0,0 +1,45 @@ |
1 | +class CustomFormsPluginProfileController < ProfileController | |
2 | + | |
3 | + before_filter :has_access, :show | |
4 | + | |
5 | + def show | |
6 | + @form = CustomFormsPlugin::Form.find(params[:id]) | |
7 | + if user | |
8 | + @submission ||= CustomFormsPlugin::Submission.find_by_form_id_and_profile_id(@form.id,user.id) | |
9 | + @submission ||= CustomFormsPlugin::Submission.new(:form_id => @form.id, :profile_id => user.id) | |
10 | + else | |
11 | + @submission ||= CustomFormsPlugin::Submission.new(:form_id => @form.id) | |
12 | + end | |
13 | + if request.post? | |
14 | + begin | |
15 | + extend(CustomFormsPlugin::Helper) | |
16 | + answers = build_answers(params[:submission], @form) | |
17 | + failed_answers = answers.select {|answer| !answer.valid? } | |
18 | + if failed_answers.empty? | |
19 | + if !user | |
20 | + @submission.author_name = params[:author_name] | |
21 | + @submission.author_email = params[:author_email] | |
22 | + end | |
23 | + @submission.save! | |
24 | + answers.map {|answer| answer.submission = @submission; answer.save!} | |
25 | + else | |
26 | + @submission.valid? | |
27 | + failed_answers.each do |answer| | |
28 | + @submission.errors.add(answer.field.name.to_sym, answer.errors[answer.field.slug.to_sym]) | |
29 | + end | |
30 | + end | |
31 | + session[:notice] = _('Submission saved') | |
32 | + redirect_to :action => 'show' | |
33 | + rescue | |
34 | + session[:notice] = _('Submission could not be saved') | |
35 | + end | |
36 | + end | |
37 | + end | |
38 | + | |
39 | + private | |
40 | + | |
41 | + def has_access | |
42 | + form = CustomFormsPlugin::Form.find(params[:id]) | |
43 | + render_access_denied if !form.accessible_to(user) | |
44 | + end | |
45 | +end | ... | ... |
plugins/custom_forms/db/migrate/20120727162444_create_custom_forms_plugin_forms.rb
0 → 100644
... | ... | @@ -0,0 +1,20 @@ |
1 | +class CreateCustomFormsPluginForms < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + create_table :custom_forms_plugin_forms do |t| | |
4 | + t.string :name | |
5 | + t.string :slug | |
6 | + t.text :description | |
7 | + t.references :profile | |
8 | + t.datetime :begining | |
9 | + t.datetime :ending | |
10 | + t.boolean :report_submissions, :default => false | |
11 | + t.boolean :on_membership, :default => false | |
12 | + t.string :access | |
13 | + t.timestamps | |
14 | + end | |
15 | + end | |
16 | + | |
17 | + def self.down | |
18 | + drop_table :custom_forms_plugin_forms | |
19 | + end | |
20 | +end | ... | ... |
plugins/custom_forms/db/migrate/20120727174506_create_custom_forms_plugin_fields.rb
0 → 100644
... | ... | @@ -0,0 +1,21 @@ |
1 | +class CreateCustomFormsPluginFields < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + create_table :custom_forms_plugin_fields do |t| | |
4 | + t.string :name | |
5 | + t.string :slug | |
6 | + t.string :type | |
7 | + t.string :default_value | |
8 | + t.string :choices | |
9 | + t.float :minimum | |
10 | + t.float :maximum | |
11 | + t.references :form | |
12 | + t.boolean :mandatory, :default => false | |
13 | + t.boolean :multiple | |
14 | + t.boolean :list | |
15 | + end | |
16 | + end | |
17 | + | |
18 | + def self.down | |
19 | + drop_table :custom_forms_plugin_fields | |
20 | + end | |
21 | +end | ... | ... |
plugins/custom_forms/db/migrate/20120727175250_create_custom_forms_plugin_answers.rb
0 → 100644
... | ... | @@ -0,0 +1,13 @@ |
1 | +class CreateCustomFormsPluginAnswers < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + create_table :custom_forms_plugin_answers do |t| | |
4 | + t.text :value | |
5 | + t.references :field | |
6 | + t.references :submission | |
7 | + end | |
8 | + end | |
9 | + | |
10 | + def self.down | |
11 | + drop_table :custom_forms_plugin_answers | |
12 | + end | |
13 | +end | ... | ... |
plugins/custom_forms/db/migrate/20120727180512_create_custom_forms_plugin_submissions.rb
0 → 100644
... | ... | @@ -0,0 +1,15 @@ |
1 | +class CreateCustomFormsPluginSubmissions < ActiveRecord::Migration | |
2 | + def self.up | |
3 | + create_table :custom_forms_plugin_submissions do |t| | |
4 | + t.string :author_name | |
5 | + t.string :author_email | |
6 | + t.references :profile | |
7 | + t.references :form | |
8 | + t.timestamps | |
9 | + end | |
10 | + end | |
11 | + | |
12 | + def self.down | |
13 | + drop_table :custom_forms_plugin_submissions | |
14 | + end | |
15 | +end | ... | ... |
... | ... | @@ -0,0 +1,21 @@ |
1 | +require 'ext/role_assignment_trigger' | |
2 | + | |
3 | +class CustomFormsPlugin < Noosfero::Plugin | |
4 | + | |
5 | + def self.plugin_name | |
6 | + "Custom Forms" | |
7 | + end | |
8 | + | |
9 | + def self.plugin_description | |
10 | + _("Enables the creation of forms.") | |
11 | + end | |
12 | + | |
13 | + def stylesheet? | |
14 | + true | |
15 | + end | |
16 | + | |
17 | + def control_panel_buttons | |
18 | + {:title => _('Manage Forms'), :icon => 'custom-forms', :url => {:controller => 'custom_forms_plugin_myprofile'}} | |
19 | + end | |
20 | + | |
21 | +end | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +class CustomFormsPlugin::Answer < Noosfero::Plugin::ActiveRecord | |
2 | + belongs_to :field, :class_name => 'CustomFormsPlugin::Field' | |
3 | + belongs_to :submission, :class_name => 'CustomFormsPlugin::Submission' | |
4 | + | |
5 | + validates_presence_of :field | |
6 | + validate :value_mandatory, :if => 'field.present?' | |
7 | + | |
8 | + def value_mandatory | |
9 | + if field.mandatory && value.blank? | |
10 | + errors.add(field.slug.to_sym, _("is mandatory.").fix_i18n) | |
11 | + end | |
12 | + end | |
13 | +end | |
14 | + | ... | ... |
... | ... | @@ -0,0 +1,16 @@ |
1 | +class CustomFormsPlugin::Field < ActiveRecord::Base | |
2 | + set_table_name :custom_forms_plugin_fields | |
3 | + | |
4 | + validates_presence_of :form, :name | |
5 | + validates_uniqueness_of :slug, :scope => :form_id | |
6 | + | |
7 | + belongs_to :form, :class_name => 'CustomFormsPlugin::Form', :dependent => :destroy | |
8 | + has_many :answers, :class_name => 'CustomFormsPlugin::Answer' | |
9 | + | |
10 | + serialize :choices, Hash | |
11 | + | |
12 | + before_validation do |field| | |
13 | + field.slug = field.name.to_slug if field.name.present? | |
14 | + end | |
15 | +end | |
16 | + | ... | ... |