Commit e755c5668041d08027a61070fe94e5d9d0d154bc
Exists in
master
and in
28 other branches
Merge branch 'master' into feature_cyrillic
Showing
828 changed files
with
79866 additions
and
47407 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 828 files displayed.
AUTHORS
... | ... | @@ -6,25 +6,42 @@ noosfero, that's not a problem). |
6 | 6 | Developers |
7 | 7 | ========== |
8 | 8 | |
9 | +Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br> | |
10 | +Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br> | |
9 | 11 | Antonio Terceiro <terceiro@colivre.coop.br> |
10 | 12 | Aurelio A. Heckert <aurelio@colivre.coop.br> |
11 | 13 | Braulio Bhavamitra <brauliobo@gmail.com> |
12 | 14 | Bráulio Bhavamitra <brauliobo@gmail.com> |
13 | 15 | Caio SBA <caio@colivre.coop.br> |
16 | +Carlos Morais <carlos88morais@gmail.com> | |
17 | +Carlos Morais + Diego Araújo <diegoamc90@gmail.com> | |
18 | +Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com> | |
14 | 19 | Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> |
15 | 20 | Daniel Cunha <daniel@colivre.coop.br> |
21 | +Diego Araújo <diegoamc90@gmail.com> | |
22 | +Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com> | |
16 | 23 | Fernanda Lopes <nanda.listas+psl@gmail.com> |
17 | 24 | Grazieno Pellegrino <grazieno@gmail.com> |
18 | 25 | Italo Valcy <italo@dcc.ufba.br> |
26 | +João da Silva <jaodsilv@linux.ime.usp.br> | |
27 | +João M. M. da Silva + Carlos Morais <jaodsilv@linux.ime.usp.br> | |
28 | +João M. M. da Silva + Diego Araújo <diegoamc90@gmail.com> | |
29 | +João M. M. da Silva + Diego Araújo <jaodsilv@linux.ime.usp.br> | |
30 | +João M. M. da Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br> | |
19 | 31 | Joenio Costa <joenio@colivre.coop.br> |
20 | 32 | Josef Spillner <josef.spillner@tu-dresden.de> |
21 | 33 | Keilla Menezes <keilla@colivre.coop.br> |
34 | +Larissa Reis <larissa@colivre.coop.br> | |
35 | +Larissa Reis <reiss.larissa@gmail.com> | |
22 | 36 | Leandro Nunes dos Santos <leandronunes@gmail.com> |
23 | 37 | LinguÁgil 2010 <linguagil.bahia@gmail.com> |
24 | 38 | Martín Olivera <molivera@solar.org.ar> |
25 | 39 | Moises Machado <moises@colivre.coop.br> |
26 | 40 | Nanda Lopes <nanda.listas+psl@gmail.com> |
41 | +Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org> | |
42 | +Paulo Meirelles <paulo@softwarelivre.org> | |
27 | 43 | Rafael Gomes <rafaelgomes@techfree.com.br> |
44 | +Rafael Martins <rmmartins@gmail.com> | |
28 | 45 | Raphaël Rousseau <raph@r4f.org> |
29 | 46 | Raquel Lira <raquel.lira@gmail.com> |
30 | 47 | Rodrigo Souto <rodrigo@colivre.coop.br> |
... | ... | @@ -41,3 +58,6 @@ Raphael Rousseau <raph@r4f.org> |
41 | 58 | Théo Bondolfi <move@cooperation.net> |
42 | 59 | Vicente Aguiar <vicenteaguiar@colivre.coop.br> |
43 | 60 | |
61 | +Arts | |
62 | +=================================== | |
63 | +Nara Oliveira <narananet@gmail.com> | ... | ... |
... | ... | @@ -0,0 +1,19 @@ |
1 | +source :rubygems | |
2 | +gem 'cucumber', '0.4.0' | |
3 | +gem 'webrat', '0.5.1' | |
4 | +gem 'rspec', '1.2.9' | |
5 | +gem 'rspec-rails', '1.2.9' | |
6 | +gem 'Selenium', '>= 1.1.14' | |
7 | +gem 'selenium-client', '>= 1.2.17' | |
8 | +gem 'database_cleaner' | |
9 | +gem 'exception_notification', '1.0.20090728' | |
10 | +gem 'system_timer' | |
11 | + | |
12 | +def program(name) | |
13 | + unless system("which #{name} > /dev/null") | |
14 | + puts "W: Program #{name} is needed, but was not found in your PATH" | |
15 | + end | |
16 | +end | |
17 | + | |
18 | +program 'java' | |
19 | +program 'firefox' | ... | ... |
... | ... | @@ -0,0 +1,44 @@ |
1 | +GEM | |
2 | + remote: http://rubygems.org/ | |
3 | + specs: | |
4 | + Selenium (1.1.14) | |
5 | + builder (3.0.0) | |
6 | + cucumber (0.4.0) | |
7 | + builder (>= 2.1.2) | |
8 | + diff-lcs (>= 1.1.2) | |
9 | + polyglot (>= 0.2.9) | |
10 | + term-ansicolor (>= 1.0.3) | |
11 | + treetop (>= 1.4.2) | |
12 | + database_cleaner (0.7.0) | |
13 | + diff-lcs (1.1.3) | |
14 | + exception_notification (1.0.20090728) | |
15 | + nokogiri (1.5.0) | |
16 | + polyglot (0.3.3) | |
17 | + rack (1.3.5) | |
18 | + rspec (1.2.9) | |
19 | + rspec-rails (1.2.9) | |
20 | + rack (>= 1.0.0) | |
21 | + rspec (>= 1.2.9) | |
22 | + selenium-client (1.2.18) | |
23 | + system_timer (1.2.4) | |
24 | + term-ansicolor (1.0.7) | |
25 | + treetop (1.4.10) | |
26 | + polyglot | |
27 | + polyglot (>= 0.3.1) | |
28 | + webrat (0.5.1) | |
29 | + nokogiri (>= 1.2.0) | |
30 | + rack (>= 1.0) | |
31 | + | |
32 | +PLATFORMS | |
33 | + ruby | |
34 | + | |
35 | +DEPENDENCIES | |
36 | + Selenium (>= 1.1.14) | |
37 | + cucumber (= 0.4.0) | |
38 | + database_cleaner | |
39 | + exception_notification (= 1.0.20090728) | |
40 | + rspec (= 1.2.9) | |
41 | + rspec-rails (= 1.2.9) | |
42 | + selenium-client (>= 1.2.17) | |
43 | + system_timer | |
44 | + webrat (= 0.5.1) | ... | ... |
HACKING
... | ... | @@ -13,7 +13,7 @@ After installing the requirements listed in INSTALL, you need to install some |
13 | 13 | packages be able to run Noosfero tests. On Debian GNU/Linux and Debian-based |
14 | 14 | systems, you install them with the following command: |
15 | 15 | |
16 | - # apt-get install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb | |
16 | + # apt-get install libtidy-ruby libhpricot-ruby libmocha-ruby imagemagick po4a xvfb libxml2-dev libxslt-dev | |
17 | 17 | |
18 | 18 | On other systems, they may or may not be available through your regular package |
19 | 19 | management system. Below are the links to their homepages. |
... | ... | @@ -24,6 +24,8 @@ management system. Below are the links to their homepages. |
24 | 24 | * Imagemagick: http://wwwimagemagick.org/ |
25 | 25 | * po4a: http://po4a.alioth.debian.org/ |
26 | 26 | * xvfb: http://packages.debian.org/lenny/xvfb |
27 | +* Libxml2: http://xmlsoft.org/ | |
28 | +* Libxslt: http://xmlsoft.org/xslt | |
27 | 29 | |
28 | 30 | == Boostraping a development/test environment |
29 | 31 | |
... | ... | @@ -46,6 +48,9 @@ commands and make sure you understand what you are doing): |
46 | 48 | rake makemo |
47 | 49 | # create some test data: |
48 | 50 | ./script/sample-data |
51 | + # install latest requirements for running tests | |
52 | + RAILS_ENV=cucumber rake gems:install | |
53 | + RAILS_ENV=test rake gems:install | |
49 | 54 | # run the automated test suite to make sure your environment is sane: |
50 | 55 | rake test |
51 | 56 | ... | ... |
... | ... | @@ -0,0 +1,14 @@ |
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 ferret | |
8 | +gem install i18n | |
9 | +gem install will_paginate -v 2.3.12 | |
10 | +gem install cucumber | |
11 | + | |
12 | +Creating initial environment: | |
13 | + | |
14 | +rake db:schema:load | ... | ... |
INSTALL
... | ... | @@ -13,7 +13,7 @@ You need to install some packages Noosfero depends on. On Debian GNU/Linux or |
13 | 13 | Debian-based systems, all of these packages are available through the Debian |
14 | 14 | archive. You can install them with the following command: |
15 | 15 | |
16 | - # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby-data libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libferret-ruby libdaemons-ruby mongrel mongrel-cluster tango-icon-theme libhpricot-ruby | |
16 | + # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby-data libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libferret-ruby libdaemons-ruby thin tango-icon-theme libhpricot-ruby | |
17 | 17 | |
18 | 18 | On other systems, they may or may not be available through your regular package |
19 | 19 | management system. Below are the links to their homepages. |
... | ... | @@ -31,7 +31,7 @@ management system. Below are the links to their homepages. |
31 | 31 | * iso-codes: http://pkg-isocodes.alioth.debian.org/ |
32 | 32 | * feedparser: http://packages.debian.org/sid/libfeedparser-ruby |
33 | 33 | * Daemons - http://daemons.rubyforge.org/ |
34 | -* Mongrel: http://mongrel.rubyforge.org/ | |
34 | +* Thin: http://code.macournoyer.com/thin/ | |
35 | 35 | * tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library |
36 | 36 | * Hpricot: http://hpricot.com/ |
37 | 37 | |
... | ... | @@ -118,13 +118,13 @@ $ cd current |
118 | 118 | Copy config/ferret_server.yml.dist to config/ferret_server.yml. You will |
119 | 119 | probably not need to customize this configuration, but have a look at it. |
120 | 120 | |
121 | -Create the mongrel configuration file: | |
121 | +Create the thin configuration file: | |
122 | 122 | |
123 | -$ mongrel_rails cluster::configure | |
123 | +$ thin -C config/thin.yml config | |
124 | 124 | |
125 | -Edit config/mongrel_cluster.yml to suit your needs. Make sure your apache | |
126 | -configuration matches the mongrel cluster configuration, specially in respect | |
127 | -to the ports and numbers of mongrel instances. | |
125 | +Edit config/thin.yml to suit your needs. Make sure your apache | |
126 | +configuration matches the thin cluster configuration, specially in respect | |
127 | +to the ports and numbers of thin instances. | |
128 | 128 | |
129 | 129 | Note: currently Noosfero only supports Rails 2.1.0, which is the version in |
130 | 130 | Debian Lenny. If you have a Rails version newer than that, Noosfero will |
... | ... | @@ -237,6 +237,10 @@ Create the database structure: |
237 | 237 | |
238 | 238 | $ RAILS_ENV=production rake db:schema:load |
239 | 239 | |
240 | +Compile the translations: | |
241 | + | |
242 | +$ RAILS_ENV=production rake noosfero:translations:compile | |
243 | + | |
240 | 244 | Now we have to create some initial data. To create your default environment |
241 | 245 | (the first one), run the command below: |
242 | 246 | |
... | ... | @@ -258,10 +262,6 @@ $ RAILS_ENV=production ./script/runner "User.create(:login => 'adminuser', :emai |
258 | 262 | (replace "adminuser", "admin@example.com", "admin" with the login, email |
259 | 263 | and password of your environment admin) |
260 | 264 | |
261 | -Compile the translations: | |
262 | - | |
263 | -$ RAILS_ENV=production rake noosfero:translations:compile | |
264 | - | |
265 | 265 | To start the Noosfero application servers: |
266 | 266 | |
267 | 267 | $ ./script/production start |
... | ... | @@ -316,7 +316,7 @@ In other systems the way by which you enable apache modules may be different. |
316 | 316 | Now with the Apache configuration. You can use the template below, replacing |
317 | 317 | /var/lib/noosfero/current with the directory in which your noosfero |
318 | 318 | installation is, your.domain.com with the domain name of your noosfero site. |
319 | -We are assuming that you are running two mongrel instances on ports 3000 and | |
319 | +We are assuming that you are running two thin instances on ports 3000 and | |
320 | 320 | 3001. If your setup is different you'll need to adjust <Proxy> section. If you |
321 | 321 | don't understand something in the configuration, please refer to the apache |
322 | 322 | documentation. | ... | ... |
... | ... | @@ -0,0 +1,78 @@ |
1 | += AWStats setup for Noosfero | |
2 | + | |
3 | +AWStats is a free powerful and featureful tool that generates advanced web, | |
4 | +streaming, ftp or mail server statistics, graphically. | |
5 | + | |
6 | +See http://awstats.sourceforge.net/ | |
7 | + | |
8 | +This guide supposes that the Noosfero server is running GNU/Linux Debian Squeeze. | |
9 | + | |
10 | +1. Install AWStats | |
11 | + | |
12 | +# apt-get install awstats libgeo-ip-perl geoip-database | |
13 | + | |
14 | +2. Basic setup | |
15 | + | |
16 | +Create AWStats config file: | |
17 | + | |
18 | + * /etc/awstats/awstats.<domain>.conf | |
19 | + | |
20 | +Include "/etc/awstats/awstats.conf" | |
21 | +Include "/etc/noosfero/awstats-noosfero.conf" | |
22 | +SiteDomain="<domain>" | |
23 | +HostAliases="<domain-aliases>" | |
24 | + | |
25 | +<domain> should be the domain used in your Noosfero server (eg.: | |
26 | +softwarelivre.org) and the <domain-aliases> should be a list with all aliases | |
27 | +that you configured in apache (eg.: www.softwarelivre.org | |
28 | +www2.softwarelivre.org etc). | |
29 | + | |
30 | +This setup is considering that the Noosfero server is running varnish (see | |
31 | +INSTALL.varnish) and varnishncsa-vhost [1]. | |
32 | + | |
33 | +[1] http://gitorious.org/varnisnncsa-vhost | |
34 | + | |
35 | +3. Running AWStats for the first time | |
36 | + | |
37 | +Run awstats by hand via command line: | |
38 | + | |
39 | +# /usr/lib/cgi-bin/awstats.pl -config=<domain> | |
40 | + | |
41 | +You should see something as below as output of this command: | |
42 | + | |
43 | +# /usr/lib/cgi-bin/awstats.pl -config=softwarelivre.org | |
44 | +Create/Update database for config "/etc/awstats/awstats.softwarelivre.org.conf" by AWStats version 6.7 (build 1.892) | |
45 | +From data in log file "/var/log/varnish/varnishncsa-vhost.log"... | |
46 | +Phase 1 : First bypass old records, searching new record... | |
47 | +Searching new records from beginning of log file... | |
48 | +Phase 2 : Now process new records (Flush history on disk after 20000 hosts)... | |
49 | +Jumped lines in file: 0 | |
50 | +Parsed lines in file: 452 | |
51 | + Found 0 dropped records, | |
52 | + Found 0 corrupted records, | |
53 | + Found 0 old records, | |
54 | + Found 452 new qualified records. | |
55 | + | |
56 | +4. Setup frontend | |
57 | + | |
58 | +You should create a new subdomain to have access to the AWStats, usually | |
59 | +something like tools.<domain> (eg.: tools.softwarelivre.org). Don't include | |
60 | +this subdomain in HostAliases in the AWStats neither in SiteAlias in the | |
61 | +Apache. | |
62 | + | |
63 | +# cp /usr/share/doc/awstats/examples/apache.conf /etc/apache2/conf.d/awstats.conf | |
64 | +# invoke-rc.d apache2 restart | |
65 | + | |
66 | +ps.: Don't forget to change the port /etc/apache/sites-enabled/000-default to | |
67 | +8080. | |
68 | + | |
69 | +Try: http://tools.<domain>/cgi-bin/awstats.pl?config=<domain> | |
70 | +(eg.: http://tools.softwarelivre.org/cgi-bin/awstats.pl?config=softwarelivre.org). | |
71 | + | |
72 | +5. Schedule AWStats in crontab | |
73 | + | |
74 | + * /etc/cron.d/awstats | |
75 | + | |
76 | +0,10,20,30,40,50 * * * * www-data [ -x /usr/lib/cgi-bin/awstats.pl -a -f /etc/awstats/awstats.<domain>.conf -a -r /var/log/apache/access.log ] && /usr/lib/cgi-bin/awstats.pl -config=<domain> -update >/dev/null | |
77 | + | |
78 | +Done, check the AWStats frontend after one or two days to see if everything is working properly. | ... | ... |
app/controllers/admin/role_controller.rb
... | ... | @@ -5,6 +5,20 @@ class RoleController < AdminController |
5 | 5 | @roles = environment.roles.find(:all) |
6 | 6 | end |
7 | 7 | |
8 | + def new | |
9 | + @role = Role.new | |
10 | + end | |
11 | + | |
12 | + def create | |
13 | + @role = Role.new :name => params[:role][:name], :permissions => params[:role][:permissions], :environment => environment | |
14 | + if @role.save | |
15 | + redirect_to :action => 'show', :id => @role | |
16 | + else | |
17 | + session[:notice] = _('Failed to create role') | |
18 | + render :action => 'new' | |
19 | + end | |
20 | + end | |
21 | + | |
8 | 22 | def show |
9 | 23 | @role = environment.roles.find(params[:id]) |
10 | 24 | end | ... | ... |
app/controllers/admin/users_controller.rb
... | ... | @@ -3,10 +3,10 @@ class UsersController < AdminController |
3 | 3 | protect 'manage_environment_users', :environment |
4 | 4 | |
5 | 5 | def index |
6 | - @users = environment.users | |
7 | 6 | respond_to do |format| |
8 | 7 | format.html |
9 | 8 | format.xml do |
9 | + @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person]) | |
10 | 10 | render :xml => @users.to_xml( |
11 | 11 | :skip_types => true, |
12 | 12 | :only => %w[email login created_at updated_at], |
... | ... | @@ -14,6 +14,7 @@ class UsersController < AdminController |
14 | 14 | ) |
15 | 15 | end |
16 | 16 | format.csv do |
17 | + @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person]) | |
17 | 18 | render :template => "users/index_csv.rhtml", :content_type => 'text/csv', :layout => false |
18 | 19 | end |
19 | 20 | end | ... | ... |
app/controllers/admin_controller.rb
app/controllers/application.rb
1 | -# his is the application's main controller. Features defined here are | |
2 | -# available in all controllers. | |
3 | -class ApplicationController < ActionController::Base | |
4 | - | |
5 | - before_filter :change_pg_schema | |
6 | - | |
7 | - include ApplicationHelper | |
8 | - layout :get_layout | |
9 | - def get_layout | |
10 | - theme_option(:layout) || 'application' | |
11 | - end | |
12 | - | |
13 | - filter_parameter_logging :password | |
14 | - | |
15 | - def log_processing | |
16 | - super | |
17 | - return unless ENV['RAILS_ENV'] == 'production' | |
18 | - if logger && logger.info? | |
19 | - logger.info(" HTTP Referer: #{request.referer}") | |
20 | - logger.info(" User Agent: #{request.user_agent}") | |
21 | - logger.info(" Accept-Language: #{request.headers['HTTP_ACCEPT_LANGUAGE']}") | |
22 | - end | |
23 | - end | |
24 | - | |
25 | - helper :document | |
26 | - helper :language | |
27 | - | |
28 | - def self.no_design_blocks | |
29 | - @no_design_blocks = true | |
30 | - end | |
31 | - def self.uses_design_blocks? | |
32 | - !@no_design_blocks | |
33 | - end | |
34 | - def uses_design_blocks? | |
35 | - !@no_design_blocks && self.class.uses_design_blocks? | |
36 | - end | |
37 | - | |
38 | - # Be sure to include AuthenticationSystem in Application Controller instead | |
39 | - include AuthenticatedSystem | |
40 | - include PermissionCheck | |
41 | - | |
42 | - def self.require_ssl(*options) | |
43 | - before_filter :check_ssl, *options | |
44 | - end | |
45 | - def check_ssl | |
46 | - return true if (request.ssl? || ENV['RAILS_ENV'] == 'development') | |
47 | - redirect_to_ssl | |
48 | - end | |
49 | - def redirect_to_ssl | |
50 | - if environment.enable_ssl | |
51 | - redirect_to(params.merge(:protocol => 'https://', :host => ssl_hostname)) | |
52 | - true | |
53 | - else | |
54 | - false | |
55 | - end | |
56 | - end | |
57 | - | |
58 | - def self.refuse_ssl(*options) | |
59 | - before_filter :avoid_ssl, *options | |
60 | - end | |
61 | - def avoid_ssl | |
62 | - if (!request.ssl? || ENV['RAILS_ENV'] == 'development') | |
63 | - true | |
64 | - else | |
65 | - redirect_to(params.merge(:protocol => 'http://')) | |
66 | - false | |
67 | - end | |
68 | - end | |
69 | - | |
70 | - before_filter :set_locale | |
71 | - def set_locale | |
72 | - FastGettext.available_locales = Noosfero.available_locales | |
73 | - FastGettext.default_locale = Noosfero.default_locale | |
74 | - FastGettext.set_locale(params[:lang] || session[:lang] || Noosfero.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') | |
75 | - if params[:lang] | |
76 | - session[:lang] = params[:lang] | |
77 | - end | |
78 | - end | |
79 | - | |
80 | - include NeedsProfile | |
81 | - | |
82 | - before_filter :detect_stuff_by_domain | |
83 | - before_filter :init_noosfero_plugins | |
84 | - attr_reader :environment | |
85 | - | |
86 | - before_filter :load_terminology | |
87 | - | |
88 | - # declares that the given <tt>actions</tt> cannot be accessed by other HTTP | |
89 | - # method besides POST. | |
90 | - def self.post_only(actions, redirect = { :action => 'index'}) | |
91 | - verify :method => :post, :only => actions, :redirect_to => redirect | |
92 | - end | |
93 | - | |
94 | - helper_method :current_person, :current_person | |
95 | - | |
96 | - def change_pg_schema | |
97 | - if Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql? | |
98 | - Noosfero::MultiTenancy.db_by_host = request.host | |
99 | - end | |
100 | - end | |
101 | - | |
102 | - protected | |
103 | - | |
104 | - def boxes_editor? | |
105 | - false | |
106 | - end | |
107 | - | |
108 | - def content_editor? | |
109 | - false | |
110 | - end | |
111 | - | |
112 | - def user | |
113 | - current_user.person if logged_in? | |
114 | - end | |
115 | - | |
116 | - alias :current_person :user | |
117 | - | |
118 | - # TODO: move this logic somewhere else (Domain class?) | |
119 | - def detect_stuff_by_domain | |
120 | - @domain = Domain.find_by_name(request.host) | |
121 | - if @domain.nil? | |
122 | - @environment = Environment.default | |
123 | - else | |
124 | - @environment = @domain.environment | |
125 | - @profile = @domain.profile | |
126 | - end | |
127 | - end | |
128 | - | |
129 | - def init_noosfero_plugins | |
130 | - @plugins = Noosfero::Plugin::Manager.new(self) | |
131 | - @plugins.enabled_plugins.map(&:class).each do |plugin| | |
132 | - prepend_view_path(plugin.view_path) | |
133 | - end | |
134 | - init_noosfero_plugins_controller_filters | |
135 | - end | |
136 | - | |
137 | - # This is a generic method that initialize any possible filter defined by a | |
138 | - # plugin to the current controller being initialized. | |
139 | - def init_noosfero_plugins_controller_filters | |
140 | - @plugins.enabled_plugins.each do |plugin| | |
141 | - plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| | |
142 | - self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) | |
143 | - self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) | |
144 | - end | |
145 | - end | |
146 | - end | |
147 | - | |
148 | - def load_terminology | |
149 | - # cache terminology for performance | |
150 | - @@terminology_cache ||= {} | |
151 | - @@terminology_cache[environment.id] ||= environment.terminology | |
152 | - Noosfero.terminology = @@terminology_cache[environment.id] | |
153 | - end | |
154 | - | |
155 | - def render_not_found(path = nil) | |
156 | - @no_design_blocks = true | |
157 | - @path ||= request.path | |
158 | - render :template => 'shared/not_found.rhtml', :status => 404, :layout => get_layout | |
159 | - end | |
160 | - alias :render_404 :render_not_found | |
161 | - | |
162 | - def render_access_denied(message = nil, title = nil) | |
163 | - @no_design_blocks = true | |
164 | - @message = message | |
165 | - @title = title | |
166 | - render :template => 'shared/access_denied.rhtml', :status => 403 | |
167 | - end | |
168 | - | |
169 | - def load_category | |
170 | - unless params[:category_path].blank? | |
171 | - path = params[:category_path].join('/') | |
172 | - @category = environment.categories.find_by_path(path) | |
173 | - if @category.nil? | |
174 | - render_not_found(path) | |
175 | - end | |
176 | - end | |
177 | - end | |
178 | - | |
179 | -end | |
1 | +require 'application_controller' | ... | ... |
... | ... | @@ -0,0 +1,155 @@ |
1 | +class ApplicationController < ActionController::Base | |
2 | + | |
3 | + before_filter :change_pg_schema | |
4 | + | |
5 | + include ApplicationHelper | |
6 | + layout :get_layout | |
7 | + def get_layout | |
8 | + prepend_view_path('public/' + theme_path) | |
9 | + theme_option(:layout) || 'application' | |
10 | + end | |
11 | + | |
12 | + filter_parameter_logging :password | |
13 | + | |
14 | + def log_processing | |
15 | + super | |
16 | + return unless ENV['RAILS_ENV'] == 'production' | |
17 | + if logger && logger.info? | |
18 | + logger.info(" HTTP Referer: #{request.referer}") | |
19 | + logger.info(" User Agent: #{request.user_agent}") | |
20 | + logger.info(" Accept-Language: #{request.headers['HTTP_ACCEPT_LANGUAGE']}") | |
21 | + end | |
22 | + end | |
23 | + | |
24 | + helper :document | |
25 | + helper :language | |
26 | + | |
27 | + def self.no_design_blocks | |
28 | + @no_design_blocks = true | |
29 | + end | |
30 | + def self.uses_design_blocks? | |
31 | + !@no_design_blocks | |
32 | + end | |
33 | + def uses_design_blocks? | |
34 | + !@no_design_blocks && self.class.uses_design_blocks? | |
35 | + end | |
36 | + | |
37 | + # Be sure to include AuthenticationSystem in Application Controller instead | |
38 | + include AuthenticatedSystem | |
39 | + include PermissionCheck | |
40 | + | |
41 | + before_filter :set_locale | |
42 | + def set_locale | |
43 | + FastGettext.available_locales = Noosfero.available_locales | |
44 | + FastGettext.default_locale = Noosfero.default_locale | |
45 | + I18n.locale = FastGettext.locale = (params[:lang] || session[:lang] || Noosfero.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') | |
46 | + if params[:lang] | |
47 | + session[:lang] = params[:lang] | |
48 | + end | |
49 | + end | |
50 | + | |
51 | + include NeedsProfile | |
52 | + | |
53 | + before_filter :detect_stuff_by_domain | |
54 | + before_filter :init_noosfero_plugins | |
55 | + attr_reader :environment | |
56 | + | |
57 | + before_filter :load_terminology | |
58 | + | |
59 | + # declares that the given <tt>actions</tt> cannot be accessed by other HTTP | |
60 | + # method besides POST. | |
61 | + def self.post_only(actions, redirect = { :action => 'index'}) | |
62 | + verify :method => :post, :only => actions, :redirect_to => redirect | |
63 | + end | |
64 | + | |
65 | + helper_method :current_person, :current_person | |
66 | + | |
67 | + protected | |
68 | + | |
69 | + def change_pg_schema | |
70 | + if Noosfero::MultiTenancy.on? and ActiveRecord::Base.postgresql? | |
71 | + Noosfero::MultiTenancy.db_by_host = request.host | |
72 | + end | |
73 | + end | |
74 | + | |
75 | + def boxes_editor? | |
76 | + false | |
77 | + end | |
78 | + | |
79 | + def content_editor? | |
80 | + false | |
81 | + end | |
82 | + | |
83 | + | |
84 | + def user | |
85 | + current_user.person if logged_in? | |
86 | + end | |
87 | + | |
88 | + alias :current_person :user | |
89 | + | |
90 | + # TODO: move this logic somewhere else (Domain class?) | |
91 | + def detect_stuff_by_domain | |
92 | + @domain = Domain.find_by_name(request.host) | |
93 | + if @domain.nil? | |
94 | + @environment = Environment.default | |
95 | + if @environment.nil? && Rails.env.development? | |
96 | + # This should only happen in development ... | |
97 | + @environment = Environment.create!(:name => "Noosfero", :is_default => true) | |
98 | + end | |
99 | + else | |
100 | + @environment = @domain.environment | |
101 | + @profile = @domain.profile | |
102 | + end | |
103 | + end | |
104 | + | |
105 | + def init_noosfero_plugins | |
106 | + @plugins = Noosfero::Plugin::Manager.new(self) | |
107 | + @plugins.each do |plugin| | |
108 | + prepend_view_path(plugin.class.view_path) | |
109 | + end | |
110 | + init_noosfero_plugins_controller_filters | |
111 | + end | |
112 | + | |
113 | + # This is a generic method that initialize any possible filter defined by a | |
114 | + # plugin to the current controller being initialized. | |
115 | + def init_noosfero_plugins_controller_filters | |
116 | + @plugins.each do |plugin| | |
117 | + plugin.send(self.class.name.underscore + '_filters').each do |plugin_filter| | |
118 | + self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {})) | |
119 | + self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block]) | |
120 | + end | |
121 | + end | |
122 | + end | |
123 | + | |
124 | + def load_terminology | |
125 | + # cache terminology for performance | |
126 | + @@terminology_cache ||= {} | |
127 | + @@terminology_cache[environment.id] ||= environment.terminology | |
128 | + Noosfero.terminology = @@terminology_cache[environment.id] | |
129 | + end | |
130 | + | |
131 | + def render_not_found(path = nil) | |
132 | + @no_design_blocks = true | |
133 | + @path ||= request.path | |
134 | + render :template => 'shared/not_found.rhtml', :status => 404, :layout => get_layout | |
135 | + end | |
136 | + alias :render_404 :render_not_found | |
137 | + | |
138 | + def render_access_denied(message = nil, title = nil) | |
139 | + @no_design_blocks = true | |
140 | + @message = message | |
141 | + @title = title | |
142 | + render :template => 'shared/access_denied.rhtml', :status => 403 | |
143 | + end | |
144 | + | |
145 | + def load_category | |
146 | + unless params[:category_path].blank? | |
147 | + path = params[:category_path].join('/') | |
148 | + @category = environment.categories.find_by_path(path) | |
149 | + if @category.nil? | |
150 | + render_not_found(path) | |
151 | + end | |
152 | + end | |
153 | + end | |
154 | + | |
155 | +end | ... | ... |
app/controllers/box_organizer_controller.rb
... | ... | @@ -82,7 +82,6 @@ class BoxOrganizerController < ApplicationController |
82 | 82 | def save |
83 | 83 | @block = boxes_holder.blocks.find(params[:id]) |
84 | 84 | @block.update_attributes(params[:block]) |
85 | - expire_timeout_fragment(@block.cache_key) | |
86 | 85 | redirect_to :action => 'index' |
87 | 86 | end |
88 | 87 | |
... | ... | @@ -93,7 +92,6 @@ class BoxOrganizerController < ApplicationController |
93 | 92 | def remove |
94 | 93 | @block = Block.find(params[:id]) |
95 | 94 | if @block.destroy |
96 | - expire_timeout_fragment(@block.cache_key) | |
97 | 95 | redirect_to :action => 'index' |
98 | 96 | else |
99 | 97 | session[:notice] = _('Failed to remove block') | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -23,15 +23,6 @@ class CmsController < MyProfileController |
23 | 23 | profile.articles.find(c.params[:id]).allow_post_content?(user) |
24 | 24 | end |
25 | 25 | |
26 | - alias :check_ssl_orig :check_ssl | |
27 | - # Redefines the SSL checking to avoid requiring SSL when creating the "New | |
28 | - # publication" button on article's public view. | |
29 | - def check_ssl | |
30 | - if ((params[:action] == 'new') && (!request.xhr?)) || (params[:action] != 'new') | |
31 | - check_ssl_orig | |
32 | - end | |
33 | - end | |
34 | - | |
35 | 26 | def boxes_holder |
36 | 27 | profile |
37 | 28 | end |
... | ... | @@ -59,7 +50,7 @@ class CmsController < MyProfileController |
59 | 50 | end |
60 | 51 | |
61 | 52 | def special_article_types |
62 | - [Folder, Blog, UploadedFile, Forum, Gallery, RssFeed] | |
53 | + [Folder, Blog, UploadedFile, Forum, Gallery, RssFeed] + @plugins.dispatch(:content_types) | |
63 | 54 | end |
64 | 55 | |
65 | 56 | def view |
... | ... | @@ -206,6 +197,7 @@ class CmsController < MyProfileController |
206 | 197 | @article = profile.articles.find(params[:id]) |
207 | 198 | if request.post? |
208 | 199 | @article.destroy |
200 | + session[:notice] = _("\"#{@article.name}\" was removed.") | |
209 | 201 | redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent |
210 | 202 | end |
211 | 203 | end |
... | ... | @@ -319,10 +311,6 @@ class CmsController < MyProfileController |
319 | 311 | end |
320 | 312 | end |
321 | 313 | |
322 | - def maybe_ssl(url) | |
323 | - [url, url.sub('https:', 'http:')] | |
324 | - end | |
325 | - | |
326 | 314 | def valid_article_type?(type) |
327 | 315 | (available_article_types + special_article_types).map {|item| item.name}.include?(type) |
328 | 316 | end |
... | ... | @@ -365,7 +353,7 @@ class CmsController < MyProfileController |
365 | 353 | } |
366 | 354 | end.to_json |
367 | 355 | end |
368 | - | |
356 | + | |
369 | 357 | def content_editor? |
370 | 358 | true |
371 | 359 | end | ... | ... |
app/controllers/my_profile/manage_products_controller.rb
... | ... | @@ -111,6 +111,36 @@ class ManageProductsController < ApplicationController |
111 | 111 | end |
112 | 112 | end |
113 | 113 | |
114 | + def manage_product_details | |
115 | + @product = @profile.products.find(params[:id]) | |
116 | + if request.post? | |
117 | + @product.update_price_details(params[:price_details]) if params[:price_details] | |
118 | + render :partial => 'display_price_details' | |
119 | + else | |
120 | + render :partial => 'manage_product_details' | |
121 | + end | |
122 | + end | |
123 | + | |
124 | + def remove_price_detail | |
125 | + @product = @profile.products.find(params[:product]) | |
126 | + @price_detail = @product.price_details.find(params[:id]) | |
127 | + @product = @price_detail.product | |
128 | + if request.post? | |
129 | + @price_detail.destroy | |
130 | + render :nothing => true | |
131 | + end | |
132 | + end | |
133 | + | |
134 | + def display_price_composition_bar | |
135 | + @product = @profile.products.find(params[:id]) | |
136 | + render :partial => 'price_composition_bar' | |
137 | + end | |
138 | + | |
139 | + def display_inputs_cost | |
140 | + @product = @profile.products.find(params[:id]) | |
141 | + render :inline => "<%= float_to_currency(@product.inputs_cost) %>" | |
142 | + end | |
143 | + | |
114 | 144 | def destroy |
115 | 145 | @product = @profile.products.find(params[:id]) |
116 | 146 | if @product.destroy |
... | ... | @@ -167,4 +197,18 @@ class ManageProductsController < ApplicationController |
167 | 197 | end |
168 | 198 | end |
169 | 199 | |
200 | + def create_production_cost | |
201 | + cost = @profile.production_costs.create(:name => params[:id]) | |
202 | + if cost.valid? | |
203 | + cost.save | |
204 | + render :text => {:name => cost.name, | |
205 | + :id => cost.id, | |
206 | + :ok => true | |
207 | + }.to_json | |
208 | + else | |
209 | + render :text => {:ok => false, | |
210 | + :error_msg => _(cost.errors['name']) % {:fn => _('Name')} | |
211 | + }.to_json | |
212 | + end | |
213 | + end | |
170 | 214 | end | ... | ... |
app/controllers/my_profile/tasks_controller.rb
... | ... | @@ -33,12 +33,14 @@ class TasksController < MyProfileController |
33 | 33 | end |
34 | 34 | end |
35 | 35 | |
36 | + url = { :action => 'index' } | |
36 | 37 | if failed.blank? |
37 | 38 | session[:notice] = _("All decisions were applied successfully.") |
38 | 39 | else |
39 | 40 | session[:notice] = _("Some decisions couldn't be applied.") |
41 | + url[:failed] = failed | |
40 | 42 | end |
41 | - redirect_to params.merge!(:action => 'index', :failed => failed) | |
43 | + redirect_to url | |
42 | 44 | end |
43 | 45 | |
44 | 46 | def new | ... | ... |
app/controllers/my_profile_controller.rb
app/controllers/public/account_controller.rb
... | ... | @@ -2,8 +2,6 @@ class AccountController < ApplicationController |
2 | 2 | |
3 | 3 | no_design_blocks |
4 | 4 | |
5 | - require_ssl :except => [ :login_popup, :logout_popup, :profile_details ] | |
6 | - | |
7 | 5 | before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise] |
8 | 6 | before_filter :redirect_if_logged_in, :only => [:login, :signup] |
9 | 7 | |
... | ... | @@ -60,6 +58,10 @@ class AccountController < ApplicationController |
60 | 58 | def signup |
61 | 59 | @invitation_code = params[:invitation_code] |
62 | 60 | begin |
61 | + if params[:user] | |
62 | + params[:user].delete(:password_confirmation_clear) | |
63 | + params[:user].delete(:password_clear) | |
64 | + end | |
63 | 65 | @user = User.new(params[:user]) |
64 | 66 | @user.terms_of_use = environment.terms_of_use |
65 | 67 | @user.environment = environment |
... | ... | @@ -91,7 +93,6 @@ class AccountController < ApplicationController |
91 | 93 | if logged_in? |
92 | 94 | self.current_user.forget_me |
93 | 95 | end |
94 | - cookies.delete :auth_token | |
95 | 96 | reset_session |
96 | 97 | session[:notice] = _("You have been logged out.") |
97 | 98 | redirect_to :controller => 'home', :action => 'index' |
... | ... | @@ -209,16 +210,26 @@ class AccountController < ApplicationController |
209 | 210 | @identifier = params[:identifier] |
210 | 211 | valid = Person.is_available?(@identifier, environment) |
211 | 212 | if valid |
212 | - @status = _('Available!') | |
213 | + @status = _('This login name is available') | |
213 | 214 | @status_class = 'available' |
214 | 215 | else |
215 | - @status = _('Unavailable!') | |
216 | + @status = _('This login name is unavailable') | |
216 | 217 | @status_class = 'unavailable' |
217 | 218 | end |
218 | - @url = environment.top_url + '/' + @identifier | |
219 | 219 | render :partial => 'identifier_status' |
220 | 220 | end |
221 | 221 | |
222 | + def check_email | |
223 | + if User.find_by_email_and_environment_id(params[:address], environment.id).nil? | |
224 | + @status = _('This e-mail address is available') | |
225 | + @status_class = 'available' | |
226 | + else | |
227 | + @status = _('This e-mail address is taken') | |
228 | + @status_class = 'unavailable' | |
229 | + end | |
230 | + render :partial => 'email_status' | |
231 | + end | |
232 | + | |
222 | 233 | def user_data |
223 | 234 | user_data = |
224 | 235 | if logged_in? |
... | ... | @@ -231,7 +242,7 @@ class AccountController < ApplicationController |
231 | 242 | session[:notice] = nil # consume the notice |
232 | 243 | end |
233 | 244 | |
234 | - @plugins.enabled_plugins.each { |plugin| user_data.merge!(plugin.user_data_extras) } | |
245 | + @plugins.each { |plugin| user_data.merge!(plugin.user_data_extras) } | |
235 | 246 | |
236 | 247 | render :text => user_data.to_json, :layout => false, :content_type => "application/javascript" |
237 | 248 | end | ... | ... |
app/controllers/public/browse_controller.rb
... | ... | @@ -6,6 +6,8 @@ class BrowseController < PublicController |
6 | 6 | more_recent |
7 | 7 | more_active |
8 | 8 | more_popular |
9 | + more_comments | |
10 | + more_views | |
9 | 11 | ) |
10 | 12 | |
11 | 13 | def per_page |
... | ... | @@ -36,6 +38,18 @@ class BrowseController < PublicController |
36 | 38 | @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) |
37 | 39 | end |
38 | 40 | |
41 | + def contents | |
42 | + @filter = filter | |
43 | + @title = self.filter_description(params[:action] + '_' + @filter ) | |
44 | + | |
45 | + @results = @environment.articles.published.text_articles.send(@filter) | |
46 | + | |
47 | + if !params[:query].blank? | |
48 | + @results = @results.find_by_contents(params[:query]) | |
49 | + end | |
50 | + @results = @results.compact.paginate(:per_page => per_page, :page => params[:page]) | |
51 | + end | |
52 | + | |
39 | 53 | protected |
40 | 54 | |
41 | 55 | def filter |
... | ... | @@ -54,6 +68,9 @@ class BrowseController < PublicController |
54 | 68 | 'communities_more_recent' => _('More recent communities'), |
55 | 69 | 'communities_more_active' => _('More active communities'), |
56 | 70 | 'communities_more_popular' => _('More popular communities'), |
71 | + 'contents_more_recent' => _('More recent contents'), | |
72 | + 'contents_more_views' => _('Most viewed contents'), | |
73 | + 'contents_more_comments' => _('Most commented contents'), | |
57 | 74 | }[str] || str |
58 | 75 | end |
59 | 76 | ... | ... |
app/controllers/public/catalog_controller.rb
... | ... | @@ -4,10 +4,11 @@ class CatalogController < PublicController |
4 | 4 | before_filter :check_enterprise_and_environment |
5 | 5 | |
6 | 6 | def index |
7 | - @products = @profile.products.paginate(:per_page => 10, :page => params[:page]) | |
7 | + @products = @profile.products.paginate(:order => 'name asc', :per_page => 9, :page => params[:page]) | |
8 | 8 | end |
9 | 9 | |
10 | 10 | protected |
11 | + | |
11 | 12 | def check_enterprise_and_environment |
12 | 13 | unless @profile.kind_of?(Enterprise) && !@profile.environment.enabled?('disable_products_for_enterprises') |
13 | 14 | redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index' | ... | ... |
app/controllers/public/content_viewer_controller.rb
... | ... | @@ -31,14 +31,6 @@ class ContentViewerController < ApplicationController |
31 | 31 | end |
32 | 32 | end |
33 | 33 | |
34 | - if !@page.public? && !request.ssl? | |
35 | - return if redirect_to_ssl | |
36 | - end | |
37 | - | |
38 | - if @page.public? | |
39 | - return unless avoid_ssl | |
40 | - end | |
41 | - | |
42 | 34 | if !@page.display_to?(user) |
43 | 35 | if profile.display_info_to?(user) || !profile.visible? |
44 | 36 | message = _('You are not allowed to view this content. You can contact the owner of this profile to request access then.') |
... | ... | @@ -54,7 +46,7 @@ class ContentViewerController < ApplicationController |
54 | 46 | return |
55 | 47 | end |
56 | 48 | |
57 | - redirect_to_translation | |
49 | + redirect_to_translation if @page.profile.redirect_l10n | |
58 | 50 | |
59 | 51 | # At this point the page will be showed |
60 | 52 | @page.hit |
... | ... | @@ -119,7 +111,11 @@ class ContentViewerController < ApplicationController |
119 | 111 | def add_comment |
120 | 112 | @comment.author = user if logged_in? |
121 | 113 | @comment.article = @page |
122 | - if (logged_in? || @comment.reply_of_id || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save | |
114 | + @comment.ip_address = request.remote_ip | |
115 | + plugins_filter_comment(@comment) | |
116 | + return if @comment.rejected? | |
117 | + if (pass_without_comment_captcha? || verify_recaptcha(:model => @comment, :message => _('Please type the words correctly'))) && @comment.save | |
118 | + plugins_comment_saved(@comment) | |
123 | 119 | @page.touch |
124 | 120 | @comment = nil # clear the comment form |
125 | 121 | redirect_to :action => 'view_page', :profile => params[:profile], :page => @page.explode_path, :view => params[:view] |
... | ... | @@ -128,6 +124,23 @@ class ContentViewerController < ApplicationController |
128 | 124 | end |
129 | 125 | end |
130 | 126 | |
127 | + def plugins_filter_comment(comment) | |
128 | + @plugins.each do |plugin| | |
129 | + plugin.filter_comment(comment) | |
130 | + end | |
131 | + end | |
132 | + | |
133 | + def plugins_comment_saved(comment) | |
134 | + @plugins.each do |plugin| | |
135 | + plugin.comment_saved(comment) | |
136 | + end | |
137 | + end | |
138 | + | |
139 | + def pass_without_comment_captcha? | |
140 | + logged_in? && !environment.enabled?('captcha_for_logged_users') | |
141 | + end | |
142 | + helper_method :pass_without_comment_captcha? | |
143 | + | |
131 | 144 | def remove_comment |
132 | 145 | @comment = @page.comments.find(params[:remove_comment]) |
133 | 146 | if (user == @comment.author || user == @page.profile || user.has_permission?(:moderate_comments, @page.profile)) | ... | ... |
app/controllers/public/enterprise_registration_controller.rb
app/controllers/public/home_controller.rb
app/controllers/public/profile_controller.rb
... | ... | @@ -23,7 +23,7 @@ class ProfileController < PublicController |
23 | 23 | |
24 | 24 | def tags |
25 | 25 | @tags_cache_key = "tags_profile_#{profile.id.to_s}" |
26 | - if is_cache_expired?(@tags_cache_key, true) | |
26 | + if is_cache_expired?(@tags_cache_key) | |
27 | 27 | @tags = profile.article_tags |
28 | 28 | end |
29 | 29 | end |
... | ... | @@ -31,7 +31,7 @@ class ProfileController < PublicController |
31 | 31 | def content_tagged |
32 | 32 | @tag = params[:id] |
33 | 33 | @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_#{profile.id.to_s}_page_#{params[:npage]}" |
34 | - if is_cache_expired?(@tag_cache_key, true) | |
34 | + if is_cache_expired?(@tag_cache_key) | |
35 | 35 | @tagged = profile.find_tagged_with(@tag).paginate(:per_page => 20, :page => params[:npage]) |
36 | 36 | end |
37 | 37 | end |
... | ... | @@ -211,7 +211,8 @@ class ProfileController < PublicController |
211 | 211 | |
212 | 212 | def remove_activity |
213 | 213 | begin |
214 | - activity = current_person.tracked_actions.find(params[:activity_id]) | |
214 | + raise if !can_edit_profile | |
215 | + activity = ActionTracker::Record.find(params[:activity_id]) | |
215 | 216 | activity.destroy |
216 | 217 | render :text => _('Activity successfully removed.') |
217 | 218 | rescue |
... | ... | @@ -219,6 +220,17 @@ class ProfileController < PublicController |
219 | 220 | end |
220 | 221 | end |
221 | 222 | |
223 | + def remove_notification | |
224 | + begin | |
225 | + raise if !can_edit_profile | |
226 | + notification = ActionTrackerNotification.find(:first, :conditions => {:profile_id => profile.id, :action_tracker_id => params[:activity_id]}) | |
227 | + notification.destroy | |
228 | + render :text => _('Notification successfully removed.') | |
229 | + rescue | |
230 | + render :text => _('You could not remove this notification.') | |
231 | + end | |
232 | + end | |
233 | + | |
222 | 234 | def profile_info |
223 | 235 | begin |
224 | 236 | @block = profile.blocks.find(params[:block_id]) |
... | ... | @@ -320,4 +332,8 @@ class ProfileController < PublicController |
320 | 332 | 20 |
321 | 333 | end |
322 | 334 | |
335 | + def can_edit_profile | |
336 | + @can_edit_profile ||= user && user.has_permission?('edit_profile', profile) | |
337 | + end | |
338 | + helper_method :can_edit_profile | |
323 | 339 | end | ... | ... |
app/controllers/public/search_controller.rb
... | ... | @@ -207,7 +207,7 @@ class SearchController < PublicController |
207 | 207 | |
208 | 208 | def tags |
209 | 209 | @tags_cache_key = "tags_env_#{environment.id.to_s}" |
210 | - if is_cache_expired?(@tags_cache_key, true) | |
210 | + if is_cache_expired?(@tags_cache_key) | |
211 | 211 | @tags = environment.tag_counts |
212 | 212 | end |
213 | 213 | end |
... | ... | @@ -215,7 +215,7 @@ class SearchController < PublicController |
215 | 215 | def tag |
216 | 216 | @tag = params[:tag] |
217 | 217 | @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_env_#{environment.id.to_s}_page_#{params[:npage]}" |
218 | - if is_cache_expired?(@tag_cache_key, true) | |
218 | + if is_cache_expired?(@tag_cache_key) | |
219 | 219 | @tagged = environment.articles.find_tagged_with(@tag).paginate(:per_page => 10, :page => params[:npage]) |
220 | 220 | end |
221 | 221 | end | ... | ... |
app/controllers/public_controller.rb
app/helpers/account_helper.rb
1 | 1 | module AccountHelper |
2 | 2 | |
3 | + def validation_classes | |
4 | + 'available unavailable valid invalid checking' | |
5 | + end | |
6 | + | |
7 | + def checking_message(key) | |
8 | + case key | |
9 | + when :url | |
10 | + _('Checking availability of login name...') | |
11 | + when :email | |
12 | + _('Checking if e-mail address is already taken...') | |
13 | + end | |
14 | + end | |
3 | 15 | end | ... | ... |
app/helpers/application_helper.rb
1 | +require 'redcloth' | |
2 | + | |
1 | 3 | # Methods added to this helper will be available to all templates in the |
2 | 4 | # application. |
3 | 5 | module ApplicationHelper |
... | ... | @@ -95,7 +97,7 @@ module ApplicationHelper |
95 | 97 | text = content_tag('div', button + content_tag('div', content_tag('div', content) + close_button, :class => 'help_message', :id => help_id, :style => 'display: none;'), :class => 'help_box') |
96 | 98 | |
97 | 99 | unless block.nil? |
98 | - concat(text, block.binding) | |
100 | + concat(text) | |
99 | 101 | end |
100 | 102 | |
101 | 103 | text |
... | ... | @@ -256,7 +258,7 @@ module ApplicationHelper |
256 | 258 | end |
257 | 259 | |
258 | 260 | def button_bar(options = {}, &block) |
259 | - concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), { :class => 'button-bar' }.merge(options)), block.binding) | |
261 | + concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), { :class => 'button-bar' }.merge(options))) | |
260 | 262 | end |
261 | 263 | |
262 | 264 | VIEW_EXTENSIONS = %w[.rhtml .html.erb] |
... | ... | @@ -538,7 +540,7 @@ module ApplicationHelper |
538 | 540 | {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, |
539 | 541 | {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}}, |
540 | 542 | {_('Join') => {:href => url_for(profile.join_url), :class => 'join-community', :style => 'display: none'}}, |
541 | - {_('Leave') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}}, | |
543 | + {_('Leave community') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}}, | |
542 | 544 | {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}} |
543 | 545 | ] |
544 | 546 | elsif profile.kind_of?(Enterprise) |
... | ... | @@ -587,19 +589,20 @@ module ApplicationHelper |
587 | 589 | |
588 | 590 | def gravatar_url_for(email, options = {}) |
589 | 591 | # Ta dando erro de roteamento |
590 | - url_for( { :gravatar_id => Digest::MD5.hexdigest(email), | |
592 | + default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil | |
593 | + url_for( { :gravatar_id => Digest::MD5.hexdigest(email.to_s), | |
591 | 594 | :host => 'www.gravatar.com', |
592 | 595 | :protocol => 'http://', |
593 | 596 | :only_path => false, |
594 | 597 | :controller => 'avatar.php', |
595 | - :d => NOOSFERO_CONF['gravatar'] ? NOOSFERO_CONF['gravatar'] : nil | |
598 | + :d => default | |
596 | 599 | }.merge(options) ) |
597 | 600 | end |
598 | 601 | |
599 | 602 | def str_gravatar_url_for(email, options = {}) |
600 | - default = NOOSFERO_CONF['gravatar'] ? NOOSFERO_CONF['gravatar'] : nil | |
603 | + default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil | |
601 | 604 | url = 'http://www.gravatar.com/avatar.php?gravatar_id=' + |
602 | - Digest::MD5.hexdigest(email) | |
605 | + Digest::MD5.hexdigest(email.to_s) | |
603 | 606 | { |
604 | 607 | :only_path => false, |
605 | 608 | :d => default |
... | ... | @@ -609,6 +612,10 @@ module ApplicationHelper |
609 | 612 | url |
610 | 613 | end |
611 | 614 | |
615 | + def gravatar_profile_url(email) | |
616 | + 'http://www.gravatar.com/'+ Digest::MD5.hexdigest(email.to_s) | |
617 | + end | |
618 | + | |
612 | 619 | attr_reader :environment |
613 | 620 | def select_categories(object_name, title=nil, title_size=4) |
614 | 621 | return nil if environment.enabled?(:disable_categories) |
... | ... | @@ -753,7 +760,7 @@ module ApplicationHelper |
753 | 760 | |
754 | 761 | # Should be on the forms_helper file but when its there the translation of labels doesn't work |
755 | 762 | class NoosferoFormBuilder < ActionView::Helpers::FormBuilder |
756 | - extend ActionView::Helpers::TagHelper | |
763 | + extend ActionView::Helpers::TagHelper | |
757 | 764 | |
758 | 765 | def self.output_field(text, field_html, field_id = nil) |
759 | 766 | # try to guess an id if none given |
... | ... | @@ -775,7 +782,7 @@ module ApplicationHelper |
775 | 782 | (field_helpers - %w(hidden_field)).each do |selector| |
776 | 783 | src = <<-END_SRC |
777 | 784 | def #{selector}(field, *args, &proc) |
778 | - text = object.class.human_attribute_name(field.to_s) | |
785 | + text = object.class.respond_to?(:human_attribute_name) && object.class.human_attribute_name(field.to_s) || field.to_s.humanize | |
779 | 786 | NoosferoFormBuilder::output_field(text, super) |
780 | 787 | end |
781 | 788 | END_SRC |
... | ... | @@ -877,7 +884,7 @@ module ApplicationHelper |
877 | 884 | end |
878 | 885 | |
879 | 886 | if block |
880 | - concat(result, block.binding) | |
887 | + concat(result) | |
881 | 888 | end |
882 | 889 | |
883 | 890 | result |
... | ... | @@ -909,18 +916,11 @@ module ApplicationHelper |
909 | 916 | |
910 | 917 | def login_url |
911 | 918 | options = Noosfero.url_options.merge({ :controller => 'account', :action => 'login' }) |
912 | - if environment.enable_ssl && (ENV['RAILS_ENV'] != 'development') | |
913 | - options.merge!(:protocol => 'https://', :host => ssl_hostname) | |
914 | - end | |
915 | 919 | url_for(options) |
916 | 920 | end |
917 | 921 | |
918 | - def ssl_hostname | |
919 | - environment.default_hostname | |
920 | - end | |
921 | - | |
922 | 922 | def base_url |
923 | - environment.top_url(request.ssl?) | |
923 | + environment.top_url | |
924 | 924 | end |
925 | 925 | |
926 | 926 | def helper_for_article(article) |
... | ... | @@ -985,7 +985,7 @@ module ApplicationHelper |
985 | 985 | 'thickbox', |
986 | 986 | 'lightbox', |
987 | 987 | 'colorpicker', |
988 | - colorbox_stylesheet_path, | |
988 | + 'colorbox', | |
989 | 989 | pngfix_stylesheet_path, |
990 | 990 | ] + |
991 | 991 | tokeninput_stylesheets |
... | ... | @@ -1000,10 +1000,6 @@ module ApplicationHelper |
1000 | 1000 | 'iepngfix/iepngfix.css' |
1001 | 1001 | end |
1002 | 1002 | |
1003 | - def colorbox_stylesheet_path | |
1004 | - 'colorbox/colorbox.css' | |
1005 | - end | |
1006 | - | |
1007 | 1003 | def tokeninput_stylesheets |
1008 | 1004 | ['token-input', 'token-input-facebook', 'token-input-mac'] |
1009 | 1005 | end |
... | ... | @@ -1024,7 +1020,7 @@ module ApplicationHelper |
1024 | 1020 | options.merge!(:page => params[:npage]) |
1025 | 1021 | content = article.to_html(options) |
1026 | 1022 | content = content.kind_of?(Proc) ? self.instance_eval(&content) : content |
1027 | - @plugins && @plugins.enabled_plugins.each do |plugin| | |
1023 | + @plugins && @plugins.each do |plugin| | |
1028 | 1024 | content = plugin.parse_content(content) |
1029 | 1025 | end |
1030 | 1026 | content |
... | ... | @@ -1134,15 +1130,26 @@ module ApplicationHelper |
1134 | 1130 | link_to(content_tag(:span, _('Communities Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') |
1135 | 1131 | end |
1136 | 1132 | |
1133 | + def browse_contents_menu | |
1134 | + links = [ | |
1135 | + {s_('contents|More Comments') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_comments'})}}, | |
1136 | + {s_('contents|More Views') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_views'})}}, | |
1137 | + {s_('contents|More Recent') => {:href => url_for({:controller => 'browse', :action => 'contents', :filter => 'more_recent'})}} | |
1138 | + ] | |
1139 | + | |
1140 | + link_to(content_tag(:span, _('Contents'), :class => 'icon-blog'), {:controller => "browse", :action => 'contents'}, :id => 'submenu-contents') + | |
1141 | + link_to(content_tag(:span, _('Contents Menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger') | |
1142 | + end | |
1143 | + | |
1137 | 1144 | def pagination_links(collection, options={}) |
1138 | - options = {:prev_label => '« ' + _('Previous'), :next_label => _('Next') + ' »'}.merge(options) | |
1145 | + options = {:previous_label => '« ' + _('Previous'), :next_label => _('Next') + ' »'}.merge(options) | |
1139 | 1146 | will_paginate(collection, options) |
1140 | 1147 | end |
1141 | 1148 | |
1142 | 1149 | def render_environment_features(folder) |
1143 | 1150 | result = '' |
1144 | 1151 | environment.enabled_features.keys.each do |feature| |
1145 | - file = File.join(@controller.view_paths, 'shared', folder.to_s, "#{feature}.rhtml") | |
1152 | + file = File.join(@controller.view_paths.last, 'shared', folder.to_s, "#{feature}.rhtml") | |
1146 | 1153 | if File.exists?(file) |
1147 | 1154 | result << render(:file => file, :use_full_path => false) |
1148 | 1155 | end |
... | ... | @@ -1166,7 +1173,7 @@ module ApplicationHelper |
1166 | 1173 | pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) |
1167 | 1174 | end |
1168 | 1175 | |
1169 | - (_('Welcome, %s') % link_to('<i></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + | |
1176 | + (_("<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'))) + | |
1170 | 1177 | render_environment_features(:usermenu) + |
1171 | 1178 | 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') + |
1172 | 1179 | manage_enterprises.to_s + |
... | ... | @@ -1226,7 +1233,7 @@ module ApplicationHelper |
1226 | 1233 | wrapper = content_tag(:div, capture(&block), :class => 'comment-balloon-content') |
1227 | 1234 | (1..8).to_a.reverse.each { |i| wrapper = content_tag(:div, wrapper, :class => "comment-wrapper-#{i}") } |
1228 | 1235 | classes = options.delete(:class) || options.delete("class") || '' |
1229 | - concat(content_tag('div', wrapper + tag('br', :style => 'clear: both;'), { :class => 'comment-balloon ' + classes.to_s }.merge(options)), block.binding) | |
1236 | + concat(content_tag('div', wrapper + tag('br', :style => 'clear: both;'), { :class => 'comment-balloon ' + classes.to_s }.merge(options))) | |
1230 | 1237 | end |
1231 | 1238 | |
1232 | 1239 | def display_source_info(page) |
... | ... | @@ -1247,25 +1254,27 @@ module ApplicationHelper |
1247 | 1254 | task.information[:message] % values |
1248 | 1255 | end |
1249 | 1256 | |
1257 | + def add_zoom_to_article_images | |
1258 | + add_zoom_to_images if environment.enabled?(:show_zoom_button_on_article_images) | |
1259 | + end | |
1260 | + | |
1250 | 1261 | def add_zoom_to_images |
1251 | - if environment.enabled?(:show_zoom_button_on_article_images) | |
1252 | - stylesheet_link_tag('fancybox') + | |
1253 | - javascript_include_tag('jquery.fancybox-1.3.4.pack') + | |
1254 | - javascript_tag("jQuery(function($) { | |
1255 | - $(window).load( function() { | |
1256 | - $('#article .article-body img').each( function(index) { | |
1257 | - var original = original_image_dimensions($(this).attr('src')); | |
1258 | - if ($(this).width() < original['width'] || $(this).height() < original['height']) { | |
1259 | - $(this).wrap('<div class=\"zoomable-image\" />'); | |
1260 | - $(this).parent('.zoomable-image').attr('style', $(this).attr('style')); | |
1261 | - $(this).attr('style', ''); | |
1262 | - $(this).after(\'<a href=\"' + $(this).attr('src') + '\" class=\"zoomify-image\"><span class=\"zoomify-text\">%s</span></a>'); | |
1263 | - } | |
1264 | - }); | |
1265 | - $('.zoomify-image').fancybox(); | |
1262 | + stylesheet_link_tag('fancybox') + | |
1263 | + javascript_include_tag('jquery.fancybox-1.3.4.pack') + | |
1264 | + javascript_tag("jQuery(function($) { | |
1265 | + $(window).load( function() { | |
1266 | + $('#article .article-body img').each( function(index) { | |
1267 | + var original = original_image_dimensions($(this).attr('src')); | |
1268 | + if ($(this).width() < original['width'] || $(this).height() < original['height']) { | |
1269 | + $(this).wrap('<div class=\"zoomable-image\" />'); | |
1270 | + $(this).parent('.zoomable-image').attr('style', $(this).attr('style')); | |
1271 | + $(this).attr('style', ''); | |
1272 | + $(this).after(\'<a href=\"' + $(this).attr('src') + '\" class=\"zoomify-image\"><span class=\"zoomify-text\">%s</span></a>'); | |
1273 | + } | |
1266 | 1274 | }); |
1267 | - });" % _('Zoom in')) | |
1268 | - end | |
1275 | + $('.zoomify-image').fancybox(); | |
1276 | + }); | |
1277 | + });" % _('Zoom in')) | |
1269 | 1278 | end |
1270 | 1279 | |
1271 | 1280 | def render_dialog_error_messages(instance_name) |
... | ... | @@ -1303,4 +1312,29 @@ module ApplicationHelper |
1303 | 1312 | ) + content_tag('span', ' | ', :class => 'comment-footer comment-footer-hide') |
1304 | 1313 | end |
1305 | 1314 | end |
1315 | + | |
1316 | + def cache_timeout(key, timeout, &block) | |
1317 | + cache(key, { :expires_in => timeout }, &block) | |
1318 | + end | |
1319 | + | |
1320 | + def is_cache_expired?(key) | |
1321 | + !cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller)) | |
1322 | + end | |
1323 | + | |
1324 | + def render_tabs(tabs) | |
1325 | + titles = tabs.inject(''){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') } | |
1326 | + contents = tabs.inject(''){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) } | |
1327 | + | |
1328 | + content_tag :div, :class => 'ui-tabs' do | |
1329 | + content_tag(:ul, titles) + contents | |
1330 | + end | |
1331 | + end | |
1332 | + | |
1333 | + def delete_article_message(article) | |
1334 | + if article.folder? | |
1335 | + _("Are you sure that you want to remove the folder \"#{article.name}\"? Note that all the items inside it will also be removed!") | |
1336 | + else | |
1337 | + _("Are you sure that you want to remove the item \"#{article.name}\"?") | |
1338 | + end | |
1339 | + end | |
1306 | 1340 | end | ... | ... |
app/helpers/blog_helper.rb
... | ... | @@ -17,7 +17,7 @@ module BlogHelper |
17 | 17 | def list_posts(articles, format = 'full') |
18 | 18 | pagination = will_paginate(articles, { |
19 | 19 | :param_name => 'npage', |
20 | - :prev_label => _('« Newer posts'), | |
20 | + :previous_label => _('« Newer posts'), | |
21 | 21 | :next_label => _('Older posts »') |
22 | 22 | }) |
23 | 23 | content = [] | ... | ... |
app/helpers/boxes_helper.rb
... | ... | @@ -81,8 +81,8 @@ module BoxesHelper |
81 | 81 | box_decorator == DontMoveBlocks |
82 | 82 | end |
83 | 83 | |
84 | - def display_block_content(block, main_content = nil) | |
85 | - content = block.main? ? wrap_main_content(main_content) : block.content | |
84 | + def display_block_content(block, person, main_content = nil) | |
85 | + content = block.main? ? wrap_main_content(main_content) : block.content({:person => person}) | |
86 | 86 | result = extract_block_content(content) |
87 | 87 | footer_content = extract_block_content(block.footer) |
88 | 88 | unless footer_content.blank? |
... | ... | @@ -99,7 +99,7 @@ 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 | - @controller.send(:content_editor?) || @plugins.enabled_plugins.each do |plugin| | |
102 | + @controller.send(:content_editor?) || @plugins.each do |plugin| | |
103 | 103 | result = plugin.parse_content(result) |
104 | 104 | end |
105 | 105 | box_decorator.block_target(block.box, block) + | ... | ... |
app/helpers/catalog_helper.rb
1 | 1 | module CatalogHelper |
2 | 2 | |
3 | -include DisplayHelper | |
4 | -include ManageProductsHelper | |
3 | + include DisplayHelper | |
4 | + include ManageProductsHelper | |
5 | 5 | |
6 | - def display_products_list(profile, products) | |
7 | - data = '' | |
8 | - extra_content = [] | |
9 | - extra_content_list = [] | |
10 | - products.each { |product| | |
11 | - extra_content = @plugins.map(:catalog_item_extras, product).collect { |content| instance_eval(&content) } if @plugins | |
12 | - extra_content_list = @plugins.map(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } if @plugins | |
13 | - data << content_tag('li', | |
14 | - link_to_product(product, :class => 'product-pic', :style => 'background-image:url(%s)' % product.default_image(:portrait) ) + | |
15 | - content_tag('h3', link_to_product(product)) + | |
16 | - content_tag('ul', | |
17 | - (product.price ? content_tag('li', _('Price: %s') % ( "%.2f" % product.price), :class => 'product_price') : '') + | |
18 | - content_tag('li', product_category_name(profile, product.product_category), :class => 'product_category') + | |
19 | - extra_content_list.map { |content| content_tag('li', content)}.join("\n") | |
20 | - ) + | |
21 | - (product.description ? content_tag('div', | |
22 | - txt2html(product.description), | |
23 | - :class => 'description') : tag('br', | |
24 | - :style => 'clear:both')) + | |
25 | - extra_content.join("\n"), | |
26 | - :class => 'product') | |
27 | - } | |
28 | - content_tag('h1', _('Products/Services')) + content_tag('ul', data, :id => 'product_list') | |
29 | - end | |
30 | - | |
31 | - private | |
32 | - | |
33 | - def product_category_name(profile, product_category) | |
34 | - if profile.enabled? | |
35 | - link_to_product_category(product_category) | |
36 | - else | |
37 | - product_category ? product_category.full_name(' → ') : _('Uncategorized product') | |
38 | - end | |
39 | - end | |
40 | 6 | end | ... | ... |
app/helpers/cms_helper.rb
... | ... | @@ -16,7 +16,7 @@ module CmsHelper |
16 | 16 | end |
17 | 17 | |
18 | 18 | def pagination_links(collection, options={}) |
19 | - options = {:prev_label => '« ', :next_label => ' »', :page_links => false}.merge(options) | |
19 | + options = {:previous_label => '« ', :next_label => ' »', :page_links => false}.merge(options) | |
20 | 20 | will_paginate(collection, options) |
21 | 21 | end |
22 | 22 | |
... | ... | @@ -49,12 +49,6 @@ module CmsHelper |
49 | 49 | end |
50 | 50 | |
51 | 51 | def display_delete_button(article) |
52 | - confirm_message = if article.folder? | |
53 | - _('Are you sure that you want to remove this folder? Note that all the items inside it will also be removed!') | |
54 | - else | |
55 | - _('Are you sure that you want to remove this item?') | |
56 | - end | |
57 | - | |
58 | - button_without_text :delete, _('Delete'), { :action => 'destroy', :id => article.id }, :method => :post, :confirm => confirm_message | |
52 | + button_without_text :delete, _('Delete'), { :action => 'destroy', :id => article.id }, :method => :post, :confirm => delete_article_message(article) | |
59 | 53 | end |
60 | 54 | end | ... | ... |
app/helpers/content_viewer_helper.rb
... | ... | @@ -55,7 +55,7 @@ module ContentViewerHelper |
55 | 55 | "http://www.facebook.com/sharer.php?s=100&p[title]=%{title}&p[summary]=%{summary}&p[url]=%{url}&p[images][0]=%{image}" % { |
56 | 56 | :title => CGI.escape(article.title), |
57 | 57 | :url => CGI.escape(url_for(article.url)), |
58 | - :summary => CGI.escape(truncate(strip_tags(article.body.to_s), 300)), | |
58 | + :summary => CGI.escape(truncate(strip_tags(article.body.to_s), :length => 300)), | |
59 | 59 | :image => CGI.escape(article.body_images_paths.first.to_s) |
60 | 60 | } |
61 | 61 | end | ... | ... |
app/helpers/dates_helper.rb
... | ... | @@ -42,11 +42,11 @@ module DatesHelper |
42 | 42 | end |
43 | 43 | end |
44 | 44 | |
45 | - def show_period(date1, date2 = nil) | |
45 | + def show_period(date1, date2 = nil, use_numbers = false) | |
46 | 46 | if (date1 == date2) || (date2.nil?) |
47 | - show_date(date1) | |
47 | + show_date(date1, use_numbers) | |
48 | 48 | else |
49 | - _('from %{date1} to %{date2}') % {:date1 => show_date(date1), :date2 => show_date(date2)} | |
49 | + _('from %{date1} to %{date2}') % {:date1 => show_date(date1, use_numbers), :date2 => show_date(date2, use_numbers)} | |
50 | 50 | end |
51 | 51 | end |
52 | 52 | ... | ... |
app/helpers/display_helper.rb
... | ... | @@ -8,6 +8,20 @@ module DisplayHelper |
8 | 8 | opts |
9 | 9 | end |
10 | 10 | |
11 | + def image_link_to_product(product, opts={}) | |
12 | + return _('No product') unless product | |
13 | + target = product_path(product) | |
14 | + link_to image_tag(product.default_image(:big), :alt => product.name), | |
15 | + target, | |
16 | + opts | |
17 | + end | |
18 | + | |
19 | + def price_span(price, options = {}) | |
20 | + content_tag 'span', | |
21 | + number_to_currency(price, :unit => environment.currency_unit, :delimiter => environment.currency_delimiter, :separator => environment.currency_separator), | |
22 | + options | |
23 | + end | |
24 | + | |
11 | 25 | def product_path(product) |
12 | 26 | product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url |
13 | 27 | end | ... | ... |
app/helpers/forms_helper.rb
... | ... | @@ -14,9 +14,9 @@ module FormsHelper |
14 | 14 | |
15 | 15 | def labelled_check_box( human_name, name, value = "1", checked = false, options = {} ) |
16 | 16 | options[:id] ||= 'checkbox-' + FormsHelper.next_id_number |
17 | - check_box_tag( name, value, checked, options ) + | |
18 | - content_tag( 'label', human_name, :for => options[:id] ) + | |
19 | - hidden_field_tag(name, '0') | |
17 | + hidden_field_tag(name, '0') + | |
18 | + check_box_tag( name, value, checked, options ) + | |
19 | + content_tag( 'label', human_name, :for => options[:id] ) | |
20 | 20 | end |
21 | 21 | |
22 | 22 | def labelled_text_field( human_name, name, value=nil, options={} ) | ... | ... |
app/helpers/forum_helper.rb
... | ... | @@ -11,7 +11,7 @@ module ForumHelper |
11 | 11 | def list_forum_posts(articles) |
12 | 12 | pagination = will_paginate(articles, { |
13 | 13 | :param_name => 'npage', |
14 | - :prev_label => _('« Newer posts'), | |
14 | + :previous_label => _('« Newer posts'), | |
15 | 15 | :next_label => _('Older posts »') |
16 | 16 | }) |
17 | 17 | content = [content_tag('tr', | ... | ... |
app/helpers/manage_products_helper.rb
... | ... | @@ -55,7 +55,7 @@ module ManageProductsHelper |
55 | 55 | def options_for_select_categories(categories, selected = nil) |
56 | 56 | categories.sort_by{|cat| cat.name.transliterate}.map do |category| |
57 | 57 | selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '') |
58 | - "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{truncate(category.name, 33) + (category.leaf? ? '': ' »')}</option>" | |
58 | + "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{truncate(category.name, :length => 33) + (category.leaf? ? '': ' »')}</option>" | |
59 | 59 | end.join("\n") |
60 | 60 | end |
61 | 61 | |
... | ... | @@ -271,4 +271,23 @@ module ManageProductsHelper |
271 | 271 | return input_amount_used if input.unit.blank? |
272 | 272 | n_('1 %{singular_unit}', '%{num} %{plural_unit}', input.amount_used.to_f) % { :num => input_amount_used, :singular_unit => content_tag('span', input.unit.singular, :class => 'input-unit'), :plural_unit => content_tag('span', input.unit.plural, :class => 'input-unit') } |
273 | 273 | end |
274 | + | |
275 | + def select_production_cost(product,selected=nil) | |
276 | + url = url_for( :controller => 'manage_products', :action => 'create_production_cost' ) | |
277 | + prompt_msg = _('Insert the name of the new cost:') | |
278 | + error_msg = _('Something went wrong. Please, try again') | |
279 | + select_tag('price_details[][production_cost_id]', | |
280 | + '<option value="" disabled="disabled">' + _('Select...') + '</option>' + | |
281 | + options_for_select(product.available_production_costs.map {|item| [truncate(item.name, 10, '...'), item.id]} + [[_('Other cost'), '']], selected), | |
282 | + {:class => 'production-cost-selection', | |
283 | + :onchange => "productionCostTypeChange(this, '#{url}', '#{prompt_msg}', '#{error_msg}')"}) | |
284 | + end | |
285 | + | |
286 | + def price_composition_progressbar_text(product, args = {}) | |
287 | + currency = environment.currency_unit | |
288 | + production_cost = args[:production_cost_value] || product.formatted_value(:total_production_cost) | |
289 | + product_price = args[:product_price] || product.formatted_value(:price) | |
290 | + | |
291 | + _("%{currency} %{production_cost} of %{currency} %{product_price}") % {:currency => currency, :production_cost => content_tag('span', production_cost, :class => 'production_cost'), :product_price => content_tag('span', product_price, :class => 'product_price')} | |
292 | + end | |
274 | 293 | end | ... | ... |
app/helpers/profile_editor_helper.rb
... | ... | @@ -137,8 +137,8 @@ module ProfileEditorHelper |
137 | 137 | content_tag( |
138 | 138 | 'div', |
139 | 139 | capture(&block) + '<br style="clear:left;"/> ', |
140 | - :class => 'control-panel'), | |
141 | - block.binding) | |
140 | + :class => 'control-panel') | |
141 | + ) | |
142 | 142 | end |
143 | 143 | |
144 | 144 | def control_panel_button(title, icon, url) | ... | ... |
app/helpers/profile_helper.rb
... | ... | @@ -15,12 +15,4 @@ module ProfileHelper |
15 | 15 | end |
16 | 16 | end |
17 | 17 | |
18 | - def render_tabs(tabs) | |
19 | - titles = tabs.inject(''){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') } | |
20 | - contents = tabs.inject(''){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) } | |
21 | - | |
22 | - content_tag :div, :class => 'ui-tabs' do | |
23 | - content_tag(:ul, titles) + contents | |
24 | - end | |
25 | - end | |
26 | 18 | end | ... | ... |
app/helpers/sweeper_helper.rb
... | ... | @@ -4,9 +4,7 @@ module SweeperHelper |
4 | 4 | ActionController::Base.new().expire_fragment(*args) |
5 | 5 | end |
6 | 6 | |
7 | - def expire_timeout_fragment(*args) | |
8 | - ActionController::Base.new().expire_timeout_fragment(*args) | |
9 | - end | |
7 | + alias :expire_timeout_fragment :expire_fragment | |
10 | 8 | |
11 | 9 | def expire_friends(profile) |
12 | 10 | # public friends page |
... | ... | @@ -22,7 +20,7 @@ module SweeperHelper |
22 | 20 | |
23 | 21 | # friends blocks |
24 | 22 | blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)} |
25 | - blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)} | |
23 | + BlockSweeper.expire_blocks(blocks) | |
26 | 24 | end |
27 | 25 | |
28 | 26 | def expire_communities(profile) |
... | ... | @@ -34,13 +32,13 @@ module SweeperHelper |
34 | 32 | |
35 | 33 | # communities block |
36 | 34 | blocks = profile.blocks.select{|b| b.kind_of?(CommunitiesBlock)} |
37 | - blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)} | |
35 | + BlockSweeper.expire_blocks(blocks) | |
38 | 36 | end |
39 | 37 | |
40 | 38 | def expire_enterprises(profile) |
41 | 39 | # enterprises and favorite enterprises blocks |
42 | 40 | blocks = profile.blocks.select {|b| [EnterprisesBlock, FavoriteEnterprisesBlock].any?{|klass| b.kind_of?(klass)} } |
43 | - blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)} | |
41 | + BlockSweeper.expire_blocks(blocks) | |
44 | 42 | end |
45 | 43 | |
46 | 44 | def expire_profile_index(profile) | ... | ... |
app/helpers/tags_helper.rb
... | ... | @@ -50,7 +50,7 @@ module TagsHelper |
50 | 50 | style = ""+ |
51 | 51 | "font-size: #{ (v * delta).round + min_size }px;"+ |
52 | 52 | "top: #{ -(delta/2) - (v * (delta/2)).round }px;" |
53 | - destination = url.kind_of?(Hash) ? url_for(url.merge(tagname_option => tag)) : (url.to_s + tag) | |
53 | + destination = url.merge(tagname_option => tag) | |
54 | 54 | |
55 | 55 | if options[:show_count] |
56 | 56 | display_count = options[:show_count] ? "<small><sup>(#{count})</sup></small>" : "" | ... | ... |
app/models/add_member.rb
... | ... | @@ -11,7 +11,9 @@ class AddMember < Task |
11 | 11 | settings_items :roles |
12 | 12 | |
13 | 13 | def perform |
14 | - self.roles ||= [Profile::Roles.member(organization.environment.id).id] | |
14 | + if !self.roles or (self.roles.uniq.compact.length == 1 and self.roles.uniq.compact.first.to_i.zero?) | |
15 | + self.roles = [Profile::Roles.member(organization.environment.id).id] | |
16 | + end | |
15 | 17 | target.affiliate(requestor, self.roles.select{|r| !r.to_i.zero? }.map{|i| Role.find(i)}) |
16 | 18 | end |
17 | 19 | ... | ... |
app/models/article.rb
... | ... | @@ -13,7 +13,7 @@ class Article < ActiveRecord::Base |
13 | 13 | validates_presence_of :profile_id, :name |
14 | 14 | validates_presence_of :slug, :path, :if => lambda { |article| !article.name.blank? } |
15 | 15 | |
16 | - validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('<!-- %{fn} -->The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? } | |
16 | + validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? } | |
17 | 17 | |
18 | 18 | belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id' |
19 | 19 | |
... | ... | @@ -34,7 +34,7 @@ class Article < ActiveRecord::Base |
34 | 34 | before_destroy :rotate_translations |
35 | 35 | |
36 | 36 | before_create do |article| |
37 | - article.published_at = article.created_at if article.published_at.nil? | |
37 | + article.published_at ||= Time.now | |
38 | 38 | if article.reference_article && !article.parent |
39 | 39 | parent = article.reference_article.parent |
40 | 40 | if parent && parent.blog? && article.profile.has_blog? |
... | ... | @@ -233,7 +233,7 @@ class Article < ActiveRecord::Base |
233 | 233 | |
234 | 234 | include ActionView::Helpers::TextHelper |
235 | 235 | def short_title |
236 | - truncate self.title, 15, '...' | |
236 | + truncate self.title, :length => 15, :omission => '...' | |
237 | 237 | end |
238 | 238 | |
239 | 239 | def belongs_to_blog? |
... | ... | @@ -355,11 +355,20 @@ class Article < ActiveRecord::Base |
355 | 355 | ['Folder', 'Blog', 'Forum', 'Gallery'] |
356 | 356 | end |
357 | 357 | |
358 | + def self.text_article_types | |
359 | + ['TextArticle', 'TextileArticle', 'TinyMceArticle'] | |
360 | + end | |
361 | + | |
358 | 362 | named_scope :published, :conditions => { :published => true } |
359 | 363 | named_scope :folders, :conditions => { :type => folder_types} |
360 | 364 | named_scope :no_folders, :conditions => ['type NOT IN (?)', folder_types] |
361 | 365 | named_scope :galleries, :conditions => { :type => 'Gallery' } |
362 | 366 | named_scope :images, :conditions => { :is_image => true } |
367 | + named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] | |
368 | + | |
369 | + named_scope :more_comments, :order => "comments_count DESC" | |
370 | + named_scope :more_views, :order => "hits DESC" | |
371 | + named_scope :more_recent, :order => "created_at DESC" | |
363 | 372 | |
364 | 373 | def self.display_filter(user, profile) |
365 | 374 | return {:conditions => ['published = ?', true]} if !user |
... | ... | @@ -487,8 +496,8 @@ class Article < ActiveRecord::Base |
487 | 496 | end |
488 | 497 | |
489 | 498 | alias :active_record_cache_key :cache_key |
490 | - def cache_key(params = {}, the_profile = nil) | |
491 | - active_record_cache_key + | |
499 | + def cache_key(params = {}, the_profile = nil, language = 'en') | |
500 | + active_record_cache_key+'-'+language + | |
492 | 501 | (allow_post_content?(the_profile) ? "-owner" : '') + |
493 | 502 | (params[:npage] ? "-npage-#{params[:npage]}" : '') + |
494 | 503 | (params[:year] ? "-year-#{params[:year]}" : '') + |
... | ... | @@ -505,7 +514,7 @@ class Article < ActiveRecord::Base |
505 | 514 | end |
506 | 515 | |
507 | 516 | def short_lead |
508 | - truncate sanitize_html(self.lead), 170, '...' | |
517 | + truncate sanitize_html(self.lead), :length => 170, :omission => '...' | |
509 | 518 | end |
510 | 519 | |
511 | 520 | def creator |
... | ... | @@ -528,6 +537,28 @@ class Article < ActiveRecord::Base |
528 | 537 | end |
529 | 538 | end |
530 | 539 | |
540 | + def more_comments_label | |
541 | + amount = self.comments_count | |
542 | + { | |
543 | + 0 => _('no comments'), | |
544 | + 1 => _('one comment') | |
545 | + }[amount] || _("%s comments") % amount | |
546 | + | |
547 | + end | |
548 | + | |
549 | + def more_views_label | |
550 | + amount = self.hits | |
551 | + { | |
552 | + 0 => _('no views'), | |
553 | + 1 => _('one view') | |
554 | + }[amount] || _("%s views") % amount | |
555 | + | |
556 | + end | |
557 | + | |
558 | + def more_recent_label | |
559 | + _('Created at: ') | |
560 | + end | |
561 | + | |
531 | 562 | private |
532 | 563 | |
533 | 564 | def sanitize_tag_list | ... | ... |
app/models/article_block.rb
... | ... | @@ -8,7 +8,7 @@ class ArticleBlock < Block |
8 | 8 | _('This block displays one of your articles. You can edit the block to select which one of your articles is going to be displayed in the block.') |
9 | 9 | end |
10 | 10 | |
11 | - def content | |
11 | + def content(args={}) | |
12 | 12 | block = self |
13 | 13 | lambda do |
14 | 14 | block_title(block.title) + | ... | ... |
app/models/block.rb
... | ... | @@ -81,7 +81,7 @@ class Block < ActiveRecord::Base |
81 | 81 | # The method can also return <tt>nil</tt>, which means "no content". |
82 | 82 | # |
83 | 83 | # See BoxesHelper#extract_block_content for implementation details. |
84 | - def content | |
84 | + def content(args={}) | |
85 | 85 | "This is block number %d" % self.id |
86 | 86 | end |
87 | 87 | |
... | ... | @@ -127,6 +127,11 @@ class Block < ActiveRecord::Base |
127 | 127 | true |
128 | 128 | end |
129 | 129 | |
130 | + alias :active_record_cache_key :cache_key | |
131 | + def cache_key(language='en') | |
132 | + active_record_cache_key+'-'+language | |
133 | + end | |
134 | + | |
130 | 135 | def timeout |
131 | 136 | 4.hours |
132 | 137 | end | ... | ... |
app/models/blog.rb
... | ... | @@ -68,7 +68,7 @@ class Blog < Folder |
68 | 68 | settings_items :visualization_format, :type => :string, :default => 'full' |
69 | 69 | validates_inclusion_of :visualization_format, :in => [ 'full', 'short' ], :if => :visualization_format |
70 | 70 | |
71 | - settings_items :display_posts_in_current_language, :type => :boolean, :default => true | |
71 | + settings_items :display_posts_in_current_language, :type => :boolean, :default => false | |
72 | 72 | |
73 | 73 | alias :display_posts_in_current_language? :display_posts_in_current_language |
74 | 74 | ... | ... |
app/models/blog_archives_block.rb
... | ... | @@ -20,11 +20,15 @@ class BlogArchivesBlock < Block |
20 | 20 | blog_id && owner.blogs.exists?(blog_id) ? owner.blogs.find(blog_id) : owner.blog |
21 | 21 | end |
22 | 22 | |
23 | - def content | |
23 | + def visible_posts(person) | |
24 | + blog.posts.native_translations.select {|post| post.display_to?(person)} | |
25 | + end | |
26 | + | |
27 | + def content(args={}) | |
24 | 28 | owner_blog = self.blog |
25 | 29 | return nil unless owner_blog |
26 | 30 | results = '' |
27 | - owner_blog.posts.native_translations.group_by {|i| i.published_at.year }.sort_by { |year,count| -year }.each do |year, results_by_year| | |
31 | + visible_posts(args[:person]).group_by {|i| i.published_at.year }.sort_by { |year,count| -year }.each do |year, results_by_year| | |
28 | 32 | results << content_tag('li', content_tag('strong', "#{year} (#{results_by_year.size})")) |
29 | 33 | results << "<ul class='#{year}-archive'>" |
30 | 34 | results_by_year.group_by{|i| [ ('%02d' % i.published_at.month()), gettext(MONTHS[i.published_at.month() - 1])]}.sort.reverse.each do |month, results_by_month| | ... | ... |
app/models/categories_block.rb
... | ... | @@ -28,7 +28,7 @@ class CategoriesBlock < Block |
28 | 28 | Category.top_level_for(self.owner).from_types(self.category_types) |
29 | 29 | end |
30 | 30 | |
31 | - def content | |
31 | + def content(args={}) | |
32 | 32 | block = self |
33 | 33 | lambda do |
34 | 34 | render :file => 'blocks/categories', :locals => { :block => block } | ... | ... |
app/models/category.rb
1 | 1 | class Category < ActiveRecord::Base |
2 | 2 | |
3 | - validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('%{fn} cannot be like that.') | |
3 | + validates_exclusion_of :slug, :in => [ 'index' ], :message => N_('%{fn} cannot be like that.').fix_i18n | |
4 | 4 | validates_presence_of :name, :environment_id |
5 | - validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.') | |
5 | + validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('%{fn} is already being used by another category.').fix_i18n | |
6 | 6 | belongs_to :environment |
7 | 7 | |
8 | 8 | validates_inclusion_of :display_color, :in => [ 1, 2, 3, 4, nil ] |
9 | - validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('%{fn} was already assigned to another category.') | |
9 | + 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 | |
10 | 10 | |
11 | 11 | # Finds all top level categories for a given environment. |
12 | 12 | named_scope :top_level_for, lambda { |environment| | ... | ... |
app/models/change_password.rb
... | ... | @@ -30,10 +30,10 @@ class ChangePassword < Task |
30 | 30 | unless data.login.blank? || data.email.blank? |
31 | 31 | user = User.find_by_login_and_environment_id(data.login, data.environment_id) |
32 | 32 | if user.nil? |
33 | - data.errors.add(:login, _('%{fn} is not a valid username.')) | |
33 | + data.errors.add(:login, _('%{fn} is not a valid username.').fix_i18n) | |
34 | 34 | else |
35 | 35 | if user.email != data.email |
36 | - data.errors.add(:email, _('%{fn} is invalid.')) | |
36 | + data.errors.add(:email) | |
37 | 37 | end |
38 | 38 | end |
39 | 39 | end | ... | ... |
app/models/comment.rb
... | ... | @@ -2,7 +2,7 @@ class Comment < ActiveRecord::Base |
2 | 2 | |
3 | 3 | track_actions :leave_comment, :after_create, :keep_params => ["article.title", "article.url", "title", "url", "body"], :custom_target => :action_tracker_target |
4 | 4 | |
5 | - validates_presence_of :title, :body | |
5 | + validates_presence_of :body | |
6 | 6 | belongs_to :article, :counter_cache => true |
7 | 7 | belongs_to :author, :class_name => 'Person', :foreign_key => 'author_id' |
8 | 8 | has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy |
... | ... | @@ -17,7 +17,7 @@ class Comment < ActiveRecord::Base |
17 | 17 | validates_presence_of :author_id, :if => (lambda { |rec| rec.name.blank? && rec.email.blank? }) |
18 | 18 | validates_each :name do |rec,attribute,value| |
19 | 19 | if rec.author_id && (!rec.name.blank? || !rec.email.blank?) |
20 | - rec.errors.add(:name, _('%{fn} can only be informed for unauthenticated authors')) | |
20 | + rec.errors.add(:name, _('%{fn} can only be informed for unauthenticated authors').fix_i18n) | |
21 | 21 | end |
22 | 22 | end |
23 | 23 | |
... | ... | @@ -126,4 +126,12 @@ class Comment < ActiveRecord::Base |
126 | 126 | end |
127 | 127 | end |
128 | 128 | |
129 | + def rejected? | |
130 | + @rejected | |
131 | + end | |
132 | + | |
133 | + def reject! | |
134 | + @rejected = true | |
135 | + end | |
136 | + | |
129 | 137 | end | ... | ... |
app/models/community.rb
app/models/create_community.rb
... | ... | @@ -16,7 +16,7 @@ class CreateCommunity < Task |
16 | 16 | def validate |
17 | 17 | self.environment.required_community_fields.each do |field| |
18 | 18 | if self.send(field).blank? |
19 | - self.errors.add(field, _('%{fn} can\'t be blank')) | |
19 | + self.errors.add_on_blank(field) | |
20 | 20 | end |
21 | 21 | end |
22 | 22 | end | ... | ... |
app/models/create_enterprise.rb
... | ... | @@ -40,12 +40,12 @@ class CreateEnterprise < Task |
40 | 40 | |
41 | 41 | if self.region && self.target |
42 | 42 | unless self.region.validators.include?(self.target) || self.target_type == "Environment" |
43 | - self.errors.add(:target, '%{fn} is not a validator for the chosen region') | |
43 | + self.errors.add(:target, _('%{fn} is not a validator for the chosen region').fix_i18n) | |
44 | 44 | end |
45 | 45 | end |
46 | 46 | |
47 | 47 | if self.status != Task::Status::CANCELLED && self.identifier && Profile.exists?(:identifier => self.identifier) |
48 | - self.errors.add(:identifier, '%{fn} is already being as identifier by another enterprise, organization or person.') | |
48 | + self.errors.add(:identifier, _('%{fn} is already being as identifier by another enterprise, organization or person.').fix_i18n) | |
49 | 49 | end |
50 | 50 | end |
51 | 51 | ... | ... |
app/models/disabled_enterprise_message_block.rb
... | ... | @@ -12,7 +12,7 @@ class DisabledEnterpriseMessageBlock < Block |
12 | 12 | _('Message') |
13 | 13 | end |
14 | 14 | |
15 | - def content | |
15 | + def content(args={}) | |
16 | 16 | message = self.owner.environment.message_for_disabled_enterprise || '' |
17 | 17 | lambda do |
18 | 18 | render :file => 'blocks/disabled_enterprise_message', :locals => {:message => message} | ... | ... |
app/models/domain.rb
... | ... | @@ -10,14 +10,14 @@ class Domain < ActiveRecord::Base |
10 | 10 | |
11 | 11 | # <tt>name</tt> must be a sequence of word characters (a to z, plus 0 to 9, |
12 | 12 | # plus '_'). Letters must be lowercase |
13 | - validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed only of lowercase latters (a to z), numbers (0 to 9), "_" and "-"') | |
13 | + validates_format_of :name, :with => /^([a-z0-9_-]+\.)+[a-z0-9_-]+$/, :message => N_('%{fn} must be composed only of lowercase latters (a to z), numbers (0 to 9), "_" and "-"').fix_i18n | |
14 | 14 | |
15 | 15 | # checks validations that could not be expressed using Rails' predefined |
16 | 16 | # validations. In particular: |
17 | 17 | # * <tt>name</tt> must not start with 'www.' |
18 | 18 | def validate |
19 | 19 | if self.name =~ /^www\./ |
20 | - self.errors.add(:name, _('%{fn} must not start with www.')) | |
20 | + self.errors.add(:name, _('%{fn} must not start with www.').fix_i18n) | |
21 | 21 | end |
22 | 22 | end |
23 | 23 | ... | ... |
app/models/enterprise.rb
... | ... | @@ -6,6 +6,7 @@ class Enterprise < Organization |
6 | 6 | |
7 | 7 | has_many :products, :dependent => :destroy, :order => 'name ASC' |
8 | 8 | has_many :inputs, :through => :products |
9 | + has_many :production_costs, :as => :owner | |
9 | 10 | |
10 | 11 | has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people' |
11 | 12 | |
... | ... | @@ -45,7 +46,7 @@ class Enterprise < Organization |
45 | 46 | super |
46 | 47 | self.required_fields.each do |field| |
47 | 48 | if self.send(field).blank? |
48 | - self.errors.add(field, _("%{fn} can't be blank")) | |
49 | + self.errors.add_on_blank(field) | |
49 | 50 | end |
50 | 51 | end |
51 | 52 | end |
... | ... | @@ -75,7 +76,11 @@ class Enterprise < Organization |
75 | 76 | end |
76 | 77 | |
77 | 78 | after_save do |e| |
78 | - e.products.each{ |p| p.enterprise_updated(e) } | |
79 | + e.delay.update_products_position | |
80 | + end | |
81 | + | |
82 | + def update_products_position | |
83 | + products.each{ |p| p.enterprise_updated(self) } | |
79 | 84 | end |
80 | 85 | |
81 | 86 | def closed? | ... | ... |
app/models/enterprise_homepage.rb
... | ... | @@ -12,18 +12,13 @@ class EnterpriseHomepage < Article |
12 | 12 | profile.nil? ? _('Homepage') : profile.name |
13 | 13 | end |
14 | 14 | |
15 | - # FIXME isn't this too much including just to be able to generate some HTML? | |
16 | - include ActionView::Helpers::TagHelper | |
17 | - include ActionView::Helpers::UrlHelper | |
18 | - include ActionController::UrlWriter | |
19 | - include ActionView::Helpers::AssetTagHelper | |
20 | - include EnterpriseHomepageHelper | |
21 | - include CatalogHelper | |
22 | - | |
23 | - def to_html(options ={}) | |
24 | - products = self.profile.products | |
25 | - display_profile_info(self.profile) + content_tag('div', self.body || '') + | |
26 | - (self.profile.environment.enabled?('disable_products_for_enterprises') ? '' : display_products_list(self.profile, products)) | |
15 | + def to_html(options = {}) | |
16 | + enterprise_homepage = self | |
17 | + lambda do | |
18 | + extend EnterpriseHomepageHelper | |
19 | + @products = profile.products.paginate(:order => 'id asc', :per_page => 9, :page => 1) | |
20 | + render :partial => 'content_viewer/enterprise_homepage', :object => enterprise_homepage | |
21 | + end | |
27 | 22 | end |
28 | 23 | |
29 | 24 | def can_display_hits? | ... | ... |
app/models/environment.rb
... | ... | @@ -120,7 +120,8 @@ class Environment < ActiveRecord::Base |
120 | 120 | 'enterprises_are_validated_when_created' => __('Enterprises are validated when created'), |
121 | 121 | 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), |
122 | 122 | 'xmpp_chat' => _('XMPP/Jabber based chat'), |
123 | - 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images') | |
123 | + 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'), | |
124 | + 'captcha_for_logged_users' => _('Ask captcha when a logged user comments too'), | |
124 | 125 | } |
125 | 126 | end |
126 | 127 | |
... | ... | @@ -174,6 +175,7 @@ class Environment < ActiveRecord::Base |
174 | 175 | acts_as_accessible |
175 | 176 | |
176 | 177 | has_many :units, :order => 'position' |
178 | + has_many :production_costs, :as => :owner | |
177 | 179 | |
178 | 180 | def superior_intances |
179 | 181 | [self, nil] |
... | ... | @@ -221,7 +223,6 @@ class Environment < ActiveRecord::Base |
221 | 223 | settings_items :layout_template, :type => String, :default => 'default' |
222 | 224 | settings_items :homepage, :type => String |
223 | 225 | settings_items :description, :type => String, :default => '<div style="text-align: center"><a href="http://noosfero.org/"><img src="/images/noosfero-network.png" alt="Noosfero"/></a></div>' |
224 | - settings_items :enable_ssl | |
225 | 226 | settings_items :local_docs, :type => Array, :default => [] |
226 | 227 | settings_items :news_amount_by_folder, :type => Integer, :default => 4 |
227 | 228 | settings_items :help_message_to_add_enterprise, :type => String, :default => '' |
... | ... | @@ -562,8 +563,8 @@ class Environment < ActiveRecord::Base |
562 | 563 | domain |
563 | 564 | end |
564 | 565 | |
565 | - def top_url(ssl = false) | |
566 | - protocol = (ssl ? 'https' : 'http') | |
566 | + def top_url | |
567 | + protocol = 'http' | |
567 | 568 | result = "#{protocol}://#{default_hostname}" |
568 | 569 | if Noosfero.url_options.has_key?(:port) |
569 | 570 | result << ':' << Noosfero.url_options[:port].to_s | ... | ... |
app/models/environment_finder.rb
... | ... | @@ -53,7 +53,7 @@ class EnvironmentFinder |
53 | 53 | # SECURITY no risk of SQL injection, since product_category_ids comes from trusted source |
54 | 54 | @environment.send(asset).find_by_contents(query, ferret_options, options.merge({:include => 'product_categorizations', :conditions => 'product_categorizations.category_id = (%s)' % product_category.id })) |
55 | 55 | elsif product_category && asset == :enterprises |
56 | - @environment.send(asset).find_by_contents(query, ferret_options, options.merge(:joins => 'inner join product_categorizations on (product_categorizations.product_id = products.id)', :include => 'products', :conditions => "product_categorizations.category_id = (#{product_category.id})")) | |
56 | + @environment.send(asset).find_by_contents(query, ferret_options, options.merge(:joins => 'inner join products on products.enterprise_id = profiles.id inner join product_categorizations on (product_categorizations.product_id = products.id)', :conditions => "product_categorizations.category_id = (#{product_category.id})")) | |
57 | 57 | else |
58 | 58 | @environment.send(asset).find_by_contents(query, ferret_options, options) |
59 | 59 | end | ... | ... |
app/models/environment_statistics_block.rb
... | ... | @@ -12,7 +12,7 @@ class EnvironmentStatisticsBlock < Block |
12 | 12 | _('This block presents some statistics about your environment.') |
13 | 13 | end |
14 | 14 | |
15 | - def content | |
15 | + def content(args={}) | |
16 | 16 | users = owner.people.visible.count |
17 | 17 | enterprises = owner.enterprises.visible.count |
18 | 18 | communities = owner.communities.visible.count | ... | ... |
app/models/event.rb
... | ... | @@ -22,7 +22,7 @@ class Event < Article |
22 | 22 | |
23 | 23 | validates_each :start_date do |event,field,value| |
24 | 24 | if event.end_date && event.start_date && event.start_date > event.end_date |
25 | - event.errors.add(:start_date, _('%{fn} cannot come before end date.')) | |
25 | + event.errors.add(:start_date, _('%{fn} cannot come before end date.').fix_i18n) | |
26 | 26 | end |
27 | 27 | end |
28 | 28 | ... | ... |
app/models/featured_products_block.rb
app/models/feed_reader_block.rb
... | ... | @@ -13,6 +13,7 @@ class FeedReaderBlock < Block |
13 | 13 | old_address = address |
14 | 14 | orig_set_address(new_address) |
15 | 15 | self.enabled = (new_address && new_address != old_address) || (new_address && self.enabled) || false |
16 | + self.fetched_at = nil | |
16 | 17 | end |
17 | 18 | |
18 | 19 | settings_items :limit, :type => :integer |
... | ... | @@ -71,12 +72,13 @@ class FeedReaderBlock < Block |
71 | 72 | self.feed_title = nil |
72 | 73 | self.error_message = nil |
73 | 74 | end |
75 | + | |
74 | 76 | def finish_fetch |
75 | 77 | self.fetched_at = Time.now |
76 | 78 | self.save! |
77 | 79 | end |
78 | 80 | |
79 | - def content | |
81 | + def content(args={}) | |
80 | 82 | block_title(title) + formatted_feed_content |
81 | 83 | end |
82 | 84 | ... | ... |
app/models/highlights_block.rb
app/models/image.rb
... | ... | @@ -9,15 +9,15 @@ class Image < ActiveRecord::Base |
9 | 9 | has_attachment :content_type => :image, |
10 | 10 | :storage => :file_system, |
11 | 11 | :path_prefix => 'public/image_uploads', |
12 | - :resize_to => '320x200>', | |
12 | + :resize_to => '800x600>', | |
13 | 13 | :thumbnails => { :big => '150x150', |
14 | 14 | :thumb => '100x100', |
15 | 15 | :portrait => '64x64', |
16 | 16 | :minor => '50x50', |
17 | 17 | :icon => '20x20!' }, |
18 | - :max_size => 500.kilobytes # remember to update validate message below | |
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 500.0 KB") | |
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/input.rb
... | ... | @@ -45,6 +45,18 @@ class Input < ActiveRecord::Base |
45 | 45 | %w[price_per_unit amount_used].each do |field| |
46 | 46 | return true unless self.send(field).blank? |
47 | 47 | end |
48 | - return false | |
48 | + false | |
49 | + end | |
50 | + | |
51 | + def has_all_price_details? | |
52 | + %w[price_per_unit unit amount_used].each do |field| | |
53 | + return false if self.send(field).blank? | |
54 | + end | |
55 | + true | |
56 | + end | |
57 | + | |
58 | + def cost | |
59 | + return 0 if self.amount_used.blank? || self.price_per_unit.blank? | |
60 | + self.amount_used * self.price_per_unit | |
49 | 61 | end |
50 | 62 | end | ... | ... |
app/models/link_list_block.rb
... | ... | @@ -47,7 +47,7 @@ class LinkListBlock < Block |
47 | 47 | _('This block can be used to create a menu of links. You can add, remove and update the links as you wish.') |
48 | 48 | end |
49 | 49 | |
50 | - def content | |
50 | + def content(args={}) | |
51 | 51 | block_title(title) + |
52 | 52 | content_tag('ul', |
53 | 53 | links.select{|i| !i[:name].blank? and !i[:address].blank?}.map{|i| content_tag('li', link_html(i))} | ... | ... |
app/models/location_block.rb
app/models/login_block.rb
app/models/main_block.rb
app/models/my_network_block.rb
app/models/organization.rb
app/models/person.rb
... | ... | @@ -116,10 +116,17 @@ class Person < Profile |
116 | 116 | contact_phone |
117 | 117 | contact_information |
118 | 118 | description |
119 | + image | |
119 | 120 | ] |
120 | 121 | |
121 | 122 | validates_multiparameter_assignments |
122 | 123 | |
124 | + validates_each :birth_date do |record,attr,value| | |
125 | + if value && value.year == 1 | |
126 | + record.errors.add(attr) | |
127 | + end | |
128 | + end | |
129 | + | |
123 | 130 | def self.fields |
124 | 131 | FIELDS |
125 | 132 | end |
... | ... | @@ -129,7 +136,7 @@ class Person < Profile |
129 | 136 | self.required_fields.each do |field| |
130 | 137 | if self.send(field).blank? |
131 | 138 | unless (field == 'custom_area_of_study' && self.area_of_study != 'Others') || (field == 'custom_formation' && self.formation != 'Others') |
132 | - self.errors.add(field, _('%{fn} is mandatory')) | |
139 | + self.errors.add_on_blank(field) | |
133 | 140 | end |
134 | 141 | end |
135 | 142 | end |
... | ... | @@ -191,7 +198,7 @@ class Person < Profile |
191 | 198 | |
192 | 199 | validates_each :email, :on => :update do |record,attr,value| |
193 | 200 | if User.find(:first, :conditions => ['email = ? and id != ? and environment_id = ?', value, record.user.id, record.environment.id]) |
194 | - record.errors.add(attr, _('%{fn} is already used by other user')) | |
201 | + record.errors.add(attr, _('%{fn} is already used by other user').fix_i18n) | |
195 | 202 | end |
196 | 203 | end |
197 | 204 | |
... | ... | @@ -403,7 +410,15 @@ class Person < Profile |
403 | 410 | end |
404 | 411 | |
405 | 412 | def control_panel_settings_button |
406 | - {:title => _('Profile Info and settings'), :icon => 'edit-profile'} | |
413 | + {:title => _('Edit Profile'), :icon => 'edit-profile'} | |
414 | + end | |
415 | + | |
416 | + def disable | |
417 | + self.visible = false | |
418 | + user.password = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{identifier}--") | |
419 | + user.password_confirmation = user.password | |
420 | + save! | |
421 | + user.save! | |
407 | 422 | end |
408 | 423 | |
409 | 424 | protected | ... | ... |
... | ... | @@ -0,0 +1,27 @@ |
1 | +class PriceDetail < ActiveRecord::Base | |
2 | + | |
3 | + belongs_to :product | |
4 | + validates_presence_of :product_id | |
5 | + | |
6 | + belongs_to :production_cost | |
7 | + validates_presence_of :production_cost_id | |
8 | + validates_uniqueness_of :production_cost_id, :scope => :product_id | |
9 | + | |
10 | + def price | |
11 | + self[:price] || 0 | |
12 | + end | |
13 | + | |
14 | + include FloatHelper | |
15 | + def price=(value) | |
16 | + if value.is_a?(String) | |
17 | + super(decimal_to_float(value)) | |
18 | + else | |
19 | + super(value) | |
20 | + end | |
21 | + end | |
22 | + | |
23 | + def formatted_value(value) | |
24 | + ("%.2f" % self[value]).to_s.gsub('.', product.enterprise.environment.currency_separator) if self[value] | |
25 | + end | |
26 | + | |
27 | +end | ... | ... |
app/models/product.rb
... | ... | @@ -5,6 +5,8 @@ class Product < ActiveRecord::Base |
5 | 5 | has_many :product_qualifiers |
6 | 6 | has_many :qualifiers, :through => :product_qualifiers |
7 | 7 | has_many :inputs, :dependent => :destroy, :order => 'position' |
8 | + has_many :price_details, :dependent => :destroy | |
9 | + has_many :production_costs, :through => :price_details | |
8 | 10 | |
9 | 11 | validates_uniqueness_of :name, :scope => :enterprise_id, :allow_nil => true |
10 | 12 | validates_presence_of :product_category_id |
... | ... | @@ -101,12 +103,13 @@ class Product < ActiveRecord::Base |
101 | 103 | enterprise.public_profile |
102 | 104 | end |
103 | 105 | |
104 | - def formatted_value(value) | |
105 | - ("%.2f" % self[value]).to_s.gsub('.', enterprise.environment.currency_separator) if self[value] | |
106 | + def formatted_value(method) | |
107 | + value = self[method] || self.send(method) | |
108 | + ("%.2f" % value).to_s.gsub('.', enterprise.environment.currency_separator) if value | |
106 | 109 | end |
107 | 110 | |
108 | 111 | def price_with_discount |
109 | - price - discount if discount | |
112 | + discount ? (price - discount) : price | |
110 | 113 | end |
111 | 114 | |
112 | 115 | def price=(value) |
... | ... | @@ -125,6 +128,23 @@ class Product < ActiveRecord::Base |
125 | 128 | end |
126 | 129 | end |
127 | 130 | |
131 | + # Note: will probably be completely overhauled for AI1413 | |
132 | + def inputs_prices? | |
133 | + return false if self.inputs.count <= 0 | |
134 | + self.inputs.each do |input| | |
135 | + return false if input.has_price_details? == false | |
136 | + end | |
137 | + true | |
138 | + end | |
139 | + | |
140 | + def any_inputs_details? | |
141 | + return false if self.inputs.count <= 0 | |
142 | + self.inputs.each do |input| | |
143 | + return true if input.has_all_price_details? == true | |
144 | + end | |
145 | + false | |
146 | + end | |
147 | + | |
128 | 148 | def has_basic_info? |
129 | 149 | %w[unit price discount].each do |field| |
130 | 150 | return true if !self.send(field).blank? |
... | ... | @@ -153,4 +173,44 @@ class Product < ActiveRecord::Base |
153 | 173 | true |
154 | 174 | end |
155 | 175 | |
176 | + def inputs_cost | |
177 | + return 0 if inputs.empty? | |
178 | + inputs.map(&:cost).inject { |sum,price| sum + price } | |
179 | + end | |
180 | + | |
181 | + def total_production_cost | |
182 | + return inputs_cost if price_details.empty? | |
183 | + inputs_cost + price_details.map(&:price).inject { |sum,price| sum + price } | |
184 | + end | |
185 | + | |
186 | + def price_described? | |
187 | + return false if price.blank? or price == 0 | |
188 | + (price - total_production_cost).zero? | |
189 | + end | |
190 | + | |
191 | + def update_price_details(price_details) | |
192 | + self.price_details.destroy_all | |
193 | + price_details.each do |price_detail| | |
194 | + self.price_details.create(price_detail) | |
195 | + end | |
196 | + end | |
197 | + | |
198 | + def price_description_percentage | |
199 | + return 0 if price.blank? || price.zero? | |
200 | + total_production_cost * 100 / price | |
201 | + end | |
202 | + | |
203 | + def available_production_costs | |
204 | + self.enterprise.environment.production_costs + self.enterprise.production_costs | |
205 | + end | |
206 | + | |
207 | + include ActionController::UrlWriter | |
208 | + def price_composition_bar_display_url | |
209 | + url_for({:host => enterprise.default_hostname, :controller => 'manage_products', :action => 'display_price_composition_bar', :profile => enterprise.identifier, :id => self.id }.merge(Noosfero.url_options)) | |
210 | + end | |
211 | + | |
212 | + def inputs_cost_update_url | |
213 | + url_for({:host => enterprise.default_hostname, :controller => 'manage_products', :action => 'display_inputs_cost', :profile => enterprise.identifier, :id => self.id }.merge(Noosfero.url_options)) | |
214 | + end | |
215 | + | |
156 | 216 | end | ... | ... |
... | ... | @@ -0,0 +1,8 @@ |
1 | +class ProductionCost < ActiveRecord::Base | |
2 | + | |
3 | + belongs_to :owner, :polymorphic => true | |
4 | + validates_presence_of :owner | |
5 | + validates_presence_of :name | |
6 | + validates_length_of :name, :maximum => 30, :allow_blank => true | |
7 | + validates_uniqueness_of :name, :scope => [:owner_id, :owner_type] | |
8 | +end | ... | ... |
app/models/products_block.rb
app/models/profile.rb
... | ... | @@ -20,12 +20,16 @@ class Profile < ActiveRecord::Base |
20 | 20 | find_role('editor', env_id) |
21 | 21 | end |
22 | 22 | def self.organization_member_roles(env_id) |
23 | - [admin(env_id), moderator(env_id), member(env_id)] | |
23 | + all_roles(env_id).select{ |r| r.key.match(/^profile_/) unless r.key.blank? } | |
24 | 24 | end |
25 | 25 | def self.all_roles(env_id) |
26 | - [admin(env_id), member(env_id), moderator(env_id), owner(env_id), editor(env_id)] | |
26 | + Role.all :conditions => { :environment_id => env_id } | |
27 | + end | |
28 | + def self.method_missing(m, *args, &block) | |
29 | + role = find_role(m, args[0]) | |
30 | + return role unless role.nil? | |
31 | + super | |
27 | 32 | end |
28 | - | |
29 | 33 | private |
30 | 34 | def self.find_role(name, env_id) |
31 | 35 | ::Role.find_by_key_and_environment_id("profile_#{name}", env_id) |
... | ... | @@ -115,6 +119,7 @@ class Profile < ActiveRecord::Base |
115 | 119 | |
116 | 120 | acts_as_having_settings :field => :data |
117 | 121 | |
122 | + settings_items :redirect_l10n, :type => :boolean, :default => false | |
118 | 123 | settings_items :public_content, :type => :boolean, :default => true |
119 | 124 | settings_items :description |
120 | 125 | |
... | ... | @@ -147,6 +152,7 @@ class Profile < ActiveRecord::Base |
147 | 152 | doc |
148 | 153 | chat |
149 | 154 | plugin |
155 | + site | |
150 | 156 | ] |
151 | 157 | |
152 | 158 | belongs_to :user |
... | ... | @@ -609,7 +615,7 @@ private :generate_url, :url_options |
609 | 615 | include ActionView::Helpers::TextHelper |
610 | 616 | def short_name(chars = 40) |
611 | 617 | if self[:nickname].blank? |
612 | - truncate self.name, chars, '...' | |
618 | + truncate self.name, :length => chars, :omission => '...' | |
613 | 619 | else |
614 | 620 | self[:nickname] |
615 | 621 | end |
... | ... | @@ -806,15 +812,10 @@ private :generate_url, :url_options |
806 | 812 | end |
807 | 813 | |
808 | 814 | def disable |
809 | - self.visible = false | |
810 | - user.password = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{identifier}--") | |
811 | - user.password_confirmation = user.password | |
812 | - save! | |
813 | - user.save! | |
814 | 815 | end |
815 | 816 | |
816 | 817 | def control_panel_settings_button |
817 | - {:title => _('Profile Info and settings'), :icon => 'edit-profile'} | |
818 | + {:title => _('Edit Profile'), :icon => 'edit-profile'} | |
818 | 819 | end |
819 | 820 | |
820 | 821 | def self.identification | ... | ... |
app/models/profile_image_block.rb
app/models/profile_info_block.rb
... | ... | @@ -8,7 +8,7 @@ class ProfileInfoBlock < Block |
8 | 8 | _('Basic information about <i>%{user}</i>: how long <i>%{user}</i> is part of <i>%{env}</i> and useful links.') % { :user => self.owner.name(), :env => self.owner.environment.name() } |
9 | 9 | end |
10 | 10 | |
11 | - def content | |
11 | + def content(args={}) | |
12 | 12 | block = self |
13 | 13 | lambda do |
14 | 14 | render :file => 'blocks/profile_info', :locals => { :block => block } | ... | ... |
app/models/profile_list_block.rb
app/models/profile_search_block.rb
app/models/raw_html_block.rb
app/models/recent_documents_block.rb
... | ... | @@ -15,7 +15,7 @@ class RecentDocumentsBlock < Block |
15 | 15 | settings_items :limit, :type => :integer, :default => 5 |
16 | 16 | |
17 | 17 | include ActionController::UrlWriter |
18 | - def content | |
18 | + def content(args={}) | |
19 | 19 | docs = self.limit.nil? ? owner.recent_documents : owner.recent_documents(self.limit) |
20 | 20 | |
21 | 21 | block_title(title) + | ... | ... |
app/models/sellers_search_block.rb
... | ... | @@ -16,7 +16,7 @@ class SellersSearchBlock < Block |
16 | 16 | _('This block presents a search engine for products.') |
17 | 17 | end |
18 | 18 | |
19 | - def content | |
19 | + def content(args={}) | |
20 | 20 | title = self.title |
21 | 21 | lambda do |
22 | 22 | render :file => 'search/_sellers_form', :locals => { :title => title } | ... | ... |
app/models/slideshow_block.rb
app/models/tags_block.rb
app/models/theme.rb
... | ... | @@ -43,8 +43,11 @@ class Theme |
43 | 43 | |
44 | 44 | def approved_themes(owner) |
45 | 45 | Dir.glob(File.join(system_themes_dir, '*')).select do |item| |
46 | - config = YAML.load_file(File.join(item, 'theme.yml')) | |
47 | - (config['owner_type'] == owner.class.base_class.name) && (config['owner_id'] == owner.id) || config['public'] | |
46 | + if File.exists?( File.join(item, 'theme.yml') ) | |
47 | + config = YAML.load_file(File.join(item, 'theme.yml')) | |
48 | + (config['owner_type'] == owner.class.base_class.name) && | |
49 | + (config['owner_id'] == owner.id) || config['public'] | |
50 | + end | |
48 | 51 | end.map do |desc| |
49 | 52 | new(File.basename(desc)) |
50 | 53 | end | ... | ... |
app/models/uploaded_file.rb
... | ... | @@ -50,7 +50,7 @@ class UploadedFile < Article |
50 | 50 | :thumbnail_class => Thumbnail, |
51 | 51 | :max_size => 5.megabytes # remember to update validate message below |
52 | 52 | |
53 | - validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB") | |
53 | + validates_attachment :size => N_("%{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n | |
54 | 54 | |
55 | 55 | delay_attachment_fu_thumbnails |
56 | 56 | ... | ... |
app/models/user.rb
... | ... | @@ -100,7 +100,7 @@ class User < ActiveRecord::Base |
100 | 100 | before_save :encrypt_password |
101 | 101 | validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|user| !user.email.blank?}) |
102 | 102 | |
103 | - 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.') | |
103 | + 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 | |
104 | 104 | |
105 | 105 | # Authenticates a user by their login name and unencrypted password. Returns the user or nil. |
106 | 106 | def self.authenticate(login, password, environment = nil) | ... | ... |
app/sweepers/article_sweeper.rb
... | ... | @@ -13,15 +13,11 @@ class ArticleSweeper < ActiveRecord::Observer |
13 | 13 | protected |
14 | 14 | |
15 | 15 | def expire_caches(article) |
16 | - article.hierarchy.each do |a| | |
17 | - if a != article | |
18 | - a.touch | |
19 | - end | |
20 | - end | |
16 | + article.hierarchy.each { |a| a.touch if a != article } | |
21 | 17 | blocks = article.profile.blocks |
22 | 18 | blocks += article.profile.environment.blocks if article.profile.environment |
23 | 19 | blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}} |
24 | - blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)} | |
20 | + BlockSweeper.expire_blocks(blocks) | |
25 | 21 | env = article.profile.environment |
26 | 22 | if env && (env.portal_community == article.profile) |
27 | 23 | expire_fragment(env.portal_news_cache_key) | ... | ... |
... | ... | @@ -0,0 +1,28 @@ |
1 | +class BlockSweeper < ActiveRecord::Observer | |
2 | + | |
3 | + observe :block | |
4 | + | |
5 | + class << self | |
6 | + include SweeperHelper | |
7 | + | |
8 | + def cache_key_regex(block) | |
9 | + regex = '-[a-z]*$' | |
10 | + clean_ck = block.cache_key.gsub(/#{regex}/,'') | |
11 | + %r{#{clean_ck+regex}} | |
12 | + end | |
13 | + | |
14 | + # Expire block's all languages cache | |
15 | + def expire_block(block) | |
16 | + expire_timeout_fragment(cache_key_regex(block)) | |
17 | + end | |
18 | + | |
19 | + def expire_blocks(blocks) | |
20 | + blocks.each { |block| expire_block(block) } | |
21 | + end | |
22 | + end | |
23 | + | |
24 | + def after_save(block) | |
25 | + self.class.expire_block(block) | |
26 | + end | |
27 | + | |
28 | +end | ... | ... |
app/sweepers/friendship_sweeper.rb
app/sweepers/profile_sweeper.rb
... | ... | @@ -31,7 +31,7 @@ protected |
31 | 31 | |
32 | 32 | def expire_statistics_block_cache(profile) |
33 | 33 | blocks = profile.environment.blocks.select { |b| b.kind_of?(EnvironmentStatisticsBlock) } |
34 | - blocks.map(&:cache_key).each{|ck|expire_timeout_fragment(ck)} | |
34 | + BlockSweeper.expire_blocks(blocks) | |
35 | 35 | end |
36 | 36 | |
37 | 37 | def expire_blogs(profile) | ... | ... |
app/sweepers/role_assignment_sweeper.rb
... | ... | @@ -0,0 +1,7 @@ |
1 | +<div class='status-identifier'> | |
2 | + <p><span class='<%= @status_class %>'><%= @status %></span></p> | |
3 | + <script type="text/javascript"> | |
4 | + jQuery('#user_email').removeClass('<%= validation_classes %>'); | |
5 | + jQuery('#user_email').addClass('<%= @status_class %>'); | |
6 | + </script> | |
7 | +</div> | ... | ... |
app/views/account/_identifier_status.rhtml
1 | 1 | <div class='status-identifier'> |
2 | - <p><%= @url %> <span class='<%= @status_class %>'><%= @status %></span> </p> | |
2 | + <p><span class='<%= @status_class %>'><%= @status %></span></p> | |
3 | + <script type="text/javascript"> | |
4 | + jQuery('#user_login').removeClass('<%= validation_classes %>'); | |
5 | + jQuery('#user_login').addClass('<%= @status_class %>'); | |
6 | + </script> | |
3 | 7 | </div> | ... | ... |
app/views/account/_signup_form.rhtml
1 | 1 | <%= error_messages_for :user, :person %> |
2 | 2 | |
3 | -<% if ! defined? hidden_atention || ! hidden_atention %> | |
4 | -<p/> | |
5 | -<div class="atention"> | |
6 | -<%= _('Dear user, welcome to the %s network. To start your participation in this space, fill in the fields below. After this operation, your login and password will be registered, allowing you to create %s and %s in this environment.') % [environment.name, __('communities'), __('enterprises')] %> | |
7 | -</div> | |
8 | -<% end %> | |
9 | - | |
10 | -<% labelled_form_for :user, @user, :html => { :multipart => true } do |f| %> | |
3 | +<% labelled_form_for :user, @user, :html => { :multipart => true, :id => 'signup-form' } do |f| %> | |
11 | 4 | |
12 | 5 | <%= hidden_field_tag :invitation_code, @invitation_code %> |
13 | 6 | |
14 | -<%= required_fields_message %> | |
7 | +<div id='signup-form-header'> | |
15 | 8 | |
16 | -<div id='signup-email'> | |
17 | - <%= required f.text_field(:email) %> | |
18 | - <%= content_tag(:small,_('This e-mail address will be used to contact you.')) %> | |
19 | -</div> | |
9 | + <span id="signup-domain"><%= environment.default_hostname %>/</span> | |
10 | + <div id='signup-login'> | |
11 | + <div id='signup-login-field'> | |
12 | + <%= required f.text_field(:login, :onchange => 'this.value = convToValidLogin(this.value);', :rel => s_('signup|Login')) %> | |
13 | + <div id='url-check'><p> </p></div> | |
14 | + </div> | |
15 | + <%= content_tag(:small, _('Choose your login name carefully! It will be your network access and you will not be able to change it later.'), :id => 'signup-balloon') %> | |
16 | + <br style="clear: both;" /> | |
17 | + </div> | |
18 | + <%= observe_field 'user_login', | |
19 | + :url => { :action => 'check_url' }, | |
20 | + :with => 'identifier', | |
21 | + :update => 'url-check', | |
22 | + :loading => "jQuery('#user_login').removeClass('#{validation_classes}').addClass('checking'); | |
23 | + jQuery('#url-check').html('<p><span class=\"checking\">#{checking_message(:url)}</span></p>');", | |
24 | + :complete => "jQuery('#user_login').removeClass('checking')" | |
25 | + %> | |
20 | 26 | |
21 | -<%= required f.text_field(:login, :onchange => 'this.value = convToValidLogin( this.value )') %> | |
22 | -<%= content_tag(:small,_('Insert your login')) %> | |
23 | -<div id='url-check'></div> | |
27 | + <div id='signup-password'> | |
28 | + <%= required f.password_field(:password, :id => 'user_pw') %> | |
29 | + <%= f.text_field(:password_clear, :value => _('password')) %> | |
30 | + <%= content_tag(:small,_('Choose a password that you can remember easily. It must have at least 4 characters.'), :id => 'password-balloon') %> | |
31 | + <div id='fake-check'><p> </p></div> | |
32 | + </div> | |
33 | + | |
34 | + <div id='signup-password-confirmation'> | |
35 | + <%= required f.password_field(:password_confirmation) %> | |
36 | + <%= f.text_field(:password_confirmation_clear, :value => _('password confirmation')) %> | |
37 | + <div id='password-check'><p> </p></div> | |
38 | + </div> | |
39 | + | |
40 | + <div id='signup-email'> | |
41 | + <%= required f.text_field(:email, :rel => _('e-Mail')) %> | |
42 | + <%= content_tag(:small,_('This e-mail address will be used to contact you.')) %> | |
43 | + <div id='email-check'><p> </p></div> | |
44 | + </div> | |
45 | + <%= observe_field "user_email", | |
46 | + :url => { :action => "check_email" }, | |
47 | + :with => "address", | |
48 | + :update => "email-check", | |
49 | + :loading => "jQuery('#user_email').removeClass('#{validation_classes}').addClass('checking'); | |
50 | + jQuery('#email-check').html('<p><span class=\"checking\">#{checking_message(:email)}</span></p>');", | |
51 | + :complete => "jQuery('#user_email').removeClass('checking')", | |
52 | + :before => "if (!( jQuery('#user_email').valid() )) { | |
53 | + jQuery('#user_email').removeClass('#{validation_classes}').addClass('unavailable'); | |
54 | + jQuery('#email-check').html('<p><span class=\"unavailable\">#{_('This e-mail address is not valid')}</span></p>'); | |
55 | + return false; | |
56 | + }" | |
57 | + %> | |
24 | 58 | |
25 | -<%= observe_field 'user_login', :url => {:action => 'check_url'}, :with => 'identifier', :update => 'url-check' %> | |
59 | + <%= label :profile_data, :name %> | |
60 | + <%= required text_field(:profile_data, :name, :rel => _('Full name')) %> | |
26 | 61 | |
27 | -<div id='signup-password'> | |
28 | - <%= required f.password_field(:password) %> | |
29 | - <%= content_tag(:small,_('Choose a password that you can remember easily. It must have at least 4 characters.')) %> | |
30 | 62 | </div> |
31 | 63 | |
32 | -<%= required f.password_field(:password_confirmation) %> | |
33 | -<%= content_tag(:small,_('To confirm, repeat your password.')) %> | |
34 | - | |
35 | -<% labelled_fields_for :profile_data, @person do |f| %> | |
36 | - <%= render :partial => 'profile_editor/person_form', :locals => {:f => f} %> | |
37 | -<% end %> | |
38 | - | |
39 | -<% unless @terms_of_use.blank? %> | |
40 | - <div id='terms-of-use-box' class='formfieldline'> | |
41 | - <%= _("By clicking on 'I accept the terms of use' below you are agreeing to the %s") % | |
42 | - link_to_function(_('Terms of use'), nil) do |page| | |
43 | - page['terms-of-use'].show | |
44 | - end %> | |
45 | - | |
46 | - <div id='terms-of-use' style='display: none;'> | |
47 | - <%= @terms_of_use %> | |
48 | - <%= link_to_function(_('Hide'), nil) do |page| | |
49 | - page['terms-of-use'].hide | |
50 | - end %> | |
64 | +<div id="signup-form-profile"> | |
65 | + | |
66 | + <% labelled_fields_for :profile_data, @person do |f| %> | |
67 | + <%= render :partial => 'profile_editor/person_form', :locals => {:f => f} %> | |
68 | + <% end %> | |
69 | + | |
70 | + <% unless @terms_of_use.blank? %> | |
71 | + <div id='terms-of-use-box' class='formfieldline'> | |
72 | + <%= labelled_check_box(_('I accept the %s') % link_to(_('terms of use'), {:controller => 'home', :action => 'terms'}, :target => '_blank'), 'user[terms_accepted]') %> | |
51 | 73 | </div> |
52 | - <p><%= labelled_check_box(environment.terms_of_use_acceptance_text.blank? ? _('I accept the terms of use') : environment.terms_of_use_acceptance_text, 'user[terms_accepted]') %></p> | |
53 | - </div> | |
54 | -<% end %> | |
55 | - | |
56 | -<% if params[:enterprise_code] %> | |
57 | - <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %> | |
58 | - <%= hidden_field_tag :answer, params[:answer] %> | |
59 | - <%= hidden_field_tag :terms_accepted, params[:terms_accepted] %> | |
60 | - <%= hidden_field_tag :new_user, true %> | |
61 | -<% end %> | |
62 | - | |
63 | -<% button_bar do %> | |
64 | - <%= submit_button('save', _('Sign up'), :cancel => {:action => 'index'}, :class => 'icon-menu-login') %> | |
65 | -<% end %> | |
74 | + <% end %> | |
75 | + | |
76 | + <% if params[:enterprise_code] %> | |
77 | + <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %> | |
78 | + <%= hidden_field_tag :answer, params[:answer] %> | |
79 | + <%= hidden_field_tag :terms_accepted, params[:terms_accepted] %> | |
80 | + <%= hidden_field_tag :new_user, true %> | |
81 | + <% end %> | |
82 | +</div> | |
83 | + | |
84 | +<p style="text-align: center"> | |
85 | + <%= submit_button('save', _('Create my account')) %> | |
86 | +</p> | |
87 | + | |
66 | 88 | <% end -%> |
89 | + | |
90 | +<script type="text/javascript"> | |
91 | +jQuery(function($) { | |
92 | + $('#signup-form input[type=text], #signup-form textarea').each(function() { | |
93 | + if ($(this).attr('rel')) var default_value = $(this).attr('rel').toLowerCase(); | |
94 | + if ($(this).val() == '') $(this).val(default_value); | |
95 | + $(this).bind('focus', function() { | |
96 | + if ($(this).val() == default_value) $(this).val(''); | |
97 | + }); | |
98 | + $(this).bind('blur', function() { | |
99 | + if ($(this).val() == '') { | |
100 | + $(this).val(default_value); | |
101 | + $(this).removeClass('filled-in'); | |
102 | + } | |
103 | + else $(this).addClass('filled-in'); | |
104 | + }); | |
105 | + }); | |
106 | + | |
107 | + $('#signup-form').bind('submit', function() { | |
108 | + $('#signup-form input[type=text], #signup-form textarea').each(function() { | |
109 | + if ($(this).attr('rel')) var default_value = $(this).attr('rel').toLowerCase(); | |
110 | + if ($(this).val() == default_value) $(this).val(''); | |
111 | + }); | |
112 | + return true; | |
113 | + }); | |
114 | + | |
115 | + $('#user_password_clear, #user_password_confirmation_clear').show(); | |
116 | + $('#user_password_clear, #user_password_confirmation_clear').unbind(); | |
117 | + $('#user_pw, #user_password_confirmation').hide(); | |
118 | + $('#user_password_clear').focus(function() { | |
119 | + $(this).hide(); | |
120 | + $('#user_pw').show(); | |
121 | + $('#user_pw').focus(); | |
122 | + }); | |
123 | + $('#user_pw').focus(function() { | |
124 | + $('#password-balloon').fadeIn('slow'); | |
125 | + }); | |
126 | + $('#user_pw').blur(function() { | |
127 | + if ($(this).val() == '') { | |
128 | + $('#user_password_clear').show(); | |
129 | + $(this).hide(); | |
130 | + } | |
131 | + }); | |
132 | + $('#user_password_confirmation_clear').focus(function() { | |
133 | + $(this).hide(); | |
134 | + $('#user_password_confirmation').show(); | |
135 | + $('#user_password_confirmation').focus(); | |
136 | + }); | |
137 | + $('#user_password_confirmation, #user_pw').blur(function() { | |
138 | + if ($('#user_password_confirmation').val() == '') { | |
139 | + $('#user_password_confirmation_clear').show(); | |
140 | + $('#user_password_confirmation').hide(); | |
141 | + } else if ($('#user_password_confirmation').val() == $('#user_pw').val()) { | |
142 | + $('#user_password_confirmation').addClass('passwords_match').removeClass('passwords_differ'); | |
143 | + $('#user_pw').removeClass('invalid_input').addClass('valid_input'); | |
144 | + $('#password-check').html("<p> </p>"); | |
145 | + } else if ($('#user_password_confirmation').val() != $('#user_pw').val()) { | |
146 | + $('#user_password_confirmation').removeClass('passwords_match').addClass('passwords_differ'); | |
147 | + $('#user_pw').addClass('invalid_input').removeClass('valid_input'); | |
148 | + $('#password-check').html("<p><span class='unavailable'><%= _('Passwords don\'t match') %></span></p>"); | |
149 | + } | |
150 | + $('#password-balloon').fadeOut('slow'); | |
151 | + }); | |
152 | + $('#user_login').focus(function() { | |
153 | + $('#signup-balloon').fadeIn('slow'); | |
154 | + }); | |
155 | + $('#user_login').blur(function() { $('#signup-balloon').fadeOut('slow'); }); | |
156 | + $('#signup-form').validate({ rules: { 'user[email]': { email: true } }, messages: { 'user[email]' : '' } }); | |
157 | +}); | |
158 | +</script> | ... | ... |