Commit 6adc8bc231ef3c5692621c8bec01ea6411c83f03
Exists in
master
and in
27 other branches
Merge branch 'master' into rails3
Conflicts: app/controllers/my_profile/memberships_controller.rb app/helpers/application_helper.rb app/helpers/boxes_helper.rb app/models/article.rb app/models/category.rb app/models/change_password.rb app/models/comment.rb app/models/environment.rb app/models/event.rb app/models/profile.rb app/models/recent_documents_block.rb app/models/region.rb app/models/task.rb app/models/uploaded_file.rb app/views/account/forgot_password.html.erb app/views/events/_events_by_day.html.erb app/views/profile/_person_profile.html.erb app/views/shared/_manage_enterprises.html.erb config/environment.rb config/initializers/plugins.rb config/routes.rb db/schema.rb debian/control lib/noosfero/plugin.rb test/unit/article_test.rb test/unit/category_test.rb test/unit/change_password_test.rb test/unit/cms_helper_test.rb test/unit/comment_test.rb test/unit/content_viewer_helper_test.rb test/unit/event_test.rb test/unit/folder_helper_test.rb test/unit/person_test.rb test/unit/price_detail_test.rb test/unit/profile_helper_test.rb test/unit/recent_documents_block_test.rb test/unit/scrap_test.rb test/unit/user_mailer_test.rb vendor/plugins/action_tracker_has_comments/init.rb vendor/plugins/delayed_job/lib/delayed/worker.rb vendor/plugins/noosfero_caching/init.rb
Showing
566 changed files
with
74620 additions
and
59234 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 566 files displayed.
AUTHORS
... | ... | @@ -44,6 +44,7 @@ Antonio Terceiro <terceiro@colivre.coop.br> |
44 | 44 | Aurelio A. Heckert <aurelio@colivre.coop.br> |
45 | 45 | Braulio Bhavamitra <brauliobo@gmail.com> |
46 | 46 | Bráulio Bhavamitra <brauliobo@gmail.com> |
47 | +Braulio Bhavamitra <braulio@eita.org.br> | |
47 | 48 | Caio <caio.csalgado@gmail.com> |
48 | 49 | Caio + Diego + Pedro + João <caio.csalgado@gmail.com> |
49 | 50 | Caio Formiga <caio.formiga@gmail.com> |
... | ... | @@ -110,6 +111,7 @@ Diego Martinez <diegoamc90@gmail.com> |
110 | 111 | Diego Martinez <diego@diego-K55A.(none)> |
111 | 112 | Diego + Renan <renanteruoc@gmail.com> |
112 | 113 | Fernanda Lopes <nanda.listas+psl@gmail.com> |
114 | +Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br> | |
113 | 115 | Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)> |
114 | 116 | Grazieno Pellegrino <grazieno@gmail.com> |
115 | 117 | Isaac Canan <isaac@intelletto.com.br> |
... | ... | @@ -147,6 +149,8 @@ João M. M. Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br> |
147 | 149 | João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br> |
148 | 150 | Joenio Costa <joenio@colivre.coop.br> |
149 | 151 | Josef Spillner <josef.spillner@tu-dresden.de> |
152 | +Junior Silva <juniorsilva1001@gmail.com> | |
153 | +Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)> | |
150 | 154 | Keilla Menezes <keilla@colivre.coop.br> |
151 | 155 | Larissa Reis <larissa@colivre.coop.br> |
152 | 156 | Larissa Reis <reiss.larissa@gmail.com> |
... | ... | @@ -158,6 +162,7 @@ Lucas Melo <lucaspradomelo@gmail.com> |
158 | 162 | Luis David Aguilar Carlos <ludwig9003@gmail.com> |
159 | 163 | Martín Olivera <molivera@solar.org.ar> |
160 | 164 | Moises Machado <moises@colivre.coop.br> |
165 | +Naíla Alves <naila@colivre.coop.br> | |
161 | 166 | Nanda Lopes <nanda.listas+psl@gmail.com> |
162 | 167 | Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org> |
163 | 168 | Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org> |
... | ... | @@ -187,12 +192,15 @@ Renan Teruo + Diego Araujo <renanteruoc@gmail.com> |
187 | 192 | Renan Teruo + Diego Araújo <renanteruoc@gmail.com> |
188 | 193 | Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com> |
189 | 194 | Renan Teruo + Rafael Manzo <renanteruoc@gmail.com> |
195 | +Rodrigo Souto <diguliu@gmail.com> | |
190 | 196 | Rodrigo Souto <rodrigo@colivre.coop.br> |
191 | 197 | Ronny Kursawe <kursawe.ronny@googlemail.com> |
192 | 198 | root <root@debian.sdr.serpro> |
193 | 199 | Samuel R. C. Vale <srcvale@holoscopio.com> |
194 | 200 | Valessio Brito <valessio@gmail.com> |
195 | 201 | vfcosta <vfcosta@gmail.com> |
202 | +Victor Costa <vfcosta@gmail.com> | |
203 | +Vinicius Cubas Brand <viniciuscb@gmail.com> | |
196 | 204 | Visita <visita@debian.(none)> |
197 | 205 | Yann Lugrin <yann.lugrin@liquid-concept.ch> |
198 | 206 | ... | ... |
COPYRIGHT
... | ... | @@ -4,8 +4,9 @@ Copyright (c) 2007-2009, |
4 | 4 | Cáritas Brasileira <http://www.caritasbrasileira.org/> |
5 | 5 | Copyright (c) 2007-2009, |
6 | 6 | Ynternet.org Foundation <http://www.ynternet.org/> |
7 | -Copyright (c) 2008-2009, | |
7 | +Copyright (c) 2008-2013, | |
8 | 8 | Colivre <http://www.colivre.coop.br/> |
9 | +Copyright (c) the Noosfero contributors. See AUTHORS | |
9 | 10 | |
10 | 11 | This program is free software: you can redistribute it and/or modify |
11 | 12 | it under the terms of the GNU Affero General Public License as published by | ... | ... |
HACKING
... | ... | @@ -52,3 +52,12 @@ If you write such script for your own OS, *please* share it with us at the |
52 | 52 | development mailing list so that we can include it in the official repository. |
53 | 53 | This way other people using the same OS will have to put less effort to develop |
54 | 54 | Noosfero. |
55 | + | |
56 | +== Submitting your changes back | |
57 | + | |
58 | +For now please read: | |
59 | + | |
60 | +- Coding conventions | |
61 | + http://noosfero.org/Development/CodingConventions | |
62 | +- Patch guidelines | |
63 | + http://noosfero.org/Development/PatchGuidelines | ... | ... |
HACKING.rails235
... | ... | @@ -1,13 +0,0 @@ |
1 | -This is a draft of how to create a environment to Rails 2.3.5 to Noosfero | |
2 | -development. | |
3 | - | |
4 | -Install dependencies: | |
5 | - | |
6 | -gem install rails -v 2.3.5 | |
7 | -gem install i18n | |
8 | -gem install will_paginate -v 2.3.12 | |
9 | -gem install cucumber | |
10 | - | |
11 | -Creating initial environment: | |
12 | - | |
13 | -rake db:schema:load |
INSTALL.chat
... | ... | @@ -6,7 +6,7 @@ To configure XMPP/BOSH in Noosfero you need: |
6 | 6 | * SystemTimer - http://ph7spot.com/musings/system-timer |
7 | 7 | * Pidgin data files - http://www.pidgin.im/ |
8 | 8 | |
9 | -If you use Debian Wheezy: | |
9 | +If you use Debian 6.0 (squeeze): | |
10 | 10 | |
11 | 11 | # apt-get install librestclient-ruby pidgin-data ruby1.8-dev |
12 | 12 | # gem install SystemTimer | ... | ... |
README
1 | -noosfero - a web-based social platform | |
1 | +Noosfero - a web-based social platform | |
2 | 2 | ====================================== |
3 | 3 | |
4 | -:: About the project | |
4 | +http://www.noosfero.org/ | |
5 | 5 | |
6 | -Homepage: http://www.noosfero.org/ | |
6 | +Documentation | |
7 | +------------- | |
7 | 8 | |
8 | -:: Authors and copyright | |
9 | +The following documentation is available: | |
9 | 10 | |
10 | -Authors: see file AUTHORS | |
11 | -Copyright information: see file COPYRIGHT | |
12 | -Full license text; see file COPYING | |
11 | +File Purpose | |
12 | +~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
13 | +INSTALL install instructions | |
14 | +INSTALL.awstats install instructions - access statistics service | |
15 | +INSTALL.chat install instructions - chat service | |
16 | +INSTALL.email install instructions - email service | |
17 | +INSTALL.multitenancy install instructions - multiple sites | |
18 | +INSTALL.varnish install instructions - varnish HTTP caching (recommended) | |
19 | +HACKING development instruction | |
20 | +RELEASING instructions for doing releases | |
21 | +doc/noosfero/* user documentation (available through the app itself) | |
22 | + | |
23 | + | |
24 | +Authors and copyright | |
25 | +--------------------- | |
26 | + | |
27 | +Authorship and copyright information is available in the files listed below. | |
28 | + | |
29 | +File Purpose | |
30 | +~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
31 | +AUTHORS list of authors (updated at each release) | |
32 | +COPYRIGHT Copyright statement for the project | |
33 | +COPYING Full text of the project license | ... | ... |
app/controllers/admin/features_controller.rb
app/controllers/admin/users_controller.rb
... | ... | @@ -4,12 +4,52 @@ class UsersController < AdminController |
4 | 4 | |
5 | 5 | protect 'manage_environment_users', :environment |
6 | 6 | |
7 | + include UsersHelper | |
8 | + | |
7 | 9 | def index |
10 | + @filter = params[:filter] | |
11 | + scope = environment.people.no_templates | |
12 | + if @filter == 'admin_users' | |
13 | + scope = scope.admins | |
14 | + elsif @filter == 'activated_users' | |
15 | + scope = scope.activated | |
16 | + elsif @filter == 'deactivated_users' | |
17 | + scope = scope.deactivated | |
18 | + end | |
19 | + @q = params[:q] | |
20 | + @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results] | |
21 | + end | |
22 | + | |
23 | + def set_admin_role | |
24 | + person = environment.people.find(params[:id]) | |
25 | + environment.add_admin(person) | |
26 | + redirect_to :action => :index, :q => params[:q], :filter => params[:filter] | |
27 | + end | |
28 | + | |
29 | + def reset_admin_role | |
30 | + person = environment.people.find(params[:id]) | |
31 | + environment.remove_admin(person) | |
32 | + redirect_to :action => :index, :q => params[:q], :filter => params[:filter] | |
33 | + end | |
34 | + | |
35 | + def activate | |
36 | + person = environment.people.find(params[:id]) | |
37 | + person.user.activate | |
38 | + redirect_to :action => :index, :q => params[:q], :filter => params[:filter] | |
39 | + end | |
40 | + | |
41 | + def deactivate | |
42 | + person = environment.people.find(params[:id]) | |
43 | + person.user.deactivate | |
44 | + redirect_to :action => :index, :q => params[:q], :filter => params[:filter] | |
45 | + end | |
46 | + | |
47 | + def download | |
8 | 48 | respond_to do |format| |
9 | 49 | format.html |
10 | 50 | format.xml do |
11 | - @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person]) | |
12 | - send_data @users.to_xml( | |
51 | + users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person]) | |
52 | + send_data users.to_xml( | |
13 | 53 | :skip_types => true, |
14 | 54 | :only => %w[email login created_at updated_at], |
15 | 55 | :include => { :person => {:only => %w[name updated_at created_at address birth_date contact_phone identifier lat lng] } }), |
... | ... | @@ -45,4 +85,10 @@ class UsersController < AdminController |
45 | 85 | end |
46 | 86 | end |
47 | 87 | |
88 | + private | |
89 | + | |
90 | + def per_page | |
91 | + 10 | |
92 | + end | |
93 | + | |
48 | 94 | end | ... | ... |
app/controllers/application_controller.rb
... | ... | @@ -5,7 +5,7 @@ class ApplicationController < ActionController::Base |
5 | 5 | |
6 | 6 | before_filter :setup_multitenancy |
7 | 7 | before_filter :detect_stuff_by_domain |
8 | - before_filter :init_noosfero_plugins | |
8 | + before_filter :init_noosfero_plugins_controller_filters | |
9 | 9 | before_filter :allow_cross_domain_access |
10 | 10 | |
11 | 11 | def allow_cross_domain_access |
... | ... | @@ -24,8 +24,12 @@ class ApplicationController < ActionController::Base |
24 | 24 | include ApplicationHelper |
25 | 25 | layout :get_layout |
26 | 26 | def get_layout |
27 | - prepend_view_path('public/' + theme_path) | |
28 | - theme_option(:layout) || 'application' | |
27 | + theme_layout = theme_option(:layout) | |
28 | + if theme_layout | |
29 | + theme_view_file('layouts/'+theme_layout) || theme_layout | |
30 | + else | |
31 | + 'application' | |
32 | + end | |
29 | 33 | end |
30 | 34 | |
31 | 35 | def log_processing |
... | ... | @@ -128,22 +132,21 @@ class ApplicationController < ActionController::Base |
128 | 132 | |
129 | 133 | include Noosfero::Plugin::HotSpot |
130 | 134 | |
131 | - def init_noosfero_plugins | |
132 | - plugins.each do |plugin| | |
133 | - prepend_view_path(plugin.class.view_path) | |
134 | - end | |
135 | - init_noosfero_plugins_controller_filters | |
136 | - end | |
137 | - | |
138 | 135 | # This is a generic method that initialize any possible filter defined by a |
139 | 136 | # plugin to the current controller being initialized. |
140 | 137 | def init_noosfero_plugins_controller_filters |
141 | 138 | plugins.each do |plugin| |
142 | 139 | filters = plugin.send(self.class.name.underscore + '_filters') |
143 | 140 | filters = [filters] if !filters.kind_of?(Array) |
141 | + controller_filters = self.class.filter_chain.map {|c| c.method } | |
144 | 142 | filters.each do |plugin_filter| |
145 | - self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) | |
146 | - self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) | |
143 | + filter_method = plugin.class.name.underscore.gsub('/','_') + '_' + plugin_filter[:method_name] | |
144 | + unless controller_filters.include?(filter_method) | |
145 | + self.class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {})) | |
146 | + self.class.send(:define_method, filter_method) do | |
147 | + instance_eval(&plugin_filter[:block]) if environment.plugin_enabled?(plugin.class) | |
148 | + end | |
149 | + end | |
147 | 150 | end |
148 | 151 | end |
149 | 152 | end |
... | ... | @@ -173,17 +176,16 @@ class ApplicationController < ActionController::Base |
173 | 176 | end |
174 | 177 | |
175 | 178 | def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={}) |
176 | - scope = scope.send(options[:filter]) if options[:filter] | |
177 | - | |
178 | - @plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) || | |
179 | + plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) || | |
179 | 180 | fallback_find_by_contents(asset, scope, query, paginate_options, options) |
180 | 181 | end |
181 | 182 | |
182 | 183 | private |
183 | 184 | |
184 | 185 | def fallback_find_by_contents(asset, scope, query, paginate_options, options) |
185 | - return {:results => scope.paginate(paginate_options)} if query.blank? | |
186 | - {:results => scope.like_search(query).paginate(paginate_options)} | |
186 | + scope = scope.like_search(query) unless query.blank? | |
187 | + scope = scope.send(options[:filter]) unless options[:filter].blank? | |
188 | + {:results => scope.paginate(paginate_options)} | |
187 | 189 | end |
188 | 190 | |
189 | 191 | end | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -73,6 +73,7 @@ class CmsController < MyProfileController |
73 | 73 | refuse_blocks |
74 | 74 | record_coming |
75 | 75 | if request.post? |
76 | + @article.image = nil if params[:remove_image] == 'true' | |
76 | 77 | @article.last_changed_by = user |
77 | 78 | if @article.update_attributes(params[:article]) |
78 | 79 | if !continue |
... | ... | @@ -144,10 +145,15 @@ class CmsController < MyProfileController |
144 | 145 | |
145 | 146 | post_only :set_home_page |
146 | 147 | def set_home_page |
147 | - @article = profile.articles.find(params[:id]) | |
148 | - profile.home_page = @article | |
149 | - profile.save(false) | |
150 | - session[:notice] = _('"%s" configured as home page.') % @article.name | |
148 | + article = params[:id].nil? ? nil : profile.articles.find(params[:id]) | |
149 | + profile.update_attribute(:home_page, article) | |
150 | + | |
151 | + if article.nil? | |
152 | + session[:notice] = _('Homepage reseted.') | |
153 | + else | |
154 | + session[:notice] = _('"%s" configured as homepage.') % article.name | |
155 | + end | |
156 | + | |
151 | 157 | redirect_to (request.referer || profile.url) |
152 | 158 | end |
153 | 159 | |
... | ... | @@ -267,7 +273,10 @@ class CmsController < MyProfileController |
267 | 273 | @back_to = params[:back_to] || request.referer || url_for(profile.public_profile_url) |
268 | 274 | @task = SuggestArticle.new(params[:task]) |
269 | 275 | if request.post? |
270 | - @task.target = profile | |
276 | + @task.target = profile | |
277 | + @task.ip_address = request.remote_ip | |
278 | + @task.user_agent = request.user_agent | |
279 | + @task.referrer = request.referrer | |
271 | 280 | if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save |
272 | 281 | session[:notice] = _('Thanks for your suggestion. The community administrators were notified.') |
273 | 282 | redirect_to @back_to | ... | ... |
app/controllers/my_profile/manage_products_controller.rb
... | ... | @@ -6,10 +6,10 @@ class ManageProductsController < ApplicationController |
6 | 6 | before_filter :login_required, :except => [:show] |
7 | 7 | before_filter :create_product?, :only => [:new] |
8 | 8 | |
9 | - protected | |
9 | + protected | |
10 | 10 | |
11 | 11 | def check_environment_feature |
12 | - if profile.environment.enabled?('disable_products_for_enterprises') | |
12 | + unless profile.environment.enabled?('products_for_enterprises') | |
13 | 13 | render_not_found |
14 | 14 | return |
15 | 15 | end | ... | ... |
app/controllers/my_profile/memberships_controller.rb
1 | 1 | class MembershipsController < MyProfileController |
2 | 2 | |
3 | 3 | protect 'manage_memberships', :profile |
4 | - | |
4 | + | |
5 | 5 | def index |
6 | - @memberships = profile.memberships | |
6 | + @roles = environment.roles.select do |role| | |
7 | + ra = profile.role_assignments.find_by_role_id(role.id) | |
8 | + ra.present? && ra.resource_type == 'Profile' | |
9 | + end | |
10 | + @filter = params[:filter_type].blank? ? nil : params[:filter_type] | |
11 | + begin | |
12 | + @memberships = @filter.nil? ? profile.memberships : profile.memberships_by_role(environment.roles.find(@filter)) | |
13 | + rescue ActiveRecord::RecordNotFound | |
14 | + @memberships = [] | |
15 | + end | |
7 | 16 | end |
8 | 17 | |
9 | 18 | def new_community |
10 | 19 | @community = Community.new(params[:community]) |
11 | 20 | @community.environment = environment |
21 | + @back_to = params[:back_to] || url_for(:action => 'index') | |
12 | 22 | if request.post? && @community.valid? |
13 | 23 | @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment})) |
14 | - redirect_to :action => 'index' | |
24 | + redirect_to @back_to | |
15 | 25 | return |
16 | 26 | end |
17 | 27 | end | ... | ... |
app/controllers/my_profile/profile_design_controller.rb
... | ... | @@ -38,7 +38,7 @@ class ProfileDesignController < BoxOrganizerController |
38 | 38 | end |
39 | 39 | |
40 | 40 | # product block exclusive for enterprises in environments that permits it |
41 | - if profile.enterprise? && !profile.environment.enabled?('disable_products_for_enterprises') | |
41 | + if profile.enterprise? && profile.environment.enabled?('products_for_enterprises') | |
42 | 42 | blocks << ProductsBlock |
43 | 43 | end |
44 | 44 | ... | ... |
app/controllers/my_profile/profile_editor_controller.rb
... | ... | @@ -4,7 +4,7 @@ class ProfileEditorController < MyProfileController |
4 | 4 | protect 'destroy_profile', :profile, :only => [:destroy_profile] |
5 | 5 | |
6 | 6 | def index |
7 | - @pending_tasks = Task.to(profile).pending.select{|i| user.has_permission?(i.permission, profile)} | |
7 | + @pending_tasks = Task.to(profile).pending.without_spam.select{|i| user.has_permission?(i.permission, profile)} | |
8 | 8 | end |
9 | 9 | |
10 | 10 | helper :profile | ... | ... |
app/controllers/my_profile/spam_controller.rb
... | ... | @@ -14,9 +14,15 @@ class SpamController < MyProfileController |
14 | 14 | if params[:remove_comment] |
15 | 15 | profile.comments_received.find(params[:remove_comment]).destroy |
16 | 16 | end |
17 | + if params[:remove_task] | |
18 | + Task.to(profile).find_by_id(params[:remove_task]).destroy | |
19 | + end | |
17 | 20 | if params[:mark_comment_as_ham] |
18 | 21 | profile.comments_received.find(params[:mark_comment_as_ham]).ham! |
19 | 22 | end |
23 | + if params[:mark_task_as_ham] && (t = Task.to(profile).find_by_id(params[:mark_task_as_ham])) | |
24 | + t.ham! | |
25 | + end | |
20 | 26 | if request.xhr? |
21 | 27 | json_response(true) |
22 | 28 | else |
... | ... | @@ -28,7 +34,8 @@ class SpamController < MyProfileController |
28 | 34 | return |
29 | 35 | end |
30 | 36 | |
31 | - @spam = profile.comments_received.spam.paginate({:page => params[:page]}) | |
37 | + @comment_spam = profile.comments_received.spam.paginate({:page => params[:comments_page]}) | |
38 | + @task_spam = Task.to(profile).spam.paginate({:page => params[:tasks_page]}) | |
32 | 39 | end |
33 | 40 | |
34 | 41 | protected | ... | ... |
app/controllers/my_profile/tasks_controller.rb
... | ... | @@ -4,12 +4,12 @@ class TasksController < MyProfileController |
4 | 4 | |
5 | 5 | def index |
6 | 6 | @filter = params[:filter_type].blank? ? nil : params[:filter_type] |
7 | - @tasks = Task.to(profile).pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) | |
7 | + @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) | |
8 | 8 | @failed = params ? params[:failed] : {} |
9 | 9 | end |
10 | 10 | |
11 | 11 | def processed |
12 | - @tasks = Task.to(profile).closed.sort_by(&:created_at) | |
12 | + @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at) | |
13 | 13 | end |
14 | 14 | |
15 | 15 | VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ] |
... | ... | @@ -57,7 +57,7 @@ class TasksController < MyProfileController |
57 | 57 | end |
58 | 58 | |
59 | 59 | def list_requested |
60 | - @tasks = Task.find_all_by_requestor_id(profile.id) | |
60 | + @tasks = Task.without_spam.find_all_by_requestor_id(profile.id) | |
61 | 61 | end |
62 | 62 | |
63 | 63 | def ticket_details | ... | ... |
app/controllers/public/account_controller.rb
... | ... | @@ -141,22 +141,34 @@ class AccountController < ApplicationController |
141 | 141 | end |
142 | 142 | end |
143 | 143 | |
144 | - # The user requests a password change. She forgot her old password. | |
145 | - # | |
146 | - # Posts back. | |
144 | + include ForgotPasswordHelper | |
145 | + helper :forgot_password | |
146 | + | |
147 | 147 | def forgot_password |
148 | 148 | if @plugins.dispatch(:allow_password_recovery).include?(false) |
149 | 149 | redirect_back_or_default(:controller => 'home') |
150 | 150 | session[:notice] = _("This environment doesn't allow password recovery.") |
151 | 151 | end |
152 | - @change_password = ChangePassword.new(params[:change_password]) | |
152 | + | |
153 | + @change_password = ChangePassword.new | |
153 | 154 | |
154 | 155 | if request.post? |
155 | 156 | begin |
156 | - @change_password.save! | |
157 | + requestors = fetch_requestors(params[:value]) | |
158 | + raise ActiveRecord::RecordNotFound if requestors.blank? || params[:value].blank? | |
159 | + | |
160 | + requestors.each do |requestor| | |
161 | + ChangePassword.create!(:requestor => requestor) | |
162 | + end | |
157 | 163 | render :action => 'password_recovery_sent' |
158 | - rescue ActiveRecord::RecordInvalid => e | |
159 | - nil # just pass and render at the end of the action | |
164 | + rescue ActiveRecord::RecordNotFound | |
165 | + if params[:value].blank? | |
166 | + @change_password.errors.add_to_base(_('Can not recover user password with blank value.')) | |
167 | + else | |
168 | + @change_password.errors.add_to_base(_('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]]) | |
169 | + end | |
170 | + rescue ActiveRecord::RecordInvald | |
171 | + @change_password.errors.add_to_base(_('Could not perform password recovery for the user.')) | |
160 | 172 | end |
161 | 173 | end |
162 | 174 | end |
... | ... | @@ -262,7 +274,7 @@ class AccountController < ApplicationController |
262 | 274 | def user_data |
263 | 275 | user_data = |
264 | 276 | if logged_in? |
265 | - current_user.data_hash | |
277 | + current_user.data_hash(gravatar_default) | |
266 | 278 | else |
267 | 279 | { } |
268 | 280 | end | ... | ... |
app/controllers/public/catalog_controller.rb
... | ... | @@ -12,7 +12,7 @@ class CatalogController < PublicController |
12 | 12 | protected |
13 | 13 | |
14 | 14 | def check_enterprise_and_environment |
15 | - unless profile.kind_of?(Enterprise) && !profile.environment.enabled?('disable_products_for_enterprises') | |
15 | + unless profile.kind_of?(Enterprise) && @profile.environment.enabled?('products_for_enterprises') | |
16 | 16 | redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index' |
17 | 17 | end |
18 | 18 | end | ... | ... |
app/controllers/public/content_viewer_controller.rb
... | ... | @@ -53,8 +53,11 @@ class ContentViewerController < ApplicationController |
53 | 53 | # At this point the page will be showed |
54 | 54 | @page.hit |
55 | 55 | |
56 | - unless @page.mime_type == 'text/html' || (@page.image? && params[:view]) | |
56 | + @page = FilePresenter.for @page | |
57 | + | |
58 | + if @page.download? params[:view] | |
57 | 59 | headers['Content-Type'] = @page.mime_type |
60 | + headers.merge! @page.download_headers | |
58 | 61 | data = @page.data |
59 | 62 | |
60 | 63 | # TODO test the condition |
... | ... | @@ -70,7 +73,7 @@ class ContentViewerController < ApplicationController |
70 | 73 | |
71 | 74 | #FIXME see a better way to do this. It's not need to pass this variable anymore |
72 | 75 | @comment = Comment.new |
73 | - | |
76 | + | |
74 | 77 | if @page.has_posts? |
75 | 78 | posts = if params[:year] and params[:month] |
76 | 79 | filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01") |
... | ... | @@ -79,15 +82,21 @@ class ContentViewerController < ApplicationController |
79 | 82 | @page.posts |
80 | 83 | end |
81 | 84 | |
82 | - if @page.blog? && @page.display_posts_in_current_language? | |
83 | - posts = posts.native_translations.all(Article.display_filter(user, profile)).map{ |p| p.get_translation_to(FastGettext.locale) }.compact | |
84 | - end | |
85 | + #FIXME Need to run this before the pagination because this version of | |
86 | + # will_paginate returns a will_paginate collection instead of a | |
87 | + # relation. | |
88 | + blog_with_translation = @page.blog? && @page.display_posts_in_current_language? | |
89 | + posts = posts.native_translations if blog_with_translation | |
85 | 90 | |
86 | 91 | @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile))) |
92 | + | |
93 | + if blog_with_translation | |
94 | + @posts.replace @posts.map{ |p| p.get_translation_to(FastGettext.locale) }.compact | |
95 | + end | |
87 | 96 | end |
88 | 97 | |
89 | 98 | if @page.folder? && @page.gallery? |
90 | - @images = @page.images | |
99 | + @images = @page.images.select{ |a| a.display_to? user } | |
91 | 100 | @images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow] |
92 | 101 | end |
93 | 102 | |
... | ... | @@ -100,9 +109,9 @@ class ContentViewerController < ApplicationController |
100 | 109 | end |
101 | 110 | |
102 | 111 | @comments = @page.comments.without_spam |
112 | + @comments = @plugins.filter(:unavailable_comments, @comments) | |
103 | 113 | @comments_count = @comments.count |
104 | - @comments = @plugins.filter(:unavailable_comments, @comments.without_reply) | |
105 | - @comments = @comments.paginate(:per_page => per_page, :page => params[:comment_page] ) | |
114 | + @comments = @comments.without_reply.paginate(:per_page => per_page, :page => params[:comment_page] ) | |
106 | 115 | |
107 | 116 | if params[:slideshow] |
108 | 117 | render :action => 'slideshow', :layout => 'slideshow' | ... | ... |
app/controllers/public/events_controller.rb
1 | 1 | class EventsController < PublicController |
2 | 2 | |
3 | 3 | needs_profile |
4 | - no_design_blocks | |
5 | 4 | |
6 | 5 | def events |
7 | - @selected_day = nil | |
8 | - @events_of_the_day = [] | |
9 | - date = build_date(params[:year], params[:month], params[:day]) | |
6 | + @events = [] | |
7 | + @date = build_date(params[:year], params[:month], params[:day]) | |
10 | 8 | |
11 | - if params[:day] || !params[:year] && !params[:month] | |
12 | - @selected_day = date | |
13 | - @events_of_the_day = profile.events.by_day(@selected_day) | |
9 | + if !params[:year] && !params[:month] && !params[:day] | |
10 | + @events = profile.events.next_events_from_month(@date) | |
14 | 11 | end |
15 | 12 | |
16 | - events = profile.events.by_range((date - 1.month).at_beginning_of_month..(date + 1.month).at_end_of_month) | |
13 | + if params[:year] || params[:month] | |
14 | + @events = profile.events.by_month(@date) | |
15 | + end | |
16 | + | |
17 | + events_in_range = profile.events.by_range((@date - 1.month).at_beginning_of_month .. (@date + 1.month).at_end_of_month) | |
17 | 18 | |
18 | - @calendar = populate_calendar(date, events) | |
19 | - @previous_calendar = populate_calendar(date - 1.month, events) | |
20 | - @next_calendar = populate_calendar(date + 1.month, events) | |
19 | + @calendar = populate_calendar(@date, events_in_range) | |
21 | 20 | end |
22 | 21 | |
23 | 22 | def events_by_day |
24 | - @selected_day = build_date(params[:year], params[:month], params[:day]) | |
25 | - @events_of_the_day = profile.events.by_day(@selected_day) | |
26 | - render :partial => 'events_by_day' | |
23 | + @date = build_date(params[:year], params[:month], params[:day]) | |
24 | + @events = profile.events.by_day(@date) | |
25 | + render :partial => 'events' | |
27 | 26 | end |
28 | 27 | |
29 | 28 | protected | ... | ... |
app/controllers/public/profile_controller.rb
... | ... | @@ -206,10 +206,50 @@ class ProfileController < PublicController |
206 | 206 | end |
207 | 207 | |
208 | 208 | def view_more_network_activities |
209 | - @activities = @profile.tracked_notifications.paginate(:per_page => 10, :page => params[:page]) | |
209 | + @activities = @profile.tracked_notifications.paginate(:per_page => 10, :page => params[:page]) | |
210 | 210 | render :partial => 'profile_network_activities', :locals => {:network_activities => @activities} |
211 | 211 | end |
212 | 212 | |
213 | + def more_comments | |
214 | + activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity], :user_id => @profile}) | |
215 | + comments_count = activity.comments.count | |
216 | + comment_page = (params[:comment_page] || 1).to_i | |
217 | + comments_per_page = 5 | |
218 | + no_more_pages = comments_count <= comment_page * comments_per_page | |
219 | + | |
220 | + render :update do |page| | |
221 | + page.insert_html :bottom, 'profile-wall-activities-comments-'+params[:activity], | |
222 | + :partial => 'comment', :collection => activity.comments.paginate(:per_page => comments_per_page, :page => comment_page) | |
223 | + | |
224 | + if no_more_pages | |
225 | + page.remove 'profile-wall-activities-comments-more-'+params[:activity] | |
226 | + else | |
227 | + page.replace_html 'profile-wall-activities-comments-more-'+params[:activity], | |
228 | + :partial => 'more_comments', :locals => {:activity => activity, :comment_page => comment_page} | |
229 | + end | |
230 | + end | |
231 | + end | |
232 | + | |
233 | + def more_replies | |
234 | + activity = Scrap.find(:first, :conditions => {:id => params[:activity], :receiver_id => @profile, :scrap_id => nil}) | |
235 | + comments_count = activity.replies.count | |
236 | + comment_page = (params[:comment_page] || 1).to_i | |
237 | + comments_per_page = 5 | |
238 | + no_more_pages = comments_count <= comment_page * comments_per_page | |
239 | + | |
240 | + render :update do |page| | |
241 | + page.insert_html :bottom, 'profile-wall-activities-comments-'+params[:activity], | |
242 | + :partial => 'profile_scrap', :collection => activity.replies.paginate(:per_page => comments_per_page, :page => comment_page), :as => :scrap | |
243 | + | |
244 | + if no_more_pages | |
245 | + page.remove 'profile-wall-activities-comments-more-'+params[:activity] | |
246 | + else | |
247 | + page.replace_html 'profile-wall-activities-comments-more-'+params[:activity], | |
248 | + :partial => 'more_replies', :locals => {:activity => activity, :comment_page => comment_page} | |
249 | + end | |
250 | + end | |
251 | + end | |
252 | + | |
213 | 253 | def remove_scrap |
214 | 254 | begin |
215 | 255 | scrap = current_user.person.scraps(params[:scrap_id]) |
... | ... | @@ -343,6 +383,7 @@ class ProfileController < PublicController |
343 | 383 | end |
344 | 384 | end |
345 | 385 | |
386 | + | |
346 | 387 | protected |
347 | 388 | |
348 | 389 | def check_access_to_profile |
... | ... | @@ -393,4 +434,5 @@ class ProfileController < PublicController |
393 | 434 | def relations_to_include |
394 | 435 | [:image, :domains, :preferred_domain, :environment] |
395 | 436 | end |
437 | + | |
396 | 438 | end | ... | ... |
app/controllers/public/search_controller.rb
... | ... | @@ -93,25 +93,27 @@ class SearchController < PublicController |
93 | 93 | year = (params[:year] ? params[:year].to_i : Date.today.year) |
94 | 94 | month = (params[:month] ? params[:month].to_i : Date.today.month) |
95 | 95 | day = (params[:day] ? params[:day].to_i : Date.today.day) |
96 | - date = build_date(params[:year], params[:month], params[:day]) | |
97 | - date_range = (date - 1.month).at_beginning_of_month..(date + 1.month).at_end_of_month | |
96 | + @date = build_date(year, month, day) | |
97 | + date_range = (@date - 1.month).at_beginning_of_month..(@date + 1.month).at_end_of_month | |
98 | 98 | |
99 | - @selected_day = nil | |
100 | - @events_of_the_day = [] | |
99 | + @events = [] | |
101 | 100 | if params[:day] || !params[:year] && !params[:month] |
102 | - @selected_day = date | |
103 | - @events_of_the_day = @category ? | |
104 | - environment.events.by_day(@selected_day).in_category(Category.find(@category_id)) : | |
105 | - environment.events.by_day(@selected_day) | |
101 | + @events = @category ? | |
102 | + environment.events.by_day(@date).in_category(Category.find(@category_id)) : | |
103 | + environment.events.by_day(@date) | |
104 | + end | |
105 | + | |
106 | + if params[:year] || params[:month] | |
107 | + @events = @category ? | |
108 | + environment.events.by_month(@date).in_category(Category.find(@category_id)) : | |
109 | + environment.events.by_month(@date) | |
106 | 110 | end |
107 | 111 | |
108 | 112 | @scope = date_range && params[:action] == 'events' ? environment.events.by_range(date_range) : environment.events |
109 | 113 | full_text_search |
110 | 114 | |
111 | 115 | events = @searches[@asset][:results] |
112 | - @calendar = populate_calendar(date, events) | |
113 | - @previous_calendar = populate_calendar(date - 1.month, events) | |
114 | - @next_calendar = populate_calendar(date + 1.month, events) | |
116 | + @calendar = populate_calendar(@date, events) | |
115 | 117 | end |
116 | 118 | |
117 | 119 | # keep old URLs workings |
... | ... | @@ -136,9 +138,9 @@ class SearchController < PublicController |
136 | 138 | end |
137 | 139 | |
138 | 140 | def events_by_day |
139 | - @selected_day = build_date(params[:year], params[:month], params[:day]) | |
140 | - @events_of_the_day = environment.events.by_day(@selected_day) | |
141 | - render :partial => 'events/events_by_day' | |
141 | + @date = build_date(params[:year], params[:month], params[:day]) | |
142 | + @events = environment.events.by_day(@date) | |
143 | + render :partial => 'events/events' | |
142 | 144 | end |
143 | 145 | |
144 | 146 | ####################################################### | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -40,6 +40,8 @@ module ApplicationHelper |
40 | 40 | |
41 | 41 | include LayoutHelper |
42 | 42 | |
43 | + include Noosfero::Gravatar | |
44 | + | |
43 | 45 | VIEW_EXTENSIONS = ['.rhtml', '.html.erb'] |
44 | 46 | |
45 | 47 | def locale |
... | ... | @@ -367,7 +369,7 @@ module ApplicationHelper |
367 | 369 | def current_theme |
368 | 370 | @current_theme ||= |
369 | 371 | begin |
370 | - if (session[:theme]) | |
372 | + if session[:theme] | |
371 | 373 | session[:theme] |
372 | 374 | else |
373 | 375 | # utility for developers: set the theme to 'random' in development mode and |
... | ... | @@ -376,7 +378,7 @@ module ApplicationHelper |
376 | 378 | if Rails.env.development? && environment.theme == 'random' |
377 | 379 | @random_theme ||= Dir.glob('public/designs/themes/*').map { |f| File.basename(f) }.rand |
378 | 380 | @random_theme |
379 | - elsif Rails.env.development? && params[:theme] && File.exists?(Rails.root.join('public/designs/themes', params[:theme])) | |
381 | + elsif Rails.env.development? && respond_to?(:params) && params[:theme] && File.exists?(Rails.root.join('public/designs/themes', params[:theme])) | |
380 | 382 | params[:theme] |
381 | 383 | else |
382 | 384 | if profile && !profile.theme.nil? |
... | ... | @@ -398,18 +400,25 @@ module ApplicationHelper |
398 | 400 | end |
399 | 401 | end |
400 | 402 | |
401 | - def theme_include(template) | |
402 | - # XXX Since we cannot control what people are doing in external themes, we | |
403 | + def theme_view_file(template) | |
404 | + # Since we cannot control what people are doing in external themes, we | |
403 | 405 | # will keep looking for the deprecated .rhtml extension here. |
404 | 406 | VIEW_EXTENSIONS.each do |ext| |
405 | 407 | file = Rails.root.join('public', theme_path[1..-1], template + ext) |
406 | - if File.exists?(file) | |
407 | - return render :file => file, :use_full_path => false | |
408 | - end | |
408 | + return file if File.exists?(file) | |
409 | 409 | end |
410 | 410 | nil |
411 | 411 | end |
412 | 412 | |
413 | + def theme_include(template) | |
414 | + file = theme_view_file(template) | |
415 | + if file | |
416 | + render :file => file, :use_full_path => false | |
417 | + else | |
418 | + nil | |
419 | + end | |
420 | + end | |
421 | + | |
413 | 422 | def theme_favicon |
414 | 423 | return '/designs/themes/' + current_theme + '/favicon.ico' if profile.nil? || profile.theme.nil? |
415 | 424 | if File.exists?(Rails.root.join('public', theme_path, 'favicon.ico')) |
... | ... | @@ -561,6 +570,9 @@ module ApplicationHelper |
561 | 570 | # displays a link to the profile homepage with its image (as generated by |
562 | 571 | # #profile_image) and its name below it. |
563 | 572 | def profile_image_link( profile, size=:portrait, tag='li', extra_info = nil ) |
573 | + if content = @plugins.dispatch_first(:profile_image_link, profile, size, tag, extra_info) | |
574 | + return instance_eval(&content) | |
575 | + end | |
564 | 576 | name = profile.short_name |
565 | 577 | if profile.person? |
566 | 578 | url = url_for(profile.check_friendship_url) |
... | ... | @@ -577,45 +589,20 @@ module ApplicationHelper |
577 | 589 | extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' ) |
578 | 590 | links = links_for_balloon(profile) |
579 | 591 | content_tag('div', content_tag(tag, |
580 | - (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") + | |
581 | - link_to( | |
582 | - content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) + | |
583 | - content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + | |
584 | - extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ), | |
585 | - profile.url, | |
586 | - :class => 'profile_link url', | |
587 | - :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, | |
588 | - :title => profile.name ), | |
589 | - :class => 'vcard'), :class => 'common-profile-list-block') | |
590 | - end | |
591 | - | |
592 | - def gravatar_url_for(email, options = {}) | |
593 | - # Ta dando erro de roteamento | |
594 | - default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil | |
595 | - url_for( { :gravatar_id => Digest::MD5.hexdigest(email.to_s), | |
596 | - :host => 'www.gravatar.com', | |
597 | - :protocol => 'http://', | |
598 | - :only_path => false, | |
599 | - :controller => 'avatar.php', | |
600 | - :d => default | |
601 | - }.merge(options) ) | |
602 | - end | |
603 | - | |
604 | - def str_gravatar_url_for(email, options = {}) | |
605 | - default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil | |
606 | - url = 'http://www.gravatar.com/avatar.php?gravatar_id=' + | |
607 | - Digest::MD5.hexdigest(email.to_s) | |
608 | - { | |
609 | - :only_path => false, | |
610 | - :d => default | |
611 | - }.merge(options).each { |k,v| | |
612 | - url += ( '&%s=%s' % [ k,v ] ) | |
613 | - } | |
614 | - url | |
615 | - end | |
616 | - | |
617 | - def gravatar_profile_url(email) | |
618 | - 'http://www.gravatar.com/'+ Digest::MD5.hexdigest(email.to_s) | |
592 | + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") + | |
593 | + link_to( | |
594 | + content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) + | |
595 | + content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + | |
596 | + extra_info + profile_sex_icon( profile ) + profile_cat_icons( profile ), | |
597 | + profile.url, | |
598 | + :class => 'profile_link url', | |
599 | + :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, | |
600 | + :title => profile.name ), | |
601 | + :class => 'vcard'), :class => 'common-profile-list-block') | |
602 | + end | |
603 | + | |
604 | + def gravatar_default | |
605 | + (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar'] | |
619 | 606 | end |
620 | 607 | |
621 | 608 | attr_reader :environment |
... | ... | @@ -730,8 +717,15 @@ module ApplicationHelper |
730 | 717 | end |
731 | 718 | |
732 | 719 | def rolename_for(profile, resource) |
733 | - role = profile.role_assignments.find_by_resource_id(resource.id).role | |
734 | - content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}") | |
720 | + roles = profile.role_assignments. | |
721 | + where(:resource_id => resource.id). | |
722 | + sort_by{ |role_assignment| role_assignment.role_id }. | |
723 | + map(&:role) | |
724 | + names = [] | |
725 | + roles.each do |role| | |
726 | + names << content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}") | |
727 | + end | |
728 | + names.join(', ') | |
735 | 729 | end |
736 | 730 | |
737 | 731 | def role_color(role, env_id) |
... | ... | @@ -945,7 +939,7 @@ module ApplicationHelper |
945 | 939 | (@category ? " - #{@category.full_name}" : '') |
946 | 940 | end |
947 | 941 | |
948 | - # DEPRECATED. Do not use this· | |
942 | + # DEPRECATED. Do not use this. | |
949 | 943 | def import_controller_stylesheets(options = {}) |
950 | 944 | stylesheet_import( "controller_"+ controller.controller_name(), options ) |
951 | 945 | end |
... | ... | @@ -1128,15 +1122,34 @@ module ApplicationHelper |
1128 | 1122 | result |
1129 | 1123 | end |
1130 | 1124 | |
1131 | - def manage_enterprises | |
1132 | - if user && !user.enterprises.empty? | |
1133 | - enterprises_link = user.enterprises.map do |enterprise| | |
1134 | - link_to(content_tag('strong', [_('<span>Manage</span> %s') % enterprise.short_name(25)]), @environment.top_url + "/myprofile/#{enterprise.identifier}", :class => "icon-menu-"+enterprise.class.identification.underscore, :title => [_('Manage %s') % enterprise.short_name]) | |
1125 | + def manage_link(list, kind) | |
1126 | + if list.present? | |
1127 | + link_to_all = nil | |
1128 | + if list.count > 5 | |
1129 | + list = list.first(5) | |
1130 | + link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => current_user.login) | |
1131 | + end | |
1132 | + link = list.map do |element| | |
1133 | + link_to(content_tag('strong', [_('<span>Manage</span> %s') % element.short_name(25)]), @environment.top_url + "/myprofile/#{element.identifier}", :class => "icon-menu-"+element.class.identification.underscore, :title => [_('Manage %s') % element.short_name]) | |
1134 | + end | |
1135 | + if link_to_all | |
1136 | + link << link_to_all | |
1135 | 1137 | end |
1136 | - render :partial => 'shared/manage_enterprises', :locals => {:enterprises_link => enterprises_link} | |
1138 | + render :partial => "shared/manage_link", :locals => {:link => link, :kind => kind.to_s} | |
1137 | 1139 | end |
1138 | 1140 | end |
1139 | 1141 | |
1142 | + def manage_enterprises | |
1143 | + return unless user && user.environment.enabled?(:display_my_enterprises_on_user_menu) | |
1144 | + manage_link(user.enterprises, :enterprises) | |
1145 | + end | |
1146 | + | |
1147 | + def manage_communities | |
1148 | + return unless user && user.environment.enabled?(:display_my_communities_on_user_menu) | |
1149 | + administered_communities = user.communities.more_popular.select {|c| c.admins.include? user} | |
1150 | + manage_link(administered_communities, :communities) | |
1151 | + end | |
1152 | + | |
1140 | 1153 | def usermenu_logged_in |
1141 | 1154 | pending_tasks_count = '' |
1142 | 1155 | count = user ? Task.to(user).pending.count : -1 |
... | ... | @@ -1144,11 +1157,12 @@ module ApplicationHelper |
1144 | 1157 | pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) |
1145 | 1158 | end |
1146 | 1159 | |
1147 | - (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + | |
1160 | + (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i style="background-image:url({avatar})"></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + | |
1148 | 1161 | render_environment_features(:usermenu) + |
1149 | - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') + | |
1162 | + link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') + | |
1150 | 1163 | manage_enterprises.to_s + |
1151 | - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) + | |
1164 | + manage_communities.to_s + | |
1165 | + link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :class => 'ctrl-panel', :title => _("Configure your personal account and content")) + | |
1152 | 1166 | pending_tasks_count + |
1153 | 1167 | link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) |
1154 | 1168 | end |
... | ... | @@ -1325,8 +1339,8 @@ module ApplicationHelper |
1325 | 1339 | @plugins.dispatch("content_remove_#{action.to_s}", @page).include?(true) |
1326 | 1340 | end |
1327 | 1341 | |
1328 | - def template_options(klass, field_name) | |
1329 | - templates = klass.templates(environment) | |
1342 | + def template_options(kind, field_name) | |
1343 | + templates = environment.send(kind).templates | |
1330 | 1344 | return '' if templates.count == 0 |
1331 | 1345 | return hidden_field_tag("#{field_name}[template_id]", templates.first.id) if templates.count == 1 |
1332 | 1346 | |
... | ... | @@ -1440,8 +1454,8 @@ module ApplicationHelper |
1440 | 1454 | end |
1441 | 1455 | |
1442 | 1456 | def filter_html(html, source) |
1443 | - if @plugins | |
1444 | - html = convert_macro(html, source) | |
1457 | + if @plugins && source && source.has_macro? | |
1458 | + html = convert_macro(html, source) unless @plugins.enabled_macros.blank? | |
1445 | 1459 | #TODO This parse should be done through the macro infra, but since there |
1446 | 1460 | # are old things that do not support it we are keeping this hot spot. |
1447 | 1461 | html = @plugins.pipeline(:parse_content, html, source).first | ... | ... |
app/helpers/blog_helper.rb
... | ... | @@ -42,7 +42,7 @@ module BlogHelper |
42 | 42 | |
43 | 43 | def display_post(article, format = 'full') |
44 | 44 | no_comments = (format == 'full') ? false : true |
45 | - html = send("display_#{format}_format", article) | |
45 | + html = send("display_#{format}_format", FilePresenter.for(article)).html_safe | |
46 | 46 | |
47 | 47 | article_title(article, :no_comments => no_comments) + html |
48 | 48 | end | ... | ... |
app/helpers/boxes_helper.rb
... | ... | @@ -99,17 +99,19 @@ module BoxesHelper |
99 | 99 | unless block.visible? |
100 | 100 | options[:title] = _("This block is invisible. Your visitors will not see it.") |
101 | 101 | end |
102 | - if controller.send(:content_editor?) | |
103 | - result = filter_html(result, block) | |
104 | - end | |
105 | - box_decorator.block_target(block.box, block) + | |
106 | - content_tag('div', | |
107 | - content_tag('div', | |
102 | + | |
103 | + result = filter_html(result, block) | |
104 | + | |
105 | + content_tag('div', | |
106 | + box_decorator.block_target(block.box, block) + | |
107 | + content_tag('div', | |
108 | 108 | content_tag('div', |
109 | - result + footer_content + box_decorator.block_edit_buttons(block), | |
110 | - :class => 'block-inner-2'), | |
111 | - :class => 'block-inner-1'), | |
112 | - options) + | |
109 | + content_tag('div', | |
110 | + result + footer_content + box_decorator.block_edit_buttons(block), | |
111 | + :class => 'block-inner-2'), | |
112 | + :class => 'block-inner-1'), | |
113 | + options), | |
114 | + :class => 'block-outer') + | |
113 | 115 | box_decorator.block_handle(block) |
114 | 116 | end |
115 | 117 | |
... | ... | @@ -225,15 +227,11 @@ module BoxesHelper |
225 | 227 | |
226 | 228 | # DEPRECATED. Do not use this. |
227 | 229 | def import_blocks_stylesheets(options = {}) |
228 | - @blocks_css_files ||= current_blocks.map{|b|'blocks/' + block_css_class_name(b)}.uniq | |
230 | + @blocks_css_files ||= current_blocks.map{|b|'blocks/' + block.class.name.to_css_class}.uniq | |
229 | 231 | stylesheet_import(@blocks_css_files, options) |
230 | 232 | end |
231 | - | |
232 | - def block_css_class_name(block) | |
233 | - block.class.name.underscore.gsub('_', '-') | |
234 | - end | |
235 | 233 | def block_css_classes(block) |
236 | - classes = block_css_class_name(block) | |
234 | + classes = block.class.name.to_css_class | |
237 | 235 | classes += ' invisible-block' if block.display == 'never' |
238 | 236 | classes |
239 | 237 | end | ... | ... |
app/helpers/categories_helper.rb
... | ... | @@ -3,10 +3,21 @@ module CategoriesHelper |
3 | 3 | |
4 | 4 | COLORS = [ |
5 | 5 | [ N_('Do not display at the menu'), nil ], |
6 | - [ N_('Orange'), 1 ], | |
7 | - [ N_('Green'), 2 ], | |
8 | - [ N_('Purple'), 3 ], | |
9 | - [ N_('Red'), 4 ], | |
6 | + [ N_('Orange'), 1], | |
7 | + [ N_('Green'), 2], | |
8 | + [ N_('Purple'), 3], | |
9 | + [ N_('Red'), 4], | |
10 | + [ N_('Dark Green'), 5], | |
11 | + [ N_('Blue Oil'), 6], | |
12 | + [ N_('Blue'), 7], | |
13 | + [ N_('Brown'), 8], | |
14 | + [ N_('Light Green'), 9], | |
15 | + [ N_('Light Blue'), 10], | |
16 | + [ N_('Dark Blue'), 11], | |
17 | + [ N_('Blue Pool'), 12], | |
18 | + [ N_('Beige'), 13], | |
19 | + [ N_('Yellow'), 14], | |
20 | + [ N_('Light Brown'), 15] | |
10 | 21 | ] |
11 | 22 | |
12 | 23 | TYPES = [ | ... | ... |
app/helpers/cms_helper.rb
... | ... | @@ -28,12 +28,12 @@ module CmsHelper |
28 | 28 | end |
29 | 29 | |
30 | 30 | def link_to_article(article) |
31 | - article_name = short_filename(article.title, 30) | |
31 | + article_name = article.title | |
32 | 32 | if article.folder? |
33 | 33 | link_to article_name, {:action => 'view', :id => article.id}, :class => icon_for_article(article) |
34 | 34 | else |
35 | 35 | if article.image? |
36 | - image_tag(icon_for_article(article)) + link_to(article_name, article.url) | |
36 | + image_tag(icon_for_article(article)) + link_to(article_name, article.url) | |
37 | 37 | else |
38 | 38 | link_to article_name, article.url, :class => icon_for_article(article) |
39 | 39 | end | ... | ... |
app/helpers/content_viewer_helper.rb
... | ... | @@ -17,7 +17,7 @@ module ContentViewerHelper |
17 | 17 | title = article.display_title if article.kind_of?(UploadedFile) && article.image? |
18 | 18 | title = article.title if title.blank? |
19 | 19 | title = content_tag('h1', h(title), :class => 'title') |
20 | - if article.belongs_to_blog? | |
20 | + if article.belongs_to_blog? || article.belongs_to_forum? | |
21 | 21 | unless args[:no_link] |
22 | 22 | title = content_tag('h1', link_to(article.name, article.url), :class => 'title') |
23 | 23 | end | ... | ... |
app/helpers/dates_helper.rb
... | ... | @@ -35,6 +35,18 @@ module DatesHelper |
35 | 35 | end |
36 | 36 | end |
37 | 37 | |
38 | + def show_date_month(date, use_numbers = false, year=true) | |
39 | + if date && use_numbers | |
40 | + date_format = year ? _('%{month}/%{year}') : _('%{month}/%{day}') | |
41 | + date_format % { :month => date.month, :year => date.year } | |
42 | + elsif date | |
43 | + date_format = year ? _('%{month_name}, %{year}') : _('%{month_name}') | |
44 | + date_format % { :month_name => month_name(date.month), :year => date.year } | |
45 | + else | |
46 | + '' | |
47 | + end | |
48 | + end | |
49 | + | |
38 | 50 | # formats a datetime for displaying. |
39 | 51 | def show_time(time) |
40 | 52 | if time |
... | ... | @@ -98,7 +110,11 @@ module DatesHelper |
98 | 110 | elsif opts[:previous] |
99 | 111 | date = date << 1 |
100 | 112 | end |
101 | - _('%{month} %{year}') % { :year => date.year, :month => month_name(date.month.to_i) } | |
113 | + if opts[:only_month] | |
114 | + _('%{month}') % {:month => month_name(date.month.to_i) } | |
115 | + else | |
116 | + _('%{month} %{year}') % { :year => date.year, :month => month_name(date.month.to_i) } | |
117 | + end | |
102 | 118 | end |
103 | 119 | |
104 | 120 | def build_date(year, month, day = 1) |
... | ... | @@ -123,7 +139,7 @@ module DatesHelper |
123 | 139 | previous_month_date = date - 1.month |
124 | 140 | |
125 | 141 | label ||= show_month(previous_month_date.year, previous_month_date.month) |
126 | - link_to label, :year => previous_month_date.year, :month => previous_month_date.month | |
142 | + button(:back, label, {:year => previous_month_date.year, :month => previous_month_date.month}) | |
127 | 143 | end |
128 | 144 | |
129 | 145 | def link_to_next_month(year, month, label = nil) |
... | ... | @@ -131,7 +147,7 @@ module DatesHelper |
131 | 147 | next_month_date = date + 1.month |
132 | 148 | |
133 | 149 | label ||= show_month(next_month_date.year, next_month_date.month) |
134 | - link_to label, :year => next_month_date.year, :month => next_month_date.month | |
150 | + button(:next, label, {:year => next_month_date.year, :month => next_month_date.month}) | |
135 | 151 | end |
136 | 152 | |
137 | 153 | def pick_date(object, method, options = {}, html_options = {}) | ... | ... |
app/helpers/events_helper.rb
1 | 1 | module EventsHelper |
2 | 2 | |
3 | 3 | def list_events(date, events) |
4 | - return content_tag('em', _("Select a day on the left to display it's events here"), :class => 'select-a-day') unless date | |
5 | - title = _('Events for %s') % show_date(date) | |
4 | + title = _('Events for %s') % show_date_month(date) | |
6 | 5 | content_tag('h2', title) + |
7 | 6 | content_tag('div', |
8 | 7 | (events.any? ? |
9 | 8 | content_tag('table', events.select { |item| item.display_to?(user) }.map {|item| display_event_in_listing(item)}.join('')) : |
10 | - content_tag('em', _('No events for this date'), :class => 'no-events') | |
9 | + content_tag('em', _('No events for this month'), :class => 'no-events') | |
11 | 10 | ), :id => 'agenda-items' |
12 | 11 | ) |
13 | 12 | end |
14 | 13 | |
15 | 14 | def display_event_in_listing(article) |
16 | - content_tag( | |
17 | - 'tr', | |
18 | - content_tag('td', link_to(article.name, article.url, :class => icon_for_article(article))), | |
19 | - :class => 'agenda-item' | |
15 | + | |
16 | + content_tag( 'tr', | |
17 | + content_tag('td', | |
18 | + content_tag('div', show_date(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_date(article.end_date))),:class => 'event-date' ) + | |
19 | + content_tag('div',link_to(article.name,article.url),:class => 'event-title') + | |
20 | + content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place') | |
21 | + ) | |
20 | 22 | ) |
21 | 23 | end |
22 | 24 | ... | ... |
app/helpers/folder_helper.rb
... | ... | @@ -23,6 +23,7 @@ module FolderHelper |
23 | 23 | end |
24 | 24 | |
25 | 25 | def display_article_in_listing(article, recursive = false, level = 0) |
26 | + article = FilePresenter.for article | |
26 | 27 | article_link = if article.image? |
27 | 28 | link_to(' ' * (level * 4) + image_tag(icon_for_article(article)) + short_filename(article.name), article.url.merge(:view => true)) |
28 | 29 | else |
... | ... | @@ -42,12 +43,15 @@ module FolderHelper |
42 | 43 | end |
43 | 44 | |
44 | 45 | def icon_for_article(article) |
45 | - icon = article.class.icon_name(article) | |
46 | + article = FilePresenter.for article | |
47 | + icon = article.respond_to?(:icon_name) ? | |
48 | + article.icon_name : | |
49 | + article.class.icon_name(article) | |
46 | 50 | if (icon =~ /\//) |
47 | 51 | icon |
48 | 52 | else |
49 | - klasses = 'icon icon-' + icon | |
50 | - if article.kind_of?(UploadedFile) | |
53 | + klasses = 'icon ' + [icon].flatten.map{|name| 'icon-'+name}.join(' ') | |
54 | + if article.kind_of?(UploadedFile) || article.kind_of?(FilePresenter) | |
51 | 55 | klasses += ' icon-upload-file' |
52 | 56 | end |
53 | 57 | klasses | ... | ... |
... | ... | @@ -0,0 +1,43 @@ |
1 | +module ForgotPasswordHelper | |
2 | + def plugins_options | |
3 | + @plugins.dispatch(:change_password_fields) | |
4 | + end | |
5 | + | |
6 | + def user_fields | |
7 | + %w[login email] + plugins_options.select {|options| options[:model].to_sym == :user }.map { |options| options[:field].to_s } | |
8 | + end | |
9 | + | |
10 | + def person_fields | |
11 | + %w[] + plugins_options.select {|options| options[:model].to_sym == :person }.map { |options| options[:field].to_s } | |
12 | + end | |
13 | + | |
14 | + def fields | |
15 | + user_fields + person_fields | |
16 | + end | |
17 | + | |
18 | + def fields_label | |
19 | + labels = [ | |
20 | + _('Username'), | |
21 | + _('Email'), | |
22 | + ] + plugins_options.map { |options| options[:name] } | |
23 | + | |
24 | + last = labels.pop | |
25 | + label = labels.join(', ') | |
26 | + "#{label} #{_('or')} #{last}" | |
27 | + end | |
28 | + | |
29 | + def build_query(fields, value) | |
30 | + fields.map {|field| "#{field} = '#{value}'"}.join(' OR ') | |
31 | + end | |
32 | + | |
33 | + def fetch_requestors(value) | |
34 | + requestors = [] | |
35 | + person_query = build_query(person_fields, value) | |
36 | + user_query = build_query(user_fields, value) | |
37 | + | |
38 | + requestors += Person.where(person_query).where(:environment_id => environment.id) if person_fields.present? | |
39 | + requestors += User.where(user_query).where(:environment_id => environment.id).map(&:person) if user_fields.present? | |
40 | + requestors | |
41 | + end | |
42 | + | |
43 | +end | ... | ... |
app/helpers/profile_editor_helper.rb
... | ... | @@ -136,7 +136,7 @@ module ProfileEditorHelper |
136 | 136 | concat( |
137 | 137 | content_tag( |
138 | 138 | 'div', |
139 | - capture(&block) + content_tag('br', '', :style => 'clear: left'), | |
139 | + capture(&block) + tag('br', :style => 'clear: left'), | |
140 | 140 | :class => 'control-panel') |
141 | 141 | ) |
142 | 142 | 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)) || | |
5 | - (profile.active_fields.include?(field.to_s) && !profile.public_fields.include?(field.to_s) && (!user || (user != profile && !user.is_a_friend?(profile)))) | |
4 | + unless force || profile.may_display_field_to?(field, user) | |
6 | 5 | return '' |
7 | 6 | end |
8 | 7 | value = profile.send(field) | ... | ... |
app/helpers/sweeper_helper.rb
... | ... | @@ -44,4 +44,30 @@ module SweeperHelper |
44 | 44 | def expire_profile_index(profile) |
45 | 45 | expire_timeout_fragment(profile.relationships_cache_key) |
46 | 46 | end |
47 | + | |
48 | + def expire_blocks_cache(context, causes) | |
49 | + if context.kind_of?(Profile) | |
50 | + profile = context | |
51 | + environment = profile.environment | |
52 | + else | |
53 | + environment = context | |
54 | + profile = nil | |
55 | + end | |
56 | + | |
57 | + blocks_to_expire = [] | |
58 | + if profile | |
59 | + profile.blocks.each {|block| | |
60 | + conditions = block.class.expire_on | |
61 | + blocks_to_expire << block unless (conditions[:profile] & causes).empty? | |
62 | + } | |
63 | + end | |
64 | + environment.blocks.each {|block| | |
65 | + conditions = block.class.expire_on | |
66 | + blocks_to_expire << block unless (conditions[:environment] & causes).empty? | |
67 | + } | |
68 | + | |
69 | + blocks_to_expire.uniq! | |
70 | + BlockSweeper.expire_blocks(blocks_to_expire) | |
71 | + end | |
72 | + | |
47 | 73 | end | ... | ... |
... | ... | @@ -0,0 +1,25 @@ |
1 | +module UsersHelper | |
2 | + | |
3 | + FILTER_TRANSLATION = { | |
4 | + 'all_users' => _('All users'), | |
5 | + 'admin_users' => _('Admin users'), | |
6 | + 'activated_users' => _('Activated users'), | |
7 | + 'deactivated_users' => _('Deativated users'), | |
8 | + } | |
9 | + | |
10 | + def filter_selector(filter, float = 'right') | |
11 | + options = options_for_select(FILTER_TRANSLATION.map {|key, name| [name, key]}, :selected => filter) | |
12 | + url_params = url_for(params.merge(:filter => 'FILTER')) | |
13 | + onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)" | |
14 | + select_field = select_tag(:filter, options, :onchange => onchange) | |
15 | + content_tag('div', | |
16 | + content_tag('strong', _('Filter')) + ': ' + select_field, | |
17 | + :class => "environment-users-customize-search" | |
18 | + ) | |
19 | + end | |
20 | + | |
21 | + def filter_title(filter) | |
22 | + FILTER_TRANSLATION[filter] | |
23 | + end | |
24 | + | |
25 | +end | ... | ... |
app/models/action_tracker_notification.rb
... | ... | @@ -3,7 +3,7 @@ class ActionTrackerNotification < ActiveRecord::Base |
3 | 3 | belongs_to :profile |
4 | 4 | belongs_to :action_tracker, :class_name => 'ActionTracker::Record', :foreign_key => 'action_tracker_id' |
5 | 5 | |
6 | - has_many :comments, :through => :action_tracker, :class_name => 'Comment', :foreign_key => 'source_id' | |
6 | + delegate :comments, :to => :action_tracker, :allow_nil => true | |
7 | 7 | |
8 | 8 | validates_presence_of :profile_id, :action_tracker_id |
9 | 9 | validates_uniqueness_of :action_tracker_id, :scope => :profile_id | ... | ... |
app/models/approve_comment.rb
... | ... | @@ -6,7 +6,7 @@ class ApproveComment < Task |
6 | 6 | validates_presence_of :comment_attributes |
7 | 7 | |
8 | 8 | def comment |
9 | - @comment ||= Comment.new(JSON.parse(self.comment_attributes)) unless self.comment_attributes.nil? | |
9 | + @comment ||= Comment.new(ActiveSupport::JSON.decode(self.comment_attributes)) unless self.comment_attributes.nil? | |
10 | 10 | end |
11 | 11 | |
12 | 12 | def requestor_name |
... | ... | @@ -42,9 +42,9 @@ class ApproveComment < Task |
42 | 42 | def information |
43 | 43 | if article |
44 | 44 | if requestor |
45 | - {:message => _('%{requestor} commented on the the article: %{linked_subject}.')} | |
45 | + {:message => _('%{requestor} commented on the article: %{linked_subject}.')} | |
46 | 46 | else |
47 | - { :message => _('%{requestor} commented on the the article: %{linked_subject}.'), | |
47 | + { :message => _('%{requestor} commented on the article: %{linked_subject}.'), | |
48 | 48 | :variables => {:requestor => requestor_name} } |
49 | 49 | end |
50 | 50 | else | ... | ... |
app/models/article.rb
... | ... | @@ -4,6 +4,8 @@ class Article < ActiveRecord::Base |
4 | 4 | |
5 | 5 | attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent |
6 | 6 | |
7 | + acts_as_having_image | |
8 | + | |
7 | 9 | SEARCHABLE_FIELDS = { |
8 | 10 | :name => 10, |
9 | 11 | :abstract => 3, |
... | ... | @@ -59,7 +61,7 @@ class Article < ActiveRecord::Base |
59 | 61 | has_many :article_categorizations, :conditions => [ 'articles_categories.virtual = ?', false ] |
60 | 62 | has_many :categories, :through => :article_categorizations |
61 | 63 | |
62 | - has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization', :dependent => :destroy | |
64 | + has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization' | |
63 | 65 | has_many :categories_including_virtual, :through => :article_categorizations_including_virtual, :source => :category |
64 | 66 | |
65 | 67 | acts_as_having_settings :field => :setting |
... | ... | @@ -156,8 +158,12 @@ class Article < ActiveRecord::Base |
156 | 158 | end |
157 | 159 | end |
158 | 160 | |
161 | + def css_class_list | |
162 | + [self.class.name.to_css_class] | |
163 | + end | |
164 | + | |
159 | 165 | def css_class_name |
160 | - self.class.name.underscore.dasherize | |
166 | + [css_class_list].flatten.compact.join(' ') | |
161 | 167 | end |
162 | 168 | |
163 | 169 | def pending_categorizations |
... | ... | @@ -190,7 +196,7 @@ class Article < ActiveRecord::Base |
190 | 196 | pending_categorizations.clear |
191 | 197 | end |
192 | 198 | |
193 | - acts_as_taggable | |
199 | + acts_as_taggable | |
194 | 200 | N_('Tag list') |
195 | 201 | |
196 | 202 | acts_as_filesystem |
... | ... | @@ -268,7 +274,7 @@ class Article < ActiveRecord::Base |
268 | 274 | end |
269 | 275 | |
270 | 276 | # returns the data of the article. Must be overriden in each subclass to |
271 | - # provide the correct content for the article. | |
277 | + # provide the correct content for the article. | |
272 | 278 | def data |
273 | 279 | body |
274 | 280 | end |
... | ... | @@ -282,6 +288,11 @@ class Article < ActiveRecord::Base |
282 | 288 | 'text-html' |
283 | 289 | end |
284 | 290 | |
291 | + # TODO Migrate the class method icon_name to instance methods. | |
292 | + def icon_name | |
293 | + self.class.icon_name(self) | |
294 | + end | |
295 | + | |
285 | 296 | def mime_type |
286 | 297 | 'text/html' |
287 | 298 | end |
... | ... | @@ -310,6 +321,10 @@ class Article < ActiveRecord::Base |
310 | 321 | def belongs_to_blog? |
311 | 322 | self.parent and self.parent.blog? |
312 | 323 | end |
324 | + | |
325 | + def belongs_to_forum? | |
326 | + self.parent and self.parent.forum? | |
327 | + end | |
313 | 328 | |
314 | 329 | def info_from_last_update |
315 | 330 | last_comment = comments.last |
... | ... | @@ -325,7 +340,7 @@ class Article < ActiveRecord::Base |
325 | 340 | end |
326 | 341 | |
327 | 342 | def view_url |
328 | - @view_url ||= image? ? url.merge(:view => true) : url | |
343 | + @view_url ||= is_a?(UploadedFile) ? url.merge(:view => true) : url | |
329 | 344 | end |
330 | 345 | |
331 | 346 | def comment_url_structure(comment, action = :edit) |
... | ... | @@ -340,24 +355,18 @@ class Article < ActiveRecord::Base |
340 | 355 | true |
341 | 356 | end |
342 | 357 | |
343 | - def folder? | |
344 | - false | |
345 | - end | |
346 | - | |
347 | - def blog? | |
348 | - false | |
349 | - end | |
350 | - | |
351 | - def forum? | |
358 | + def has_posts? | |
352 | 359 | false |
353 | 360 | end |
354 | 361 | |
355 | - def uploaded_file? | |
356 | - false | |
362 | + def download? view = nil | |
363 | + (self.uploaded_file? and not self.image?) or | |
364 | + (self.image? and view.blank?) or | |
365 | + (not self.uploaded_file? and self.mime_type != 'text/html') | |
357 | 366 | end |
358 | 367 | |
359 | - def has_posts? | |
360 | - false | |
368 | + def download_headers | |
369 | + {} | |
361 | 370 | end |
362 | 371 | |
363 | 372 | scope :native_translations, :conditions => { :translation_of_id => nil } |
... | ... | @@ -444,6 +453,7 @@ class Article < ActiveRecord::Base |
444 | 453 | scope :galleries, :conditions => { :type => 'Gallery' } |
445 | 454 | scope :images, :conditions => { :is_image => true } |
446 | 455 | scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] |
456 | + scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } } | |
447 | 457 | |
448 | 458 | scope :more_popular, :order => 'hits DESC' |
449 | 459 | scope :more_comments, :order => "comments_count DESC" |
... | ... | @@ -586,6 +596,22 @@ class Article < ActiveRecord::Base |
586 | 596 | false |
587 | 597 | end |
588 | 598 | |
599 | + def folder? | |
600 | + false | |
601 | + end | |
602 | + | |
603 | + def blog? | |
604 | + false | |
605 | + end | |
606 | + | |
607 | + def forum? | |
608 | + false | |
609 | + end | |
610 | + | |
611 | + def uploaded_file? | |
612 | + false | |
613 | + end | |
614 | + | |
589 | 615 | def author |
590 | 616 | if versions.empty? |
591 | 617 | last_changed_by |
... | ... | @@ -725,6 +751,10 @@ class Article < ActiveRecord::Base |
725 | 751 | |
726 | 752 | delegate :region, :region_id, :environment, :environment_id, :to => :profile, :allow_nil => true |
727 | 753 | |
754 | + def has_macro? | |
755 | + true | |
756 | + end | |
757 | + | |
728 | 758 | private |
729 | 759 | |
730 | 760 | def sanitize_tag_list | ... | ... |
app/models/article_block.rb
... | ... | @@ -12,7 +12,7 @@ class ArticleBlock < Block |
12 | 12 | block = self |
13 | 13 | proc do |
14 | 14 | block_title(block.title) + |
15 | - (block.article ? article_to_html(block.article, | |
15 | + (block.article ? article_to_html(FilePresenter.for(block.article), | |
16 | 16 | :gallery_view => false, |
17 | 17 | :inside_block => block, # For Blogs and folders |
18 | 18 | :format => block.visualization_format # For Articles and contents |
... | ... | @@ -23,7 +23,7 @@ class ArticleBlock < Block |
23 | 23 | def article_id |
24 | 24 | self.settings[:article_id] |
25 | 25 | end |
26 | - | |
26 | + | |
27 | 27 | def article_id= value |
28 | 28 | self.settings[:article_id] = value.blank? ? nil : value.to_i |
29 | 29 | end |
... | ... | @@ -49,8 +49,8 @@ class ArticleBlock < Block |
49 | 49 | end |
50 | 50 | |
51 | 51 | def available_articles |
52 | - return [] if self.box.nil? or self.box.owner.nil? | |
53 | - self.box.owner.kind_of?(Environment) ? self.box.owner.portal_community.articles : self.box.owner.articles | |
52 | + return [] if self.owner.nil? | |
53 | + self.owner.kind_of?(Environment) ? self.owner.portal_community.articles : self.owner.articles | |
54 | 54 | end |
55 | 55 | |
56 | 56 | def posts_per_page |
... | ... | @@ -63,4 +63,9 @@ class ArticleBlock < Block |
63 | 63 | end |
64 | 64 | |
65 | 65 | settings_items :visualization_format, :type => :string, :default => 'short' |
66 | + | |
67 | + def self.expire_on | |
68 | + { :profile => [:article], :environment => [:article] } | |
69 | + end | |
70 | + | |
66 | 71 | end | ... | ... |
app/models/block.rb
... | ... | @@ -140,4 +140,19 @@ class Block < ActiveRecord::Base |
140 | 140 | 4.hours |
141 | 141 | end |
142 | 142 | |
143 | + def has_macro? | |
144 | + false | |
145 | + end | |
146 | + | |
147 | + # Override in your subclasses. | |
148 | + # Define which events and context should cause the block cache to expire | |
149 | + # Possible events are: :article, :profile, :friendship, :category | |
150 | + # Possible contexts are: :profile, :environment | |
151 | + def self.expire_on | |
152 | + { | |
153 | + :profile => [], | |
154 | + :environment => [] | |
155 | + } | |
156 | + end | |
157 | + | |
143 | 158 | end | ... | ... |
app/models/blog_archives_block.rb
app/models/box.rb
... | ... | @@ -3,12 +3,15 @@ class Box < ActiveRecord::Base |
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 | 5 | |
6 | + include Noosfero::Plugin::HotSpot | |
7 | + | |
6 | 8 | def environment |
7 | 9 | owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil |
8 | 10 | end |
9 | 11 | |
10 | 12 | def acceptable_blocks |
11 | - to_css_class_name central? ? Box.acceptable_center_blocks : Box.acceptable_side_blocks | |
13 | + blocks_classes = central? ? Box.acceptable_center_blocks + plugins.dispatch(:extra_blocks, :position => 1) : Box.acceptable_side_blocks + plugins.dispatch(:extra_blocks, :position => [2, 3]) | |
14 | + to_css_class_name(blocks_classes) | |
12 | 15 | end |
13 | 16 | |
14 | 17 | def central? |
... | ... | @@ -74,8 +77,8 @@ class Box < ActiveRecord::Base |
74 | 77 | |
75 | 78 | private |
76 | 79 | |
77 | - def to_css_class_name(blocks) | |
78 | - blocks.map{ |block| block.to_s.underscore.tr('_', '-') } | |
80 | + def to_css_class_name(blocks_classes) | |
81 | + blocks_classes.map{ |block_class| block_class.name.to_css_class } | |
79 | 82 | end |
80 | 83 | |
81 | 84 | end | ... | ... |
app/models/categories_block.rb
app/models/category.rb
... | ... | @@ -9,13 +9,13 @@ class Category < ActiveRecord::Base |
9 | 9 | :slug => 1, |
10 | 10 | } |
11 | 11 | |
12 | - validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('%{fn} cannot be like that.').fix_i18n | |
12 | + validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('{fn} cannot be like that.').fix_i18n | |
13 | 13 | validates_presence_of :name, :environment_id |
14 | - validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.').fix_i18n | |
14 | + validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('{fn} is already being used by another category.').fix_i18n | |
15 | 15 | belongs_to :environment |
16 | 16 | |
17 | - validates_inclusion_of :display_color, :in => [ 1, 2, 3, 4, nil ] | |
18 | - validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('%{fn} was already assigned to another category.').fix_i18n | |
17 | + validates_inclusion_of :display_color, :in => 1..15, :allow_nil => true | |
18 | + validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('{fn} was already assigned to another category.').fix_i18n | |
19 | 19 | |
20 | 20 | # Finds all top level categories for a given environment. |
21 | 21 | scope :top_level_for, lambda { |environment| |
... | ... | @@ -24,23 +24,15 @@ class Category < ActiveRecord::Base |
24 | 24 | |
25 | 25 | scope :on_level, lambda { |parent| {:conditions => {:parent_id => parent}} } |
26 | 26 | |
27 | - scope :sub_categories, lambda { |category| | |
28 | - {:conditions => ['categories.path LIKE ? AND categories.id != ?', "%#{category.slug}%", category.id]} | |
29 | - } | |
30 | - | |
31 | - scope :sub_tree, lambda { |category| | |
32 | - {:conditions => ['categories.path LIKE ?', "%#{category.slug}%"]} | |
33 | - } | |
34 | - | |
35 | 27 | acts_as_filesystem |
36 | 28 | |
37 | - has_many :article_categorizations, :dependent => :destroy | |
29 | + has_many :article_categorizations | |
38 | 30 | has_many :articles, :through => :article_categorizations |
39 | 31 | has_many :comments, :through => :articles |
40 | 32 | |
41 | 33 | has_many :events, :through => :article_categorizations, :class_name => 'Event', :source => :article |
42 | 34 | |
43 | - has_many :profile_categorizations, :dependent => :destroy | |
35 | + has_many :profile_categorizations | |
44 | 36 | has_many :profiles, :through => :profile_categorizations, :source => :profile |
45 | 37 | has_many :enterprises, :through => :profile_categorizations, :source => :profile, :class_name => 'Enterprise' |
46 | 38 | has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' | ... | ... |
app/models/change_password.rb
1 | 1 | class ChangePassword < Task |
2 | 2 | |
3 | - attr_accessor :login, :email, :password, :password_confirmation, :environment_id | |
3 | + attr_accessor :password, :password_confirmation | |
4 | 4 | |
5 | 5 | def self.human_attribute_name(attrib) |
6 | 6 | case attrib.to_sym |
7 | - when :login | |
8 | - _('Username') | |
9 | - when :email | |
10 | - _('e-mail') | |
11 | 7 | when :password |
12 | 8 | _('Password') |
13 | 9 | when :password_confirmation |
... | ... | @@ -17,29 +13,7 @@ class ChangePassword < Task |
17 | 13 | end |
18 | 14 | end |
19 | 15 | |
20 | - ################################################### | |
21 | - # validations for creating a ChangePassword task | |
22 | - | |
23 | - validates_presence_of :login, :email, :environment_id, :on => :create, :message => _('must be filled in') | |
24 | - | |
25 | - validates_format_of :email, :on => :create, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |obj| !obj.email.blank? }) | |
26 | - | |
27 | - validates_each :login, :on => :create do |data,attr,value| | |
28 | - unless data.login.blank? || data.email.blank? | |
29 | - user = User.find_by_login_and_environment_id(data.login, data.environment_id) | |
30 | - if user.nil? | |
31 | - data.errors.add(:login, _('is invalid or user does not exists.')) | |
32 | - else | |
33 | - if user.email != data.email | |
34 | - data.errors.add(:email, _('does not match the username you filled in')) | |
35 | - end | |
36 | - end | |
37 | - end | |
38 | - end | |
39 | - | |
40 | - before_validation(:on => :create) do |change_password| | |
41 | - change_password.requestor = Person.find_by_identifier_and_environment_id(change_password.login, change_password.environment_id) | |
42 | - end | |
16 | + validates_presence_of :requestor | |
43 | 17 | |
44 | 18 | ################################################### |
45 | 19 | # validations for updating a ChangePassword task |
... | ... | @@ -49,6 +23,10 @@ class ChangePassword < Task |
49 | 23 | validates_presence_of :password_confirmation, :on => :update, :if => lambda { |change| change.status != Task::Status::CANCELLED } |
50 | 24 | validates_confirmation_of :password, :if => lambda { |change| change.status != Task::Status::CANCELLED } |
51 | 25 | |
26 | + def environment | |
27 | + requestor.environment unless requestor.nil? | |
28 | + end | |
29 | + | |
52 | 30 | def title |
53 | 31 | _("Change password") |
54 | 32 | end |
... | ... | @@ -87,12 +65,8 @@ class ChangePassword < Task |
87 | 65 | url = url_for(:host => hostname, :controller => 'account', :action => 'new_password', :code => code) |
88 | 66 | |
89 | 67 | proc do |
90 | - _("In order to change your password, please visit the following address:\n\n%s") % url | |
68 | + _("In order to change your password, please visit the following address:\n\n%s\n\nIf you did not required any change to your password just desconsider this email.") % url | |
91 | 69 | end |
92 | 70 | end |
93 | 71 | |
94 | - def environment | |
95 | - self.requestor.environment | |
96 | - end | |
97 | - | |
98 | 72 | end | ... | ... |
app/models/comment.rb
... | ... | @@ -16,9 +16,7 @@ class Comment < ActiveRecord::Base |
16 | 16 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
17 | 17 | belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id' |
18 | 18 | |
19 | - scope :without_spam, :conditions => ['spam IS NULL OR spam = ?', false] | |
20 | 19 | scope :without_reply, :conditions => ['reply_of_id IS NULL'] |
21 | - scope :spam, :conditions => ['spam = ?', true] | |
22 | 20 | |
23 | 21 | # unauthenticated authors: |
24 | 22 | validates_presence_of :name, :if => (lambda { |record| !record.email.blank? }) |
... | ... | @@ -29,7 +27,7 @@ class Comment < ActiveRecord::Base |
29 | 27 | validates_presence_of :author_id, :if => (lambda { |rec| rec.name.blank? && rec.email.blank? }) |
30 | 28 | validates_each :name do |rec,attribute,value| |
31 | 29 | if rec.author_id && (!rec.name.blank? || !rec.email.blank?) |
32 | - rec.errors.add(:name, _('%{fn} can only be informed for unauthenticated authors').fix_i18n) | |
30 | + rec.errors.add(:name, _('{fn} can only be informed for unauthenticated authors').fix_i18n) | |
33 | 31 | end |
34 | 32 | end |
35 | 33 | |
... | ... | @@ -104,10 +102,21 @@ class Comment < ActiveRecord::Base |
104 | 102 | end |
105 | 103 | |
106 | 104 | delegate :environment, :to => :profile |
107 | - delegate :profile, :to => :source | |
105 | + delegate :profile, :to => :source, :allow_nil => true | |
108 | 106 | |
109 | 107 | include Noosfero::Plugin::HotSpot |
110 | 108 | |
109 | + include Spammable | |
110 | + | |
111 | + def after_spam! | |
112 | + SpammerLogger.log(ip_address, self) | |
113 | + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam)) | |
114 | + end | |
115 | + | |
116 | + def after_ham! | |
117 | + Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham)) | |
118 | + end | |
119 | + | |
111 | 120 | def verify_and_notify |
112 | 121 | check_for_spam |
113 | 122 | unless spam? |
... | ... | @@ -115,10 +124,6 @@ class Comment < ActiveRecord::Base |
115 | 124 | end |
116 | 125 | end |
117 | 126 | |
118 | - def check_for_spam | |
119 | - plugins.dispatch(:check_comment_for_spam, self) | |
120 | - end | |
121 | - | |
122 | 127 | def notify_by_mail |
123 | 128 | if source.kind_of?(Article) && article.notify_comments? |
124 | 129 | if !notification_emails.empty? |
... | ... | @@ -171,37 +176,6 @@ class Comment < ActiveRecord::Base |
171 | 176 | @rejected = true |
172 | 177 | end |
173 | 178 | |
174 | - def spam? | |
175 | - !spam.nil? && spam | |
176 | - end | |
177 | - | |
178 | - def ham? | |
179 | - !spam.nil? && !spam | |
180 | - end | |
181 | - | |
182 | - def spam! | |
183 | - self.spam = true | |
184 | - self.save! | |
185 | - SpammerLogger.log(ip_address, self) | |
186 | - Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam)) | |
187 | - self | |
188 | - end | |
189 | - | |
190 | - def ham! | |
191 | - self.spam = false | |
192 | - self.save! | |
193 | - Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham)) | |
194 | - self | |
195 | - end | |
196 | - | |
197 | - def marked_as_spam | |
198 | - plugins.dispatch(:comment_marked_as_spam, self) | |
199 | - end | |
200 | - | |
201 | - def marked_as_ham | |
202 | - plugins.dispatch(:comment_marked_as_ham, self) | |
203 | - end | |
204 | - | |
205 | 179 | def need_moderation? |
206 | 180 | article.moderate_comments? && (author.nil? || article.author != author) |
207 | 181 | end | ... | ... |
app/models/create_enterprise.rb
... | ... | @@ -42,14 +42,14 @@ class CreateEnterprise < Task |
42 | 42 | def validator_correct_region |
43 | 43 | if self.region && self.target |
44 | 44 | unless self.region.validators.include?(self.target) || self.target_type == "Environment" |
45 | - self.errors.add(:target, _('%{fn} is not a validator for the chosen region').fix_i18n) | |
45 | + self.errors.add(:target, _('{fn} is not a validator for the chosen region').fix_i18n) | |
46 | 46 | end |
47 | 47 | end |
48 | 48 | end |
49 | 49 | |
50 | 50 | def not_used_identifier |
51 | 51 | if self.status != Task::Status::CANCELLED && self.identifier && Profile.exists?(:identifier => self.identifier) |
52 | - self.errors.add(:identifier, _('%{fn} is already being as identifier by another enterprise, organization or person.').fix_i18n) | |
52 | + self.errors.add(:identifier, _('{fn} is already being as identifier by another enterprise, organization or person.').fix_i18n) | |
53 | 53 | end |
54 | 54 | end |
55 | 55 | ... | ... |
app/models/domain.rb
... | ... | @@ -14,7 +14,7 @@ class Domain < ActiveRecord::Base |
14 | 14 | |
15 | 15 | # <tt>name</tt> must be sequences of alphanumeric characters (a to z, |
16 | 16 | # 0 to 9), plus '_' or '-', separated by dots. Letters must be lowercase. |
17 | - validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed of sequences of lowercase letters (a to z), numbers (0 to 9), "_" and "-", separated by dots.').fix_i18n | |
17 | + validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('{fn} must be composed of sequences of lowercase letters (a to z), numbers (0 to 9), "_" and "-", separated by dots.').fix_i18n | |
18 | 18 | |
19 | 19 | # checks validations that could not be expressed using Rails' predefined |
20 | 20 | # validations. In particular: |
... | ... | @@ -23,7 +23,7 @@ class Domain < ActiveRecord::Base |
23 | 23 | |
24 | 24 | def no_www |
25 | 25 | if self.name =~ /^www\./ |
26 | - self.errors.add(:name, _('%{fn} must not start with www.').fix_i18n) | |
26 | + self.errors.add(:name, _('{fn} must not start with www.').fix_i18n) | |
27 | 27 | end |
28 | 28 | end |
29 | 29 | ... | ... |
app/models/enterprise.rb
... | ... | @@ -135,7 +135,7 @@ class Enterprise < Organization |
135 | 135 | [ProfileImageBlock.new, LinkListBlock.new(:links => links)], |
136 | 136 | [] |
137 | 137 | ] |
138 | - if !environment.enabled?('disable_products_for_enterprises') | |
138 | + if environment.enabled?('products_for_enterprises') | |
139 | 139 | blocks[2].unshift ProductsBlock.new |
140 | 140 | end |
141 | 141 | blocks | ... | ... |
app/models/environment.rb
... | ... | @@ -97,7 +97,6 @@ class Environment < ActiveRecord::Base |
97 | 97 | 'disable_asset_communities' => _('Disable search for communities'), |
98 | 98 | 'disable_asset_products' => _('Disable search for products'), |
99 | 99 | 'disable_asset_events' => _('Disable search for events'), |
100 | - 'disable_products_for_enterprises' => _('Disable products for enterprises'), | |
101 | 100 | 'disable_categories' => _('Disable categories'), |
102 | 101 | 'disable_header_and_footer' => _('Disable header/footer editing by users'), |
103 | 102 | 'disable_gender_icon' => _('Disable gender icon'), |
... | ... | @@ -105,9 +104,13 @@ class Environment < ActiveRecord::Base |
105 | 104 | 'disable_select_city_for_contact' => _('Disable state/city select for contact form'), |
106 | 105 | 'disable_contact_person' => _('Disable contact for people'), |
107 | 106 | 'disable_contact_community' => _('Disable contact for groups/communities'), |
108 | - 'enterprise_registration' => _('Enterprise registration'), | |
109 | 107 | |
110 | - 'enterprise_activation' => _('Enable activation of enterprises'), | |
108 | + 'products_for_enterprises' => __('Enable products for enterprises'), | |
109 | + 'enterprise_registration' => __('Enterprise registration'), | |
110 | + 'enterprise_activation' => __('Enable activation of enterprises'), | |
111 | + 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'), | |
112 | + 'enterprises_are_validated_when_created' => __('Enterprises are validated when created'), | |
113 | + | |
111 | 114 | 'media_panel' => _('Media panel in WYSIWYG editor'), |
112 | 115 | 'select_preferred_domain' => _('Select preferred domains per profile'), |
113 | 116 | 'use_portal_community' => _('Use the portal as news source for front page'), |
... | ... | @@ -120,15 +123,15 @@ class Environment < ActiveRecord::Base |
120 | 123 | 'organizations_are_moderated_by_default' => _("Organizations have moderated publication by default"), |
121 | 124 | 'enable_organization_url_change' => _("Allow organizations to change their URL"), |
122 | 125 | 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), |
123 | - 'enterprises_are_disabled_when_created' => _('Enterprises are disabled when created'), | |
124 | - 'enterprises_are_validated_when_created' => _('Enterprises are validated when created'), | |
125 | 126 | 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), |
126 | 127 | 'xmpp_chat' => _('XMPP/Jabber based chat'), |
127 | 128 | 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'), |
128 | 129 | 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'), |
129 | 130 | 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'), |
130 | 131 | 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'), |
131 | - 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login') | |
132 | + 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'), | |
133 | + 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage'), | |
134 | + 'display_my_enterprises_on_user_menu' => _('Display on menu the list of enterprises the user can manage') | |
132 | 135 | } |
133 | 136 | end |
134 | 137 | |
... | ... | @@ -169,7 +172,7 @@ class Environment < ActiveRecord::Base |
169 | 172 | |
170 | 173 | # One Environment can be reached by many domains |
171 | 174 | has_many :domains, :as => :owner |
172 | - has_many :profiles | |
175 | + has_many :profiles, :dependent => :destroy | |
173 | 176 | |
174 | 177 | has_many :organizations |
175 | 178 | has_many :enterprises |
... | ... | @@ -277,7 +280,7 @@ class Environment < ActiveRecord::Base |
277 | 280 | settings_items :restrict_to_access_control_origins, :default => false |
278 | 281 | # Set this according to http://www.w3.org/TR/cors/. Headers are set at every response |
279 | 282 | # For multiple domains acts as suggested in http://stackoverflow.com/questions/1653308/access-control-allow-origin-multiple-origin-domains |
280 | - settings_items :access_control_allow_origin, :type => Array | |
283 | + settings_items :access_control_allow_origin, :type => Array, :default => [] | |
281 | 284 | settings_items :access_control_allow_methods, :type => String |
282 | 285 | |
283 | 286 | def news_amount_by_folder=(amount) |
... | ... | @@ -285,8 +288,9 @@ class Environment < ActiveRecord::Base |
285 | 288 | end |
286 | 289 | |
287 | 290 | # Enables a feature identified by its name |
288 | - def enable(feature) | |
291 | + def enable(feature, must_save=true) | |
289 | 292 | self.settings["#{feature}_enabled".to_sym] = true |
293 | + self.save! if must_save | |
290 | 294 | end |
291 | 295 | |
292 | 296 | def enable_plugin(plugin) |
... | ... | @@ -296,8 +300,9 @@ class Environment < ActiveRecord::Base |
296 | 300 | end |
297 | 301 | |
298 | 302 | # Disables a feature identified by its name |
299 | - def disable(feature) | |
303 | + def disable(feature, must_save=true) | |
300 | 304 | self.settings["#{feature}_enabled".to_sym] = false |
305 | + self.save! if must_save | |
301 | 306 | end |
302 | 307 | |
303 | 308 | def disable_plugin(plugin) |
... | ... | @@ -341,7 +346,7 @@ class Environment < ActiveRecord::Base |
341 | 346 | %w( |
342 | 347 | disable_asset_products |
343 | 348 | disable_gender_icon |
344 | - disable_products_for_enterprises | |
349 | + products_for_enterprises | |
345 | 350 | disable_select_city_for_contact |
346 | 351 | enterprise_registration |
347 | 352 | media_panel |
... | ... | @@ -349,7 +354,7 @@ class Environment < ActiveRecord::Base |
349 | 354 | show_balloon_with_profile_links_when_clicked |
350 | 355 | use_portal_community |
351 | 356 | ).each do |feature| |
352 | - enable(feature) | |
357 | + enable(feature, false) | |
353 | 358 | end |
354 | 359 | end |
355 | 360 | |
... | ... | @@ -802,13 +807,6 @@ class Environment < ActiveRecord::Base |
802 | 807 | self.save! |
803 | 808 | end |
804 | 809 | |
805 | - after_destroy :destroy_templates | |
806 | - def destroy_templates | |
807 | - [enterprise_template, inactive_enterprise_template, community_template, person_template].compact.each do |template| | |
808 | - template.destroy | |
809 | - end | |
810 | - end | |
811 | - | |
812 | 810 | after_create :create_default_licenses |
813 | 811 | def create_default_licenses |
814 | 812 | [ | ... | ... |
app/models/event.rb
... | ... | @@ -30,12 +30,30 @@ class Event < Article |
30 | 30 | |
31 | 31 | validates_each :start_date do |event,field,value| |
32 | 32 | if event.end_date && event.start_date && event.start_date > event.end_date |
33 | - event.errors.add(:start_date, _('%{fn} cannot come before end date.').fix_i18n) | |
33 | + event.errors.add(:start_date, _('{fn} cannot come before end date.').fix_i18n) | |
34 | 34 | end |
35 | 35 | end |
36 | 36 | |
37 | 37 | scope :by_day, lambda { |date| |
38 | - {:conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}]} | |
38 | + { :conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}], | |
39 | + :order => 'start_date ASC' | |
40 | + } | |
41 | + } | |
42 | + | |
43 | + scope :next_events_from_month, lambda { |date| | |
44 | + date_temp = date.strftime("%Y-%m-%d") | |
45 | + { :conditions => ["start_date >= ?","#{date_temp}"], | |
46 | + :limit => 10, | |
47 | + :order => 'start_date ASC' | |
48 | + } | |
49 | + } | |
50 | + | |
51 | + scope :by_month, lambda { |date| | |
52 | + date_temp = date.strftime("%Y-%m") | |
53 | + { :conditions => ["EXTRACT(YEAR FROM start_date) = ? AND EXTRACT(MONTH FROM start_date) = ?",date.year,date.month], | |
54 | + :limit => 10, | |
55 | + :order => 'start_date ASC' | |
56 | + } | |
39 | 57 | } |
40 | 58 | |
41 | 59 | include WhiteListFilter |
... | ... | @@ -112,7 +130,7 @@ class Event < Article |
112 | 130 | |
113 | 131 | # TODO: some good soul, please clean this ugly hack: |
114 | 132 | if self.body |
115 | - html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description') | |
133 | + html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description') | |
116 | 134 | end |
117 | 135 | } |
118 | 136 | ... | ... |
app/models/featured_products_block.rb
... | ... | @@ -7,8 +7,9 @@ class FeaturedProductsBlock < Block |
7 | 7 | |
8 | 8 | before_save do |block| |
9 | 9 | if block.owner.kind_of?(Environment) && block.product_ids.blank? |
10 | - seed = block.owner.products.count | |
11 | - block.product_ids = block.owner.highlighted_products_with_image(:offset => (rand(seed) % (seed - block.groups_of * 3)), :limit => block.groups_of * 3).map(&:id) | |
10 | + total = block.owner.products.count | |
11 | + offset = rand([(total - block.groups_of * 3) + 1, 1].max) | |
12 | + block.product_ids = block.owner.highlighted_products_with_image(:offset => offset, :limit => block.groups_of * 3).map(&:id) | |
12 | 13 | end |
13 | 14 | block.groups_of = block.groups_of.to_i |
14 | 15 | end | ... | ... |
app/models/image.rb
... | ... | @@ -17,7 +17,7 @@ class Image < ActiveRecord::Base |
17 | 17 | :icon => '20x20!' }, |
18 | 18 | :max_size => 5.megabytes # remember to update validate message below |
19 | 19 | |
20 | - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n | |
20 | + validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n | |
21 | 21 | |
22 | 22 | delay_attachment_fu_thumbnails |
23 | 23 | ... | ... |
app/models/link_list_block.rb
... | ... | @@ -35,6 +35,12 @@ class LinkListBlock < Block |
35 | 35 | ['chat', N_('Chat')] |
36 | 36 | ] |
37 | 37 | |
38 | + TARGET_OPTIONS = [ | |
39 | + [N_('Same page'), '_self'], | |
40 | + [N_('New tab'), '_blank'], | |
41 | + [N_('New window'), '_new'], | |
42 | + ] | |
43 | + | |
38 | 44 | settings_items :links, Array, :default => [] |
39 | 45 | |
40 | 46 | before_save do |block| |
... | ... | @@ -59,7 +65,7 @@ class LinkListBlock < Block |
59 | 65 | def link_html(link) |
60 | 66 | klass = 'icon-' + link[:icon] if link[:icon] |
61 | 67 | sanitize_link( |
62 | - link_to(link[:name], expand_address(link[:address]), :class => klass) | |
68 | + link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass) | |
63 | 69 | ) |
64 | 70 | end |
65 | 71 | ... | ... |
app/models/person.rb
... | ... | @@ -32,6 +32,10 @@ class Person < Profile |
32 | 32 | Profile.memberships_of(self) |
33 | 33 | end |
34 | 34 | |
35 | + def memberships_by_role(role) | |
36 | + memberships.where('role_assignments.role_id = ?', role.id) | |
37 | + end | |
38 | + | |
35 | 39 | has_many :friendships, :dependent => :destroy |
36 | 40 | has_many :friends, :class_name => 'Person', :through => :friendships |
37 | 41 | |
... | ... | @@ -61,6 +65,10 @@ class Person < Profile |
61 | 65 | scope :abusers, :joins => :abuse_complaints, :conditions => ['tasks.status = 3'], :select => 'DISTINCT profiles.*' |
62 | 66 | scope :non_abusers, :joins => "LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'", :conditions => ["tasks.status != 3 OR tasks.id is NULL"], :select => "DISTINCT profiles.*" |
63 | 67 | |
68 | + scope :admins, :joins => [:role_assignments => :role], :conditions => ['roles.key = ?', 'environment_administrator' ] | |
69 | + scope :activated, :joins => :user, :conditions => ['users.activation_code IS NULL AND users.activated_at IS NOT NULL'] | |
70 | + scope :deactivated, :joins => :user, :conditions => ['NOT (users.activation_code IS NULL AND users.activated_at IS NOT NULL)'] | |
71 | + | |
64 | 72 | after_destroy do |person| |
65 | 73 | Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy } |
66 | 74 | end |
... | ... | @@ -230,7 +238,7 @@ class Person < Profile |
230 | 238 | |
231 | 239 | validates_each :email, :on => :update do |record,attr,value| |
232 | 240 | if User.find(:first, :conditions => ['email = ? and id != ? and environment_id = ?', value, record.user.id, record.environment.id]) |
233 | - record.errors.add(attr, _('%{fn} is already used by other user').fix_i18n) | |
241 | + record.errors.add(attr, _('{fn} is already used by other user').fix_i18n) | |
234 | 242 | end |
235 | 243 | end |
236 | 244 | |
... | ... | @@ -458,11 +466,19 @@ class Person < Profile |
458 | 466 | end |
459 | 467 | |
460 | 468 | def activities |
461 | - 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") | |
469 | + 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' and action_tracker.verb != 'reply_scrap_on_self' ORDER BY updated_at DESC") | |
462 | 470 | end |
463 | 471 | |
472 | + # by default, all fields are private | |
464 | 473 | def public_fields |
465 | - self.fields_privacy.nil? ? self.active_fields : self.fields_privacy.reject{ |k, v| v != 'public' }.keys.map(&:to_s) | |
474 | + self.fields_privacy.nil? ? [] : self.fields_privacy.reject{ |k, v| v != 'public' }.keys.map(&:to_s) | |
475 | + end | |
476 | + | |
477 | + include Noosfero::Gravatar | |
478 | + | |
479 | + def profile_custom_icon(gravatar_default=nil) | |
480 | + (self.image.present? && self.image.public_filename(:icon)) || | |
481 | + gravatar_profile_image_url(self.email, :size=>20, :d => gravatar_default) | |
466 | 482 | end |
467 | 483 | |
468 | 484 | protected | ... | ... |
app/models/price_detail.rb
... | ... | @@ -6,11 +6,11 @@ class PriceDetail < ActiveRecord::Base |
6 | 6 | validates_presence_of :product_id |
7 | 7 | |
8 | 8 | belongs_to :production_cost |
9 | - validates_presence_of :production_cost | |
9 | + # Do not validates_presence_of production_cost. We may have undefined other costs. | |
10 | 10 | validates_uniqueness_of :production_cost_id, :scope => :product_id |
11 | 11 | |
12 | 12 | def name |
13 | - production_cost.name | |
13 | + production_cost.nil? ? _('Other costs') : production_cost.name | |
14 | 14 | end |
15 | 15 | |
16 | 16 | def price | ... | ... |
app/models/product.rb
... | ... | @@ -205,11 +205,13 @@ class Product < ActiveRecord::Base |
205 | 205 | (price - total_production_cost.to_f).zero? |
206 | 206 | end |
207 | 207 | |
208 | - def update_price_details(price_details) | |
209 | - self.price_details.destroy_all | |
210 | - price_details.each do |price_detail| | |
211 | - self.price_details.create(price_detail) | |
208 | + def update_price_details(new_price_details) | |
209 | + price_details.destroy_all | |
210 | + new_price_details.each do |detail| | |
211 | + price_details.create(detail) | |
212 | 212 | end |
213 | + reload # to remove temporary duplicated price_details | |
214 | + price_details | |
213 | 215 | end |
214 | 216 | |
215 | 217 | def price_description_percentage | ... | ... |
app/models/profile.rb
... | ... | @@ -86,7 +86,8 @@ class Profile < ActiveRecord::Base |
86 | 86 | #FIXME: these will work only if the subclass is already loaded |
87 | 87 | scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} } |
88 | 88 | scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} } |
89 | - scope :templates, lambda { |environment| { :conditions => {:is_template => true, :environment_id => environment.id} } } | |
89 | + scope :templates, {:conditions => {:is_template => true}} | |
90 | + scope :no_templates, {:conditions => {:is_template => false}} | |
90 | 91 | |
91 | 92 | def members |
92 | 93 | scopes = plugins.dispatch_scopes(:organization_members, self) |
... | ... | @@ -98,6 +99,14 @@ class Profile < ActiveRecord::Base |
98 | 99 | members.count |
99 | 100 | end |
100 | 101 | |
102 | + class << self | |
103 | + def count_with_distinct(*args) | |
104 | + options = args.last || {} | |
105 | + count_without_distinct(:id, {:distinct => true}.merge(options)) | |
106 | + end | |
107 | + alias_method_chain :count, :distinct | |
108 | + end | |
109 | + | |
101 | 110 | def members_by_role(role) |
102 | 111 | Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id]) |
103 | 112 | end |
... | ... | @@ -111,6 +120,7 @@ class Profile < ActiveRecord::Base |
111 | 120 | end |
112 | 121 | |
113 | 122 | scope :visible, :conditions => { :visible => true } |
123 | + scope :public, :conditions => { :visible => true, :public_profile => true } | |
114 | 124 | # Subclasses must override these methods |
115 | 125 | scope :more_popular |
116 | 126 | scope :more_active |
... | ... | @@ -187,7 +197,7 @@ class Profile < ActiveRecord::Base |
187 | 197 | |
188 | 198 | has_many :tasks, :dependent => :destroy, :as => 'target' |
189 | 199 | |
190 | - has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name' | |
200 | + has_many :events, :source => 'articles', :class_name => 'Event', :order => 'start_date' | |
191 | 201 | |
192 | 202 | def find_in_all_tasks(task_id) |
193 | 203 | begin |
... | ... | @@ -220,12 +230,14 @@ class Profile < ActiveRecord::Base |
220 | 230 | |
221 | 231 | belongs_to :region |
222 | 232 | |
233 | + LOCATION_FIELDS = %w[address district city state country_name zip_code] | |
234 | + | |
223 | 235 | def location(separator = ' - ') |
224 | 236 | myregion = self.region |
225 | 237 | if myregion |
226 | 238 | myregion.hierarchy.reverse.first(2).map(&:name).join(separator) |
227 | 239 | else |
228 | - %w[address district city state country_name zip_code ].map {|item| (self.respond_to?(item) && !self.send(item).blank?) ? self.send(item) : nil }.compact.join(separator) | |
240 | + LOCATION_FIELDS.map {|item| (self.respond_to?(item) && !self.send(item).blank?) ? self.send(item) : nil }.compact.join(separator) | |
229 | 241 | end |
230 | 242 | end |
231 | 243 | |
... | ... | @@ -292,7 +304,7 @@ class Profile < ActiveRecord::Base |
292 | 304 | validate :valid_template |
293 | 305 | |
294 | 306 | def valid_template |
295 | - if template_id.present? and !template.is_template | |
307 | + if template_id.present? && template && !template.is_template | |
296 | 308 | errors.add(:template, _('is not a template.')) |
297 | 309 | end |
298 | 310 | end |
... | ... | @@ -843,8 +855,10 @@ private :generate_url, :url_options |
843 | 855 | }[amount] || _("%s members") % amount |
844 | 856 | end |
845 | 857 | |
846 | - def profile_custom_icon | |
847 | - self.image.public_filename(:icon) unless self.image.blank? | |
858 | + include Noosfero::Gravatar | |
859 | + | |
860 | + def profile_custom_icon(gravatar_default=nil) | |
861 | + image.public_filename(:icon) if image.present? | |
848 | 862 | end |
849 | 863 | |
850 | 864 | def jid(options = {}) |
... | ... | @@ -883,6 +897,21 @@ private :generate_url, :url_options |
883 | 897 | [] |
884 | 898 | end |
885 | 899 | |
900 | + def may_display_field_to? field, user = nil | |
901 | + if not self.active_fields.include? field.to_s | |
902 | + self.send "may_display_#{field}_to?", user rescue true | |
903 | + else | |
904 | + not (!self.public_fields.include? field.to_s and (!user or (user != self and !user.is_a_friend?(self)))) | |
905 | + end | |
906 | + end | |
907 | + | |
908 | + def may_display_location_to? user = nil | |
909 | + LOCATION_FIELDS.each do |field| | |
910 | + return false if !self.may_display_field_to? field, user | |
911 | + end | |
912 | + return true | |
913 | + end | |
914 | + | |
886 | 915 | # field => privacy (e.g.: "address" => "public") |
887 | 916 | def fields_privacy |
888 | 917 | self.data[:fields_privacy] | ... | ... |
app/models/profile_list_block.rb
... | ... | @@ -56,7 +56,7 @@ class ProfileListBlock < Block |
56 | 56 | list = content_tag 'ul', nl +' '+ list + nl |
57 | 57 | end |
58 | 58 | block_title(title) + nl + |
59 | - content_tag('div', nl + list + nl + content_tag('br', '', :style => 'clear:both')) | |
59 | + content_tag('div', nl + list + nl + tag('br', :style => 'clear:both')) | |
60 | 60 | end |
61 | 61 | end |
62 | 62 | ... | ... |
app/models/raw_html_block.rb
app/models/recent_documents_block.rb
... | ... | @@ -32,8 +32,7 @@ class RecentDocumentsBlock < Block |
32 | 32 | end |
33 | 33 | end |
34 | 34 | |
35 | - def docs | |
36 | - self.limit.nil? ? owner.recent_documents(nil, {}, false) : owner.recent_documents(self.limit, {}, false) | |
35 | + def self.expire_on | |
36 | + { :profile => [:article], :environment => [:article] } | |
37 | 37 | end |
38 | - | |
39 | 38 | end | ... | ... |
app/models/region.rb
... | ... | @@ -11,9 +11,9 @@ class Region < Category |
11 | 11 | validators.count > 0 |
12 | 12 | end |
13 | 13 | |
14 | - scope :with_validators, :group => 'id', | |
14 | + scope :with_validators, :select => 'DISTINCT ON (categories.id) *', | |
15 | 15 | :joins => 'INNER JOIN region_validators on (region_validators.region_id = categories.id)' |
16 | - | |
16 | + | |
17 | 17 | end |
18 | 18 | |
19 | 19 | require_dependency 'city' | ... | ... |
app/models/scrap.rb
... | ... | @@ -17,9 +17,11 @@ class Scrap < ActiveRecord::Base |
17 | 17 | |
18 | 18 | scope :not_replies, :conditions => {:scrap_id => nil} |
19 | 19 | |
20 | - track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.receiver != s.sender}, :custom_target => :action_tracker_target | |
20 | + track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.sender != s.receiver && s.sender != s.top_root.receiver}, :custom_target => :action_tracker_target | |
21 | 21 | |
22 | - track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.receiver == s.sender} | |
22 | + track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender == s.receiver} | |
23 | + | |
24 | + track_actions :reply_scrap_on_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender != s.receiver && s.sender == s.top_root.receiver} | |
23 | 25 | |
24 | 26 | after_create do |scrap| |
25 | 27 | scrap.root.update_attribute('updated_at', DateTime.now) unless scrap.root.nil? |
... | ... | @@ -28,6 +30,12 @@ class Scrap < ActiveRecord::Base |
28 | 30 | |
29 | 31 | before_validation :strip_all_html_tags |
30 | 32 | |
33 | + def top_root | |
34 | + scrap = self | |
35 | + scrap = Scrap.find(scrap.scrap_id) while scrap.scrap_id | |
36 | + scrap | |
37 | + end | |
38 | + | |
31 | 39 | def strip_all_html_tags |
32 | 40 | sanitizer = HTML::WhiteListSanitizer.new |
33 | 41 | self.content = sanitizer.sanitize(self.content, :tags => []) | ... | ... |
app/models/spammer_logger.rb
... | ... | @@ -6,6 +6,8 @@ class SpammerLogger < Logger |
6 | 6 | if object |
7 | 7 | if object.kind_of?(Comment) |
8 | 8 | @logger << "[#{Time.now.strftime('%F %T %z')}] Comment-id: #{object.id} IP: #{spammer_ip}\n" |
9 | + elsif object.kind_of?(SuggestArticle) | |
10 | + @logger << "[#{Time.now.strftime('%F %T %z')}] SuggestArticle-id: #{object.id} IP: #{spammer_ip}\n" | |
9 | 11 | end |
10 | 12 | else |
11 | 13 | @logger << "[#{Time.now.strftime('%F %T %z')}] IP: #{spammer_ip}\n" | ... | ... |
app/models/suggest_article.rb
... | ... | @@ -11,6 +11,17 @@ class SuggestArticle < Task |
11 | 11 | settings_items :source, :type => String |
12 | 12 | settings_items :source_name, :type => String |
13 | 13 | settings_items :highlighted, :type => :boolean, :default => false |
14 | + settings_items :ip_address, :type => String | |
15 | + settings_items :user_agent, :type => String | |
16 | + settings_items :referrer, :type => String | |
17 | + | |
18 | + after_create :schedule_spam_checking | |
19 | + | |
20 | + def schedule_spam_checking | |
21 | + self.delay.check_for_spam | |
22 | + end | |
23 | + | |
24 | + include Noosfero::Plugin::HotSpot | |
14 | 25 | |
15 | 26 | def sender |
16 | 27 | "#{name} (#{email})" |
... | ... | @@ -61,4 +72,12 @@ class SuggestArticle < Task |
61 | 72 | _('You need to login on %{system} in order to approve or reject this article.') % { :system => target.environment.name } |
62 | 73 | end |
63 | 74 | |
75 | + def after_spam! | |
76 | + SpammerLogger.log(ip_address, self) | |
77 | + self.delay.marked_as_spam | |
78 | + end | |
79 | + | |
80 | + def after_ham! | |
81 | + self.delay.marked_as_ham | |
82 | + end | |
64 | 83 | end | ... | ... |
app/models/tags_block.rb
app/models/task.rb
... | ... | @@ -258,6 +258,8 @@ class Task < ActiveRecord::Base |
258 | 258 | status == Task::Status::ACTIVE || status == Task::Status::HIDDEN |
259 | 259 | end |
260 | 260 | |
261 | + include Spammable | |
262 | + | |
261 | 263 | protected |
262 | 264 | |
263 | 265 | # This method must be overrided in subclasses, and its implementation must do | ... | ... |
app/models/uploaded_file.rb
... | ... | @@ -45,7 +45,25 @@ class UploadedFile < Article |
45 | 45 | end |
46 | 46 | |
47 | 47 | def self.max_size |
48 | - UploadedFile.attachment_options[:max_size] | |
48 | + default = 5.megabytes | |
49 | + | |
50 | + multipliers = { | |
51 | + :KB => :kilobytes, | |
52 | + :MB => :megabytes, | |
53 | + :GB => :gigabytes, | |
54 | + :TB => :terabytes, | |
55 | + } | |
56 | + max_upload_size = NOOSFERO_CONF['max_upload_size'] | |
57 | + | |
58 | + if max_upload_size =~ /^(\d+(\.\d+)?)\s*(KB|MB|GB|TB)?$/ | |
59 | + number = $1.to_f | |
60 | + unit = $3 || :MB | |
61 | + multiplier = multipliers[unit.to_sym] | |
62 | + | |
63 | + number.send(multiplier).to_i | |
64 | + else | |
65 | + default | |
66 | + end | |
49 | 67 | end |
50 | 68 | |
51 | 69 | # FIXME need to define min/max file size |
... | ... | @@ -56,20 +74,28 @@ class UploadedFile < Article |
56 | 74 | has_attachment :storage => :file_system, |
57 | 75 | :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' }, |
58 | 76 | :thumbnail_class => Thumbnail, |
59 | - :max_size => 5.megabytes # remember to update validate message below | |
77 | + :max_size => self.max_size | |
60 | 78 | |
61 | - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n | |
79 | + validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n | |
62 | 80 | |
63 | 81 | delay_attachment_fu_thumbnails |
64 | 82 | |
65 | 83 | postgresql_attachment_fu |
66 | 84 | |
85 | + # Use this method only to get the generic icon for this kind of content. | |
86 | + # If you want the specific icon for a file type or the iconified version | |
87 | + # of an image, use FilePresenter.for(uploaded_file).icon_name | |
67 | 88 | def self.icon_name(article = nil) |
68 | - if article | |
69 | - article.image? ? article.public_filename(:icon) : (article.mime_type ? article.mime_type.gsub(/[\/+.]/, '-') : 'upload-file') | |
70 | - else | |
71 | - 'upload-file' | |
89 | + unless article.nil? | |
90 | + warn = ('='*80) + "\n" + | |
91 | + 'The method `UploadedFile.icon_name(obj)` is deprecated. ' + | |
92 | + 'You must to encapsulate UploadedFile with `FilePresenter.for()`.' + | |
93 | + "\n" + ('='*80) | |
94 | + raise NoMethodError, warn if ENV['RAILS_ENV'] == 'test' | |
95 | + Rails.logger.warn warn if Rails.logger | |
96 | + puts warn if ENV['RAILS_ENV'] == 'development' | |
72 | 97 | end |
98 | + 'upload-file' | |
73 | 99 | end |
74 | 100 | |
75 | 101 | def mime_type |
... | ... | @@ -90,45 +116,38 @@ class UploadedFile < Article |
90 | 116 | self.name = self.filename |
91 | 117 | end |
92 | 118 | |
119 | + def download_headers | |
120 | + { | |
121 | + 'Content-Disposition' => "attachment; filename=\"#{self.filename}\"", | |
122 | + } | |
123 | + end | |
124 | + | |
93 | 125 | def data |
94 | 126 | File.read(self.full_filename) |
95 | 127 | end |
96 | 128 | |
97 | 129 | def to_html(options = {}) |
130 | + warn = ('='*80) + "\n" + | |
131 | + 'The method `UploadedFile#to_html()` is deprecated. ' + | |
132 | + 'You must to encapsulate UploadedFile with `FilePresenter.for()`.' + | |
133 | + "\n" + ('='*80) | |
134 | + raise NoMethodError, warn if ENV['RAILS_ENV'] == 'test' | |
135 | + Rails.logger.warn warn if Rails.logger | |
136 | + puts warn if ENV['RAILS_ENV'] == 'development' | |
98 | 137 | article = self |
99 | 138 | if image? |
100 | 139 | proc do |
101 | - if article.gallery? && options[:gallery_view] | |
102 | - images = article.parent.images | |
103 | - current_index = images.index(article) | |
104 | - total_of_images = images.count | |
105 | - | |
106 | - link_to_previous = if current_index >= 1 | |
107 | - link_to(_('« Previous'), images[current_index - 1].view_url, :class => 'left') | |
108 | - else | |
109 | - content_tag('span', _('« Previous'), :class => 'left') | |
110 | - end | |
111 | - | |
112 | - link_to_next = if current_index < total_of_images - 1 | |
113 | - link_to(_('Next »'), images[current_index + 1].view_url, :class => 'right') | |
114 | - else | |
115 | - content_tag('span', _('Next »'), :class => 'right') | |
116 | - end | |
117 | - | |
118 | - content_tag( | |
119 | - 'div', | |
120 | - link_to_previous + (content_tag('span', _('image %d of %d'), :class => 'total-of-images') % [current_index + 1, total_of_images]).html_safe + link_to_next, | |
121 | - :class => 'gallery-navigation' | |
122 | - ) | |
123 | - end.to_s + | |
124 | - image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') + | |
125 | - content_tag('p', article.abstract, :class => 'uploaded-file-description') | |
126 | - | |
140 | + image_tag(article.public_filename(:display), | |
141 | + :class => article.css_class_name, | |
142 | + :style => 'max-width: 100%') + | |
143 | + content_tag('div', article.abstract, :class => 'uploaded-file-description') | |
127 | 144 | end |
128 | 145 | else |
129 | 146 | proc do |
130 | - content_tag('ul', content_tag('li', link_to(article.name, article.url, :class => article.css_class_name))) + | |
131 | - content_tag('p', article.abstract, :class => 'uploaded-file-description') | |
147 | + content_tag('div', | |
148 | + link_to(article.name, article.url), | |
149 | + :class => article.css_class_name) + | |
150 | + content_tag('div', article.abstract, :class => 'uploaded-file-description') | |
132 | 151 | end |
133 | 152 | end |
134 | 153 | end | ... | ... |
app/models/user.rb
... | ... | @@ -89,7 +89,7 @@ class User < ActiveRecord::Base |
89 | 89 | before_save :encrypt_password |
90 | 90 | validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?}) |
91 | 91 | |
92 | - validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('%{fn} must be checked in order to signup.').fix_i18n | |
92 | + validates_inclusion_of :terms_accepted, :in => [ '1' ], :if => lambda { |u| ! u.terms_of_use.blank? }, :message => N_('{fn} must be checked in order to signup.').fix_i18n | |
93 | 93 | |
94 | 94 | # Authenticates a user by their login name or email and unencrypted password. Returns the user or nil. |
95 | 95 | def self.authenticate(login, password, environment = nil) |
... | ... | @@ -118,6 +118,21 @@ class User < ActiveRecord::Base |
118 | 118 | end |
119 | 119 | end |
120 | 120 | |
121 | + # Deactivates the user in the database. | |
122 | + def deactivate | |
123 | + return false unless self.person | |
124 | + self.activated_at = nil | |
125 | + self.person.visible = false | |
126 | + begin | |
127 | + self.person.save! && self.save! | |
128 | + rescue Exception => exception | |
129 | + logger.error(exception.to_s) | |
130 | + false | |
131 | + else | |
132 | + true | |
133 | + end | |
134 | + end | |
135 | + | |
121 | 136 | def activated? |
122 | 137 | self.activation_code.nil? && !self.activated_at.nil? |
123 | 138 | end |
... | ... | @@ -250,19 +265,21 @@ class User < ActiveRecord::Base |
250 | 265 | end |
251 | 266 | end |
252 | 267 | |
253 | - def data_hash | |
268 | + def data_hash(gravatar_default = nil) | |
254 | 269 | friends_list = {} |
255 | 270 | enterprises = person.enterprises.map { |e| { 'name' => e.short_name, 'identifier' => e.identifier } } |
256 | 271 | self.person.friends.online.map do |person| |
257 | 272 | friends_list[person.identifier] = { |
258 | - 'avatar' => person.profile_custom_icon, | |
273 | + 'avatar' => person.profile_custom_icon(gravatar_default), | |
259 | 274 | 'name' => person.short_name, |
260 | 275 | 'jid' => person.full_jid, |
261 | 276 | 'status' => person.user.chat_status, |
262 | 277 | } |
263 | 278 | end |
279 | + | |
264 | 280 | { |
265 | 281 | 'login' => self.login, |
282 | + 'avatar' => self.person.profile_custom_icon(gravatar_default), | |
266 | 283 | 'is_admin' => self.person.is_admin?, |
267 | 284 | 'since_month' => self.person.created_at.month, |
268 | 285 | 'since_year' => self.person.created_at.year, | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
1 | +class FilePresenter::Image < FilePresenter | |
2 | + def self.accepts?(f) | |
3 | + return nil unless f.respond_to? :image? | |
4 | + f.image? ? 10 : nil | |
5 | + end | |
6 | + | |
7 | + def icon_name | |
8 | + public_filename :icon | |
9 | + end | |
10 | + | |
11 | + def short_description | |
12 | + _('Image (%s)') % content_type.split('/')[1].upcase | |
13 | + end | |
14 | +end | ... | ... |
app/sweepers/article_sweeper.rb
... | ... | @@ -16,15 +16,15 @@ class ArticleSweeper < ActiveRecord::Observer |
16 | 16 | end |
17 | 17 | end |
18 | 18 | |
19 | + | |
19 | 20 | protected |
20 | 21 | |
21 | 22 | def expire_caches(article) |
23 | + expire_blocks_cache(article.profile, [:article]) | |
24 | + | |
22 | 25 | return if !article.environment |
26 | + | |
23 | 27 | article.hierarchy(true).each { |a| a.touch if a != article } |
24 | - blocks = article.profile.blocks | |
25 | - blocks += article.profile.environment.blocks if article.profile.environment | |
26 | - blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}} | |
27 | - BlockSweeper.expire_blocks(blocks) | |
28 | 28 | env = article.profile.environment |
29 | 29 | if env && (env.portal_community == article.profile) |
30 | 30 | article.environment.locales.keys.each do |locale| | ... | ... |
app/sweepers/category_sweeper.rb
... | ... | @@ -3,7 +3,13 @@ class CategorySweeper < ActiveRecord::Observer |
3 | 3 | include SweeperHelper |
4 | 4 | |
5 | 5 | def after_save(category) |
6 | + expire_blocks_cache(category.environment, [:category]) | |
7 | + | |
8 | + # Needed for environments with application layout | |
6 | 9 | expire_fragment(category.environment.id.to_s + "_categories_menu") |
7 | 10 | end |
8 | 11 | |
12 | + def after_destroy(category) | |
13 | + expire_blocks_cache(category.environment, [:category]) | |
14 | + end | |
9 | 15 | end | ... | ... |
app/sweepers/profile_sweeper.rb
app/views/account/_signup_form.html.erb
... | ... | @@ -101,7 +101,7 @@ |
101 | 101 | |
102 | 102 | <%= @plugins.dispatch(:signup_extra_contents).collect { |content| instance_eval(&content) }.join("") %> |
103 | 103 | |
104 | - <%= template_options(Person, 'profile_data') %> | |
104 | + <%= template_options(:people, 'profile_data') %> | |
105 | 105 | |
106 | 106 | <% unless @terms_of_use.blank? %> |
107 | 107 | <div id='terms-of-use-box' class='formfieldline'> | ... | ... |
app/views/account/forgot_password.html.erb
... | ... | @@ -2,21 +2,13 @@ |
2 | 2 | |
3 | 3 | <%= error_messages_for :change_password, :header_message => _('Instructions to password recovery could not be sent'), :message => nil %> |
4 | 4 | |
5 | -<%= labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %> | |
6 | - | |
7 | - <%= f.text_field :login, | |
8 | - :onchange => 'this.value = convToValidUsername( this.value )' %> | |
9 | - | |
10 | - <%= f.text_field :email %> | |
11 | - | |
12 | - <%= f.hidden_field :environment_id, :value => environment.id %> | |
13 | - | |
14 | -<div> | |
15 | - <% button_bar do %> | |
16 | - <%= submit_button('send', _('Send instructions')) %> | |
17 | - <% end %> | |
18 | -</div> | |
19 | -<%= content_tag(:small,_('After clicking the button above, you will receive an email with a link to a page where you will be able to create a new password.')) %> | |
20 | - | |
5 | +<% form_tag do %> | |
6 | + <%= labelled_form_field fields_label, text_field_tag(:value) %> | |
7 | + | |
8 | + <div> | |
9 | + <% button_bar do %> | |
10 | + <%= submit_button('send', _('Send instructions')) %> | |
11 | + <% end %> | |
12 | + </div> | |
13 | + <%= content_tag(:small,_('After clicking the button above, you will receive an email with a link to a page where you will be able to create a new password.')) %> | |
21 | 14 | <% end %> |
22 | - | ... | ... |
app/views/blocks/location.html.erb
1 | 1 | <% if profile.lat %> |
2 | 2 | <%= block_title block.title %> |
3 | 3 | <div class='the-localization-map'> |
4 | - <img src="http://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/> | |
4 | + <img src="https://maps.google.com/maps/api/staticmap?center=<%=profile.lat%>,<%=profile.lng%>&zoom=<%=block.zoom%>&size=190x250&maptype=<%=block.map_type%>&markers=<%=profile.lat%>,<%=profile.lng%>&sensor=false"/> | |
5 | 5 | </div> |
6 | 6 | </div> |
7 | 7 | <% else %> | ... | ... |
app/views/blocks/profile_info.html.erb
... | ... | @@ -17,7 +17,7 @@ |
17 | 17 | <ul class="profile-info-data" id="profile-info-data-<%= block.id %>"> |
18 | 18 | <li><%= link_to _('Homepage'), block.owner.url, :class => 'url' %></li> |
19 | 19 | <li><%= link_to _('View profile'), block.owner.public_profile_url %></li> |
20 | - <% if block.owner.enterprise? && !block.owner.environment.enabled?('disable_products_for_enterprises') %> | |
20 | + <% if block.owner.enterprise? && block.owner.environment.enabled?('products_for_enterprises') %> | |
21 | 21 | <li><%= link_to(_('Products/Services'), :controller => 'catalog', :profile => block.owner.identifier) %></li> |
22 | 22 | <% end %> |
23 | 23 | <li id="profile-admin-url-<%= block.id %>"></li> | ... | ... |
app/views/box_organizer/_article_block.html.erb
1 | 1 | <div class="article-block-edition"> |
2 | -<% if @block.box.owner.kind_of?(Environment) and @block.box.owner.portal_community.nil? %> | |
2 | +<% if @block.owner.kind_of?(Environment) and @block.owner.portal_community.nil? %> | |
3 | 3 | <p id="no_portal_community"> |
4 | 4 | <%= _("You don't have an community defined as the portal community. Define it before use this block properly.") %> |
5 | 5 | </p> | ... | ... |
app/views/box_organizer/_link_list_block.html.erb
1 | 1 | <strong><%= _('Links') %></strong> |
2 | 2 | <div id='edit-link-list-block' style='width:450px'> |
3 | 3 | <table id='links' class='noborder'> |
4 | - <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th></tr> | |
4 | + <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th><th><%= _('Target') %></th></tr> | |
5 | 5 | <% for link in @block.links do %> |
6 | 6 | <tr> |
7 | 7 | <td> |
... | ... | @@ -9,6 +9,9 @@ |
9 | 9 | </td> |
10 | 10 | <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td> |
11 | 11 | <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td> |
12 | + <td> | |
13 | + <%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %> | |
14 | + </td> | |
12 | 15 | </tr> |
13 | 16 | <% end %> |
14 | 17 | </table> |
... | ... | @@ -18,7 +21,9 @@ |
18 | 21 | page.insert_html :bottom, 'links', content_tag('tr', |
19 | 22 | content_tag('td', icon_selector('ok')) + |
20 | 23 | content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) + |
21 | - content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'cel-address')) | |
24 | + content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'link-address'), :class => 'cel-address') + | |
25 | + content_tag('td', select_tag('block[links][][target]', | |
26 | +options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target]))) | |
22 | 27 | ) + |
23 | 28 | javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight") |
24 | 29 | end %> | ... | ... |
app/views/catalog/index.html.erb
... | ... | @@ -92,7 +92,7 @@ |
92 | 92 | <% end %> |
93 | 93 | <% product.price_details.each do |i| %> |
94 | 94 | <div class="search-product-input-dots-to-price"> |
95 | - <div class="search-product-input-name"><%= i.production_cost.name %></div> | |
95 | + <div class="search-product-input-name"><%= i.name %></div> | |
96 | 96 | <%= price_span i.price, :class => 'search-product-input-price' %> |
97 | 97 | </div> |
98 | 98 | <% end %> | ... | ... |
app/views/cms/_blog.html.erb
... | ... | @@ -54,6 +54,15 @@ |
54 | 54 | |
55 | 55 | <%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 10)) %> |
56 | 56 | |
57 | +<% f.fields_for :image_builder, @article.image do |i| %> | |
58 | + <%= file_field_or_thumbnail(_('Cover image:'), @article.image, i)%> | |
59 | + <%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %> | |
60 | +<% end %> | |
61 | + | |
62 | +<% unless @article.image.nil? %> | |
63 | + <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%> | |
64 | +<% end %> | |
65 | + | |
57 | 66 | <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %> |
58 | 67 | |
59 | 68 | <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %> | ... | ... |
app/views/cms/view.html.erb
... | ... | @@ -2,6 +2,18 @@ |
2 | 2 | <%= _('Content management') %> |
3 | 3 | </h1> |
4 | 4 | |
5 | +<% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %> | |
6 | + <div class="cms-homepage"> | |
7 | + <%= _('Profile homepage:') %> | |
8 | + <% if profile.home_page %> | |
9 | + <%= link_to_article(profile.home_page) %> | |
10 | + <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %> | |
11 | + <% else %> | |
12 | + <span class="cms-homepage-default"><%= _('Profile Information') %></span> | |
13 | + <% end %> | |
14 | + </div> | |
15 | +<% end %> | |
16 | + | |
5 | 17 | <% button_bar(:style => 'margin-bottom: 1em;') do %> |
6 | 18 | <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %> |
7 | 19 | |
... | ... | @@ -40,20 +52,27 @@ |
40 | 52 | </tr> |
41 | 53 | <% end %> |
42 | 54 | |
43 | - <% @articles.each do |article| %> | |
44 | - <tr> | |
45 | - <td> | |
55 | + <% @articles.each do |article| article = FilePresenter.for article %> | |
56 | + <tr title="<%= article.title%>" > | |
57 | + <td class="article-name"> | |
46 | 58 | <%= link_to_article(article) %> |
47 | 59 | </td> |
48 | - <td> | |
49 | - <%= article.class.short_description %> | |
60 | + <% short_description = article.respond_to?(:short_description) ? | |
61 | + article.short_description : | |
62 | + article.class.short_description %> | |
63 | + <td class="article-mime" title=<%= short_description.to_json %>> | |
64 | + <%= short_description %> | |
50 | 65 | </td> |
51 | 66 | <td class="article-controls"> |
52 | 67 | <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %> |
53 | 68 | <%= button_without_text :eyes, _('Public view'), article.view_url %> |
54 | 69 | <%= display_spread_button(profile, article) unless article.folder? || remove_content_button(:spread)%> |
55 | 70 | <% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %> |
56 | - <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %> | |
71 | + <% if profile.home_page != article %> | |
72 | + <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %> | |
73 | + <% else %> | |
74 | + <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %> | |
75 | + <% end %> | |
57 | 76 | <% end %> |
58 | 77 | <%= display_delete_button(article) if !remove_content_button(:delete) %> |
59 | 78 | </td> | ... | ... |
app/views/comment/_comment.rhtml
... | ... | @@ -13,11 +13,11 @@ |
13 | 13 | <% else %> |
14 | 14 | <% url_image, status_class = comment.author_id ? |
15 | 15 | [comment.removed_user_image, 'icon-user-removed'] : |
16 | - [str_gravatar_url_for( comment.email, :size => 50, :d=>404 ), 'icon-user-unknown'] %> | |
16 | + [gravatar_profile_image_url( comment.email, :size => 50, :d=>404 ), 'icon-user-unknown'] %> | |
17 | 17 | |
18 | 18 | <%= link_to( |
19 | 19 | image_tag(url_image, :onerror=>'gravatarCommentFailback(this)', |
20 | - 'data-gravatar'=>str_gravatar_url_for(comment.email, :size=>50)) + | |
20 | + 'data-gravatar'=>gravatar_profile_image_url(comment.email, :size=>50)) + | |
21 | 21 | content_tag('span', comment.author_name, :class => 'comment-info') + |
22 | 22 | content_tag('span', comment.message, |
23 | 23 | :class => 'comment-user-status ' + status_class), | ... | ... |
app/views/content_viewer/_article_toolbar.html.erb
... | ... | @@ -52,6 +52,9 @@ |
52 | 52 | |
53 | 53 | </div> |
54 | 54 | <div id="article-header"> |
55 | + <% if @page.blog? and !@page.image.nil? %> | |
56 | + <div class="blog-cover"><%= image_tag(@page.image.public_filename())%></div> | |
57 | + <% end %> | |
55 | 58 | <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %> |
56 | 59 | <%= article_title(@page, :no_link => true) %> |
57 | 60 | <%= article_translations(@page) %> | ... | ... |
app/views/content_viewer/_enterprise_homepage.html.erb
1 | 1 | <%= display_profile_info enterprise_homepage.profile %> |
2 | 2 | <div><%= enterprise_homepage.body %></div> |
3 | -<%= render :file => 'catalog/index' unless enterprise_homepage.profile.environment.enabled?('disable_products_for_enterprises') %> | |
3 | +<%= render :file => 'catalog/index' if enterprise_homepage.profile.environment.enabled?('products_for_enterprises') %> | ... | ... |
app/views/content_viewer/view_page.html.erb
... | ... | @@ -14,6 +14,12 @@ |
14 | 14 | window.NO_COMMENT_YET = "<%= _('No comments yet') %>"; |
15 | 15 | </script> |
16 | 16 | |
17 | +<% if @page.parent && !@page.parent.path.blank? %> | |
18 | +<div id="article-parent"> | |
19 | + <%= button(:back, _('Go back to %s') % @page.parent.short_title, @page.parent.url) %> | |
20 | +</div> | |
21 | +<% end %> | |
22 | + | |
17 | 23 | <div id="article-toolbar"></div> |
18 | 24 | |
19 | 25 | <script type="text/javascript"> |
... | ... | @@ -43,11 +49,6 @@ |
43 | 49 | </div> |
44 | 50 | <% end %> |
45 | 51 | |
46 | -<% if @page.parent && !@page.parent.path.blank? %> | |
47 | -<div id="article-parent"> | |
48 | - <%= button(:back, _('Go back to %s') % @page.parent.short_title, @page.parent.url) %> | |
49 | -</div> | |
50 | -<% end %> | |
51 | 52 | |
52 | 53 | <%= render :partial => 'shared/disabled_enterprise' %> |
53 | 54 | ... | ... |
app/views/enterprise_registration/basic_information.html.erb
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | <% end %> |
35 | 35 | <% end %> |
36 | 36 | |
37 | - <%= template_options(Enterprise, 'create_enterprise')%> | |
37 | + <%= template_options(:enterprises, 'create_enterprise')%> | |
38 | 38 | |
39 | 39 | <% button_bar do %> |
40 | 40 | <%= submit_button('next', _('Next'), :cancel => {:profile => current_user.person.identifier, :action=>"enterprises", :controller=>"profile"}) %> | ... | ... |
app/views/events/_agenda.html.erb
... | ... | @@ -3,22 +3,14 @@ |
3 | 3 | <table class='noborder current-month'> |
4 | 4 | <caption> |
5 | 5 | <h2><%= show_month(params[:year], params[:month]) %></h2> |
6 | - <%= link_to_previous_month(params[:year], params[:month], '« %s' % _('previous')) %> | |
7 | - <%= link_to_next_month(params[:year], params[:month], '%s »' % _('next')) %> | |
6 | + <%= link_to_previous_month(params[:year], params[:month], show_month(params[:year], params[:month], :previous => true, :only_month => true)) %> | |
7 | + <%= link_to_next_month(params[:year], params[:month], show_month(params[:year], params[:month], :next => true, :only_month => true)) %> | |
8 | 8 | </caption> |
9 | 9 | <%= render :partial => 'events/month', :locals => {:calendar => @calendar, :abbreviated => true} %> |
10 | 10 | </table> |
11 | - <table class='noborder previous-month'> | |
12 | - <caption><h3><%= link_to_previous_month(params[:year], params[:month], show_month(params[:year], params[:month], :previous => true)) %></h3></caption> | |
13 | - <%= render :partial => 'events/month', :locals => {:calendar => @previous_calendar, :abbreviated => true} %> | |
14 | - </table> | |
15 | - <table class='noborder next-month'> | |
16 | - <caption><h3><%= link_to_next_month(params[:year], params[:month], show_month(params[:year], params[:month], :next => true)) %></h3></caption> | |
17 | - <%= render :partial => 'events/month', :locals => {:calendar => @next_calendar, :abbreviated => true} %> | |
18 | - </table> | |
19 | 11 | <br clear='both'/> |
20 | 12 | </div> |
21 | 13 | <div id='events-of-the-day'> |
22 | - <%= render :partial => 'events/events_by_day' %> | |
14 | + <%= render :partial => 'events/events' %> | |
23 | 15 | </div> |
24 | 16 | </div> | ... | ... |
app/views/events/_events_by_day.html.erb
... | ... | @@ -1 +0,0 @@ |
1 | -<%= list_events(@selected_day, @events_of_the_day) %> |
... | ... | @@ -0,0 +1,9 @@ |
1 | +<span class="download-link"> | |
2 | + <span>Download</span> | |
3 | + <strong><%= link_to generic.filename, generic.public_filename %></strong> | |
4 | +</span> | |
5 | + | |
6 | +<div class="uploaded-file-description <%= 'empty' if generic.abstract.blank? %>"> | |
7 | + <%= generic.abstract %> | |
8 | +</div> | |
9 | + | ... | ... |
... | ... | @@ -0,0 +1,36 @@ |
1 | +<% if image.gallery? && options[:gallery_view] %> | |
2 | +<% | |
3 | + images = image.parent.images | |
4 | + current_index = images.index(image.encapsulated_file) | |
5 | + total_of_images = images.count | |
6 | + link_to_previous = if current_index >= 1 | |
7 | + link_to(_('« Previous'), images[current_index - 1].view_url, :class => 'previous') | |
8 | + else | |
9 | + content_tag('span', _('« Previous'), :class => 'previous') | |
10 | + end | |
11 | + | |
12 | + link_to_next = if current_index < total_of_images - 1 | |
13 | + link_to(_('Next »'), images[current_index + 1].view_url, :class => 'next') | |
14 | + else | |
15 | + content_tag('span', _('Next »'), :class => 'next') | |
16 | + end | |
17 | +%> | |
18 | + | |
19 | +<div class="gallery-navigation"> | |
20 | + <%= link_to_previous %> | |
21 | + <span class="total-of-images"> | |
22 | + <%= _('image %d of %d') % [current_index + 1, total_of_images] %> | |
23 | + </span> | |
24 | + <%= link_to_next %> | |
25 | +</div> | |
26 | + | |
27 | +<% end %> | |
28 | + | |
29 | +<%# image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') %> | |
30 | + | |
31 | +<img src="<%=image.public_filename(:display)%>" class="<%=image.css_class_name%>"> | |
32 | + | |
33 | +<div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>"> | |
34 | + <%= image.abstract %> | |
35 | +</div> | |
36 | + | ... | ... |
app/views/manage_products/_display_price_details.html.erb
... | ... | @@ -10,7 +10,7 @@ |
10 | 10 | </li> |
11 | 11 | <% @product.price_details.each do |price_detail| %> |
12 | 12 | <li> |
13 | - <div class='price-detail-name'><%= "%s:" % price_detail.production_cost.name %></div> | |
13 | + <div class='price-detail-name'><%= "%s:" % price_detail.name %></div> | |
14 | 14 | <div class='price-detail-price'><%= float_to_currency(price_detail.price) %></div> |
15 | 15 | </li> |
16 | 16 | <% end %> | ... | ... |
app/views/manage_products/_edit_price_details.html.erb
1 | 1 | <% price_details.each do |price_detail| %> |
2 | 2 | <tr id='<%= "price-detail-#{price_detail.id}" %>'> |
3 | 3 | <td><%= select_production_cost(@product, price_detail.production_cost_id) %></td> |
4 | - <td><%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', price_detail.formatted_value(:price), :class => 'numbers-only price-details-price')) %></td> | |
4 | + <td><%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', price_detail.formatted_value(:price), :class => 'numbers-only price-details-price', :size => 6)) %></td> | |
5 | 5 | <td> |
6 | 6 | <%= link_to_remote(_('Remove'), |
7 | 7 | :update => "price-detail-#{price_detail.id}", | ... | ... |
app/views/manage_products/_manage_product_details.html.erb
... | ... | @@ -34,7 +34,7 @@ |
34 | 34 | <table id='new-cost-fields'> |
35 | 35 | <tr> |
36 | 36 | <td><%= select_production_cost(@product) %></td> |
37 | - <td><%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', nil, :class => 'numbers-only price-details-price')) %></td> | |
37 | + <td><%= labelled_form_field(environment.currency_unit, text_field_tag('price_details[][price]', nil, :class => 'numbers-only price-details-price', :size => 6)) %></td> | |
38 | 38 | <td><%= link_to(_('Cancel'), '#', {:class => 'cancel-new-cost'}) %></td> |
39 | 39 | </tr> |
40 | 40 | </table> | ... | ... |
app/views/maps/edit_location.html.erb
... | ... | @@ -29,5 +29,5 @@ |
29 | 29 | |
30 | 30 | <% end %> |
31 | 31 | |
32 | -<%= content_tag('script', '', :src => "http://maps.googleapis.com/maps/api/js?sensor=false", :type => 'text/javascript') %> | |
32 | +<%= content_tag('script', '', :src => "https://maps.googleapis.com/maps/api/js?sensor=false", :type => 'text/javascript') %> | |
33 | 33 | <%= content_tag('script', '', :src => url_for(:controller => :maps, :action => :google_map), :type => 'text/javascript') %> | ... | ... |
app/views/memberships/index.html.erb
... | ... | @@ -8,6 +8,19 @@ |
8 | 8 | <%= button :back, _('Go back'), :controller => 'profile_editor' %> |
9 | 9 | <% end %> |
10 | 10 | |
11 | -<%= render :partial => 'shared/list_groups', :locals => {:groups => @memberships} %> | |
11 | +<% type_collection = [[nil, _('All')]] %> | |
12 | +<% type_collection += @roles.sort_by {|role| role.id}.map{|r| ["#{r.id}", r.name]} %> | |
13 | + | |
14 | +<p> | |
15 | + <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => 'document.location.href = "?filter_type="+this.value')%> | |
16 | +</p> | |
17 | + | |
18 | +<% if @memberships.empty? %> | |
19 | + <p> | |
20 | + <em><%= _('No groups to list') %></em> | |
21 | + </p> | |
22 | +<% else %> | |
23 | + <%= render :partial => 'shared/list_groups', :locals => {:groups => @memberships} %> | |
24 | +<% end %> | |
12 | 25 | |
13 | 26 | </div> | ... | ... |
app/views/memberships/new_community.html.erb
... | ... | @@ -44,11 +44,13 @@ |
44 | 44 | </div> |
45 | 45 | </div> |
46 | 46 | |
47 | - <%= template_options(Community, 'community')%> | |
47 | + <%= template_options(:communities, 'community')%> | |
48 | + | |
49 | + <%= hidden_field_tag('back_to', @back_to) %> | |
48 | 50 | |
49 | 51 | <% button_bar do %> |
50 | 52 | <%= submit_button(:save, _('Create')) %> |
51 | - <%= button(:cancel, _('Cancel'), :action => 'index') %> | |
53 | + <%= button(:cancel, _('Cancel'), @back_to ) %> | |
52 | 54 | <% end %> |
53 | 55 | |
54 | 56 | <% end %> | ... | ... |