Commit 303c546aba26aa5ee3776940128a734323a7a3f0

Authored by Joenio Costa
2 parents 576c5dbe 3ef8b49b

Merge branch 'master' into AI3042-custom_signup_welcome

Showing 2993 changed files with 196296 additions and 46508 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 2993 files displayed.

AUTHORS
... ... @@ -7,6 +7,7 @@ Developers
7 7 ==========
8 8  
9 9 Alan Freihof Tygel <alantygel@gmail.com>
  10 +alcampelo <alcampelo@alcampelo.(none)>
10 11 Alessandro Palmeira <alessandro.palmeira@gmail.com>
11 12 Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>
12 13 Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>
... ... @@ -38,6 +39,7 @@ Alessandro Palmeira + João M. M. Silva &lt;alessandro.palmeira@gmail.com&gt;
38 39 Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
39 40 Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
40 41 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
  42 +Ana Losnak <analosnak@gmail.com>
41 43 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
42 44 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
43 45 Antonio Terceiro <terceiro@colivre.coop.br>
... ... @@ -85,6 +87,7 @@ Daniel Alves + Rafael Manzo &lt;rr.manzo@gmail.com&gt;
85 87 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
86 88 Daniel Bucher <daniel.bucher88@gmail.com>
87 89 Daniel Cunha <daniel@colivre.coop.br>
  90 +David Carlos <ddavidcarlos1392@gmail.com>
88 91 diegoamc <diegoamc90@gmail.com>
89 92 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
90 93 Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>
... ... @@ -114,12 +117,16 @@ Diego Martinez &lt;diegoamc90@gmail.com&gt;
114 117 Diego Martinez <diego@diego-K55A.(none)>
115 118 Diego + Renan <renanteruoc@gmail.com>
116 119 Eduardo Tourinho Edington <eduardo.edington@serpro.gov.br>
  120 +Fabio Teixeira <fabio1079@gmail.com>
117 121 Fernanda Lopes <nanda.listas+psl@gmail.com>
118 122 Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>
119 123 Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)>
120 124 Francisco Marcelo de Araújo Lima Júnior <francisco.lima-junior@serpro.gov.br>
121 125 Francisco Marcelo de Araújo Lima Júnior <maljunior@gmail.com>
  126 +Gabriela Navarro <navarro1703@gmail.com>
122 127 Grazieno Pellegrino <grazieno@gmail.com>
  128 +Gust <darksshades@hotmail.com>
  129 +Hugo Melo <hugo@riseup.net>
123 130 Isaac Canan <isaac@intelletto.com.br>
124 131 Italo Valcy <italo@dcc.ufba.br>
125 132 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
... ... @@ -155,6 +162,7 @@ João M. M. Silva + Rafael Manzo &lt;jaodsilv@linux.ime.usp.br&gt;
155 162 João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
156 163 Joenio Costa <joenio@colivre.coop.br>
157 164 Josef Spillner <josef.spillner@tu-dresden.de>
  165 +Junior Silva <junior@bajor.localhost.localdomain>
158 166 Junior Silva <juniorsilva1001@gmail.com>
159 167 Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>
160 168 Junior Silva <juniorsilva@colivre.coop.br>
... ... @@ -202,6 +210,7 @@ Renan Teruo + Diego Araujo &lt;renanteruoc@gmail.com&gt;
202 210 Renan Teruo + Diego Araújo <renanteruoc@gmail.com>
203 211 Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
204 212 Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
  213 +Rodrigo Souto + Ana Losnak + Daniel Bucher + Caio Almeida + Leandro Nunes + Daniela Feitosa + Mariel Zasso <noosfero-br@listas.softwarelivre.org>
205 214 Rodrigo Souto <diguliu@gmail.com>
206 215 Rodrigo Souto <rodrigo@colivre.coop.br>
207 216 Ronny Kursawe <kursawe.ronny@googlemail.com>
... ...
Gemfile
1 1 source "https://rubygems.org"
  2 +gem 'rails'
  3 +gem 'fast_gettext'
  4 +gem 'acts-as-taggable-on'
  5 +gem 'prototype-rails'
  6 +gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
  7 +gem 'rails_autolink'
  8 +gem 'pg'
  9 +gem 'rmagick'
  10 +gem 'RedCloth'
  11 +gem 'will_paginate'
  12 +gem 'ruby-feedparser'
  13 +gem 'daemons'
  14 +gem 'thin'
  15 +gem 'hpricot'
  16 +gem 'nokogiri'
  17 +gem 'rake', :require => false
2 18  
3   -gem 'exception_notification', '1.0.20090728'
4   -gem 'system_timer'
  19 +# FIXME list here all actual dependencies (i.e. the ones in debian/control),
  20 +# with their GEM names (not the Debian package names)
  21 +
  22 +group :production do
  23 + gem 'dalli'
  24 +end
5 25  
6 26 group :test do
7   - gem 'rspec', '1.2.9'
8   - gem 'rspec-rails', '1.2.9'
  27 + gem 'rspec'
  28 + gem 'rspec-rails'
9 29 end
10 30  
11 31 group :cucumber do
12   - gem 'rake', '0.8.7'
13   - gem 'cucumber-rails', '0.3.2'
14   - gem 'capybara', '1.1.1'
15   - gem 'cucumber', '1.1.0'
  32 + gem 'rake'
  33 + gem 'cucumber-rails', :require => false
  34 + gem 'capybara'
  35 + gem 'cucumber'
16 36 gem 'database_cleaner'
  37 + gem 'selenium-webdriver'
17 38 end
18 39  
19   -def program(name)
20   - unless system("which #{name} > /dev/null")
21   - puts "W: Program #{name} is needed, but was not found in your PATH"
22   - end
  40 +# include plugin gemfiles
  41 +Dir.glob(File.join('config', 'plugins', '*')).each do |plugin|
  42 + plugin_gemfile = File.join(plugin, 'Gemfile')
  43 + eval File.read(plugin_gemfile) if File.exists?(plugin_gemfile)
23 44 end
24   -
25   -program 'java'
26   -program 'firefox'
... ...
Gemfile.lock
  1 +PATH
  2 + remote: vendor/prototype_legacy_helper
  3 + specs:
  4 + prototype_legacy_helper (0.0.0)
  5 +
1 6 GEM
2 7 remote: https://rubygems.org/
3 8 specs:
4   - builder (3.1.4)
5   - capybara (1.1.1)
  9 + RedCloth (4.2.9)
  10 + actionmailer (3.2.6)
  11 + actionpack (= 3.2.6)
  12 + mail (~> 2.4.4)
  13 + actionpack (3.2.6)
  14 + activemodel (= 3.2.6)
  15 + activesupport (= 3.2.6)
  16 + builder (~> 3.0.0)
  17 + erubis (~> 2.7.0)
  18 + journey (~> 1.0.1)
  19 + rack (~> 1.4.0)
  20 + rack-cache (~> 1.2)
  21 + rack-test (~> 0.6.1)
  22 + sprockets (~> 2.1.3)
  23 + activemodel (3.2.6)
  24 + activesupport (= 3.2.6)
  25 + builder (~> 3.0.0)
  26 + activerecord (3.2.6)
  27 + activemodel (= 3.2.6)
  28 + activesupport (= 3.2.6)
  29 + arel (~> 3.0.2)
  30 + tzinfo (~> 0.3.29)
  31 + activeresource (3.2.6)
  32 + activemodel (= 3.2.6)
  33 + activesupport (= 3.2.6)
  34 + activesupport (3.2.6)
  35 + i18n (~> 0.6)
  36 + multi_json (~> 1.0)
  37 + acts-as-taggable-on (3.0.2)
  38 + rails (>= 3, < 5)
  39 + arel (3.0.2)
  40 + builder (3.0.0)
  41 + capybara (2.1.0)
6 42 mime-types (>= 1.16)
7 43 nokogiri (>= 1.3.3)
8 44 rack (>= 1.0.0)
9 45 rack-test (>= 0.5.4)
10   - selenium-webdriver (~> 2.0)
11   - xpath (~> 0.1.4)
12   - childprocess (0.3.6)
13   - ffi (~> 1.0, >= 1.0.6)
14   - cucumber (1.1.0)
  46 + xpath (~> 2.0)
  47 + childprocess (0.3.3)
  48 + ffi (~> 1.0.6)
  49 + cucumber (1.0.6)
15 50 builder (>= 2.1.2)
16 51 diff-lcs (>= 1.1.2)
17   - gherkin (~> 2.5.0)
  52 + gherkin (~> 2.4.18)
18 53 json (>= 1.4.6)
19 54 term-ansicolor (>= 1.0.6)
20   - cucumber-rails (0.3.2)
21   - cucumber (>= 0.8.0)
22   - database_cleaner (0.9.1)
  55 + cucumber-rails (1.0.6)
  56 + capybara (>= 1.1.1)
  57 + cucumber (>= 1.0.6)
  58 + nokogiri (>= 1.5.0)
  59 + daemons (1.1.5)
  60 + dalli (2.7.0)
  61 + database_cleaner (1.2.0)
23 62 diff-lcs (1.1.3)
24   - exception_notification (1.0.20090728)
25   - ffi (1.2.0)
26   - gherkin (2.5.4)
  63 + erubis (2.7.0)
  64 + eventmachine (0.12.11)
  65 + fast_gettext (0.6.8)
  66 + ffi (1.0.11)
  67 + gherkin (2.4.21)
27 68 json (>= 1.4.6)
28   - json (1.7.5)
29   - libwebsocket (0.1.6.1)
30   - websocket
  69 + hike (1.2.1)
  70 + hpricot (0.8.6)
  71 + i18n (0.6.0)
  72 + journey (1.0.3)
  73 + json (1.7.3)
  74 + mail (2.4.4)
  75 + i18n (>= 0.4.0)
  76 + mime-types (~> 1.16)
  77 + treetop (~> 1.4.8)
31 78 mime-types (1.19)
32   - multi_json (1.3.7)
  79 + multi_json (1.3.6)
33 80 nokogiri (1.5.5)
34   - rack (1.1.0)
35   - rack-test (0.6.2)
  81 + pg (0.13.2)
  82 + polyglot (0.3.3)
  83 + prototype-rails (3.2.1)
  84 + rails (~> 3.2)
  85 + rack (1.4.1)
  86 + rack-cache (1.2)
  87 + rack (>= 0.4)
  88 + rack-ssl (1.3.2)
  89 + rack
  90 + rack-test (0.6.1)
36 91 rack (>= 1.0)
37   - rake (0.8.7)
38   - rspec (1.2.9)
39   - rspec-rails (1.2.9)
40   - rack (>= 1.0.0)
41   - rspec (>= 1.2.9)
42   - rubyzip (0.9.9)
43   - selenium-webdriver (2.26.0)
  92 + rails (3.2.6)
  93 + actionmailer (= 3.2.6)
  94 + actionpack (= 3.2.6)
  95 + activerecord (= 3.2.6)
  96 + activeresource (= 3.2.6)
  97 + activesupport (= 3.2.6)
  98 + bundler (~> 1.0)
  99 + railties (= 3.2.6)
  100 + rails_autolink (1.1.5)
  101 + rails (> 3.1)
  102 + railties (3.2.6)
  103 + actionpack (= 3.2.6)
  104 + activesupport (= 3.2.6)
  105 + rack-ssl (~> 1.3.2)
  106 + rake (>= 0.8.7)
  107 + rdoc (~> 3.4)
  108 + thor (>= 0.14.6, < 2.0)
  109 + rake (0.9.2.2)
  110 + rdoc (3.9.4)
  111 + rmagick (2.13.1)
  112 + rspec (2.10.0)
  113 + rspec-core (~> 2.10.0)
  114 + rspec-expectations (~> 2.10.0)
  115 + rspec-mocks (~> 2.10.0)
  116 + rspec-core (2.10.1)
  117 + rspec-expectations (2.10.0)
  118 + diff-lcs (~> 1.1.3)
  119 + rspec-mocks (2.10.1)
  120 + rspec-rails (2.10.1)
  121 + actionpack (>= 3.0)
  122 + activesupport (>= 3.0)
  123 + railties (>= 3.0)
  124 + rspec (~> 2.10.0)
  125 + ruby-feedparser (0.7)
  126 + rubyzip (1.1.2)
  127 + selenium-webdriver (2.39.0)
44 128 childprocess (>= 0.2.5)
45   - libwebsocket (~> 0.1.3)
46 129 multi_json (~> 1.0)
47   - rubyzip
48   - system_timer (1.2.4)
  130 + rubyzip (~> 1.0)
  131 + websocket (~> 1.0.4)
  132 + sprockets (2.1.3)
  133 + hike (~> 1.2)
  134 + multi_json (~> 1.0)
  135 + rack (~> 1.0)
  136 + tilt (~> 1.1, != 1.3.0)
49 137 term-ansicolor (1.0.7)
50   - websocket (1.0.4)
51   - xpath (0.1.4)
  138 + thin (1.3.1)
  139 + daemons (>= 1.0.9)
  140 + eventmachine (>= 0.12.6)
  141 + rack (>= 1.0.0)
  142 + thor (0.15.3)
  143 + tilt (1.3.3)
  144 + treetop (1.4.10)
  145 + polyglot
  146 + polyglot (>= 0.3.1)
  147 + tzinfo (0.3.33)
  148 + websocket (1.0.7)
  149 + will_paginate (3.0.3)
  150 + xpath (2.0.0)
52 151 nokogiri (~> 1.3)
53 152  
54 153 PLATFORMS
55 154 ruby
56 155  
57 156 DEPENDENCIES
58   - capybara (= 1.1.1)
59   - cucumber (= 1.1.0)
60   - cucumber-rails (= 0.3.2)
  157 + RedCloth
  158 + acts-as-taggable-on
  159 + capybara
  160 + cucumber
  161 + cucumber-rails
  162 + daemons
  163 + dalli
61 164 database_cleaner
62   - exception_notification (= 1.0.20090728)
63   - rake (= 0.8.7)
64   - rspec (= 1.2.9)
65   - rspec-rails (= 1.2.9)
66   - system_timer
  165 + fast_gettext
  166 + hpricot
  167 + nokogiri
  168 + pg
  169 + prototype-rails
  170 + prototype_legacy_helper (= 0.0.0)!
  171 + rails
  172 + rails_autolink
  173 + rake
  174 + rmagick
  175 + rspec
  176 + rspec-rails
  177 + ruby-feedparser
  178 + selenium-webdriver
  179 + thin
  180 + will_paginate
... ...
INSTALL.md
... ... @@ -110,7 +110,7 @@ Setup Noosfero log and tmp directories:
110 110 # cd /var/lib/noosfero/current
111 111 # ./etc/init.d/noosfero setup
112 112  
113   -Now it's time to setup the database. In this example we are using PostgreSQL, so if you are planning to use a different database this steps won't apply.
  113 +Now it's time to setup the database. In this example we are using PostgreSQL, so if you are planning to use a different database this steps won't apply. Pay special attention to the default collation defined on your setup by the environment variable LC_COLLATE because it might interfere in some sorting operations on your database. For more information checkout `man locale`.
114 114  
115 115 # apt-get install postgresql libpgsql-ruby
116 116 # su postgres -c 'createuser noosfero -S -d -R'
... ...
MIGRATION_ISSUES 0 → 100644
... ... @@ -0,0 +1,41 @@
  1 +* ruby-get-text incmopatible with rails3. Maybe we can use it's gem
  2 +
  3 +* all js code is inside miscellaneous.js. Would be nice to refactor this
  4 +
  5 +* rails 2 uses prototype instead of jquery
  6 +
  7 +* config/environment.rb maybe still have some code that should be on the initializers
  8 +
  9 +* initializers session_store.rb inflections.rb... don't exist
  10 +
  11 +* rails gems version have to be forced on Gemfile or it will use incompatible pre3vious versions (3.1.3)
  12 +
  13 +* Sweepers are now natively supported on Rails 3. Would be nice to refactor it
  14 +
  15 +* On Rails 3 it is no more possible to add allowed tags to avoid scape. The html_safe initializer is an option.
  16 +
  17 +* error when call sqlite_extensiosn
  18 +
  19 +* error related to action_tracker
  20 +
  21 +* check FIXME's in script/quick-start
  22 +
  23 +* check FIXME's in Gemfile
  24 +
  25 +* Check the FIXME in config/routes.rb
  26 +
  27 +* rewrite conditional routing. See FIXME in lib/route_if.rb and re-implement using the Rails 3 mechanism - http://guides.rubyonrails.org/routing.html#advanced-constraints
  28 +
  29 +* check FIXME's in config/environment.rb
  30 +
  31 +* xss_terminate sucks. We should replace it with the builtin mechanism in Rails 3
  32 +
  33 +* instance_eval on Ruby 1.9 yields self, so lambdas that are passed to instance_eval and do not accept exactly 1 argument will blow up. See http://www.ruby-forum.com/topic/213313 ... search for instance_eval and fix where necessary. In special, most of the blocks still need fixing.
  34 +
  35 +* all instances of <% *_form_for ... %> must be changed to <%= instead of <%
  36 +
  37 +* all ActiveRecord models have to declare explicitly which attributes must be allowed for mass assignment with attr_accessible.
  38 +
  39 +* check if we need to update config/locales/*
  40 +
  41 +* check observe_field and labelled_form_for in app/helpers/application_helper.rb
... ...
README.md
  1 +[![Code Climate](https://codeclimate.com/github/Noosfero/noosfero.png)](https://codeclimate.com/github/Noosfero/noosfero)
  2 +
1 3 Noosfero - a web-based social platform
2 4 ======================================
3 5  
... ... @@ -30,4 +32,4 @@ Authorship and copyright information is available in the files listed below.
30 32 -------------------- -----------------------------------------
31 33 AUTHORS.md list of authors (updated at each release)
32 34 COPYRIGHT Copyright statement for the project
33 35 - COPYING Full text of the project license
  36 + COPYING Full text of the project license
34 37 \ No newline at end of file
... ...
Rakefile
  1 +#!/usr/bin/env rake
1 2 # Add your own tasks in files placed in lib/tasks ending in .rake,
2 3 # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 4  
4   -require(File.join(File.dirname(__FILE__), 'config', 'boot'))
  5 +require File.expand_path('../config/application', __FILE__)
5 6  
6   -require 'rake'
7   -require 'rake/testtask'
8   -require 'rake/rdoctask'
9   -
10   -# rails tasks
11   -require 'tasks/rails'
12   -
13   -# plugins' tasks
14   -plugins_tasks = Dir.glob("config/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake").sort +
15   - Dir.glob("config/plugins/*/vendor/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake").sort
16   -plugins_tasks.each{ |ext| load ext }
  7 +Noosfero::Application.load_tasks
... ...
Vagrantfile 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +# -*- mode: ruby -*-
  2 +# vi: set ft=ruby :
  3 +
  4 +VAGRANTFILE_API_VERSION = "2"
  5 +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  6 + config.vm.box = "debian-wheezy"
  7 + config.vm.network :forwarded_port, host: 3000, guest: 3000
  8 + config.vm.provision :shell do |shell|
  9 + shell.inline = 'su vagrant -c /vagrant/script/vagrant'
  10 + end
  11 +end
... ...
app/controllers/admin/admin_panel_controller.rb
... ... @@ -42,7 +42,7 @@ class AdminPanelController &lt; AdminController
42 42 end
43 43 redirect_to :action => 'set_portal_folders'
44 44 else
45   - session[:notice] = __('Community not found. You must insert the identifier of a community from this environment')
  45 + session[:notice] = _('Community not found. You must insert the identifier of a community from this environment')
46 46 end
47 47 end
48 48 end
... ...
app/controllers/admin/environment_design_controller.rb
... ... @@ -3,6 +3,8 @@ class EnvironmentDesignController &lt; BoxOrganizerController
3 3 protect 'edit_environment_design', :environment
4 4  
5 5 def available_blocks
  6 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  7 + # the Noosfero core soon, see ActionItem3045
6 8 @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
7 9 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
8 10 end
... ...
app/controllers/admin/environment_role_manager_controller.rb
1 1 class EnvironmentRoleManagerController < AdminController
2 2 protect 'manage_environment_roles', :environment
3   -
  3 +
4 4 def index
5 5 @admins = Person.find(:all, :conditions => ['role_assignments.resource_type = ?', 'Environment'], :include => :role_assignments )
6 6 end
... ... @@ -8,7 +8,7 @@ class EnvironmentRoleManagerController &lt; AdminController
8 8 def change_roles
9 9 @admin = Person.find(params[:id])
10 10 @roles = Role.find(:all).select{ |r| r.has_kind?(:environment) }
11   - end
  11 + end
12 12  
13 13 def update_roles
14 14 @roles = params[:roles] ? Role.find(params[:roles]) : []
... ... @@ -20,7 +20,7 @@ class EnvironmentRoleManagerController &lt; AdminController
20 20 end
21 21 redirect_to :action => :index
22 22 end
23   -
  23 +
24 24 def change_role
25 25 @roles = Role.find(:all).select{ |r| r.has_kind?(:environment) }
26 26 @admin = Person.find(params[:id])
... ...
app/controllers/admin/features_controller.rb
... ... @@ -34,9 +34,9 @@ class FeaturesController &lt; AdminController
34 34 def manage_enterprise_fields
35 35 environment.custom_enterprise_fields = params[:enterprise_fields]
36 36 if environment.save!
37   - session[:notice] = __('Enterprise fields updated successfully.')
  37 + session[:notice] = _('Enterprise fields updated successfully.')
38 38 else
39   - flash[:error] = __('Enterprise fields not updated successfully.')
  39 + flash[:error] = _('Enterprise fields not updated successfully.')
40 40 end
41 41 redirect_to :action => 'manage_fields'
42 42 end
... ...
app/controllers/admin/users_controller.rb
... ... @@ -45,6 +45,20 @@ class UsersController &lt; AdminController
45 45 redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
46 46 end
47 47  
  48 +
  49 + def destroy_user
  50 + if request.post?
  51 + person = environment.people.find_by_id(params[:id])
  52 + if person && person.destroy
  53 + session[:notice] = _('The profile was deleted.')
  54 + else
  55 + session[:notice] = _('Could not remove profile')
  56 + end
  57 + end
  58 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  59 + end
  60 +
  61 +
48 62 def download
49 63 respond_to do |format|
50 64 format.html
... ... @@ -65,7 +79,7 @@ class UsersController &lt; AdminController
65 79 users = User.connection.execute(command)
66 80 csv_content = "name;email\n"
67 81 users.each { |u|
68   - CSV.generate_row([u['name'], u['email']], 2, csv_content, fs=';')
  82 + csv_content << CSV.generate_line([u['name'], u['email']], {:col_sep => ';'})
69 83 }
70 84 render :text => csv_content, :content_type => 'text/csv', :layout => false
71 85 end
... ...
app/controllers/application_controller.rb
  1 +require 'noosfero/multi_tenancy'
  2 +
1 3 class ApplicationController < ActionController::Base
  4 + protect_from_forgery
2 5  
3 6 before_filter :setup_multitenancy
4 7 before_filter :detect_stuff_by_domain
5   - before_filter :init_noosfero_plugins_controller_filters
  8 + before_filter :init_noosfero_plugins
6 9 before_filter :allow_cross_domain_access
7 10  
  11 + after_filter :set_csrf_cookie
  12 +
  13 + def set_csrf_cookie
  14 + cookies['_noosfero_.XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery? && logged_in?
  15 + end
  16 +
8 17 def allow_cross_domain_access
9 18 origin = request.headers['Origin']
10 19 return if origin.blank?
... ... @@ -21,7 +30,8 @@ class ApplicationController &lt; ActionController::Base
21 30 include ApplicationHelper
22 31 layout :get_layout
23 32 def get_layout
24   - return nil if request.format == :js
  33 + return nil if request.format == :js or request.xhr?
  34 +
25 35 theme_layout = theme_option(:layout)
26 36 if theme_layout
27 37 theme_view_file('layouts/'+theme_layout) || theme_layout
... ... @@ -30,11 +40,9 @@ class ApplicationController &lt; ActionController::Base
30 40 end
31 41 end
32 42  
33   - filter_parameter_logging :password
34   -
35 43 def log_processing
36 44 super
37   - return unless ENV['RAILS_ENV'] == 'production'
  45 + return unless Rails.env == 'production'
38 46 if logger && logger.info?
39 47 logger.info(" HTTP Referer: #{request.referer}")
40 48 logger.info(" User Agent: #{request.user_agent}")
... ... @@ -65,6 +73,7 @@ class ApplicationController &lt; ActionController::Base
65 73 FastGettext.default_locale = environment.default_locale
66 74 FastGettext.locale = (params[:lang] || session[:lang] || environment.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
67 75 I18n.locale = FastGettext.locale
  76 + I18n.default_locale = FastGettext.default_locale
68 77 if params[:lang]
69 78 session[:lang] = params[:lang]
70 79 end
... ... @@ -74,18 +83,24 @@ class ApplicationController &lt; ActionController::Base
74 83  
75 84 attr_reader :environment
76 85  
77   - before_filter :load_terminology
78   -
79 86 # declares that the given <tt>actions</tt> cannot be accessed by other HTTP
80 87 # method besides POST.
81 88 def self.post_only(actions, redirect = { :action => 'index'})
82   - verify :method => :post, :only => actions, :redirect_to => redirect
  89 + before_filter(:only => actions) do |controller|
  90 + if !controller.request.post?
  91 + controller.redirect_to redirect
  92 + end
  93 + end
83 94 end
84 95  
85 96 helper_method :current_person, :current_person
86 97  
87 98 protected
88 99  
  100 + def verified_request?
  101 + super || form_authenticity_token == request.headers['X-XSRF-TOKEN']
  102 + end
  103 +
89 104 def setup_multitenancy
90 105 Noosfero::MultiTenancy.setup!(request.host)
91 106 end
... ... @@ -111,7 +126,10 @@ class ApplicationController &lt; ActionController::Base
111 126 @environment = Environment.default
112 127 if @environment.nil? && Rails.env.development?
113 128 # This should only happen in development ...
114   - @environment = Environment.create!(:name => "Noosfero", :is_default => true)
  129 + @environment = Environment.new
  130 + @environment.name = "Noosfero"
  131 + @environment.is_default = true
  132 + @environment.save!
115 133 end
116 134 else
117 135 @environment = @domain.environment
... ... @@ -127,36 +145,15 @@ class ApplicationController &lt; ActionController::Base
127 145  
128 146 include Noosfero::Plugin::HotSpot
129 147  
130   - # This is a generic method that initialize any possible filter defined by a
131   - # plugin to the current controller being initialized.
132   - def init_noosfero_plugins_controller_filters
133   - plugins.each do |plugin|
134   - filters = plugin.send(self.class.name.underscore + '_filters')
135   - filters = [filters] if !filters.kind_of?(Array)
136   - controller_filters = self.class.filter_chain.map {|c| c.method }
137   - filters.each do |plugin_filter|
138   - filter_method = plugin.class.name.underscore.gsub('/','_') + '_' + plugin_filter[:method_name]
139   - unless controller_filters.include?(filter_method)
140   - self.class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {}))
141   - self.class.send(:define_method, filter_method) do
142   - instance_eval(&plugin_filter[:block]) if environment.plugin_enabled?(plugin.class)
143   - end
144   - end
145   - end
146   - end
147   - end
148   -
149   - def load_terminology
150   - # cache terminology for performance
151   - @@terminology_cache ||= {}
152   - @@terminology_cache[environment.id] ||= environment.terminology
153   - Noosfero.terminology = @@terminology_cache[environment.id]
  148 + # FIXME this filter just loads @plugins to children controllers and helpers
  149 + def init_noosfero_plugins
  150 + plugins
154 151 end
155 152  
156 153 def render_not_found(path = nil)
157 154 @no_design_blocks = true
158 155 @path ||= request.path
159   - render :template => 'shared/not_found.rhtml', :status => 404, :layout => get_layout
  156 + render :template => 'shared/not_found.html.erb', :status => 404, :layout => get_layout
160 157 end
161 158 alias :render_404 :render_not_found
162 159  
... ... @@ -164,12 +161,12 @@ class ApplicationController &lt; ActionController::Base
164 161 @no_design_blocks = true
165 162 @message = message
166 163 @title = title
167   - render :template => 'shared/access_denied.rhtml', :status => 403
  164 + render :template => 'shared/access_denied.html.erb', :status => 403
168 165 end
169 166  
170 167 def load_category
171 168 unless params[:category_path].blank?
172   - path = params[:category_path].join('/')
  169 + path = params[:category_path]
173 170 @category = environment.categories.find_by_path(path)
174 171 if @category.nil?
175 172 render_not_found(path)
... ...
app/controllers/box_organizer_controller.rb
... ... @@ -80,6 +80,22 @@ class BoxOrganizerController &lt; ApplicationController
80 80 render :action => 'edit', :layout => false
81 81 end
82 82  
  83 + def search_autocomplete
  84 + if request.xhr? and params[:query]
  85 + search = params[:query]
  86 + path_list = if boxes_holder.is_a?(Environment) && boxes_holder.enabled?('use_portal_community') && boxes_holder.portal_community
  87 + boxes_holder.portal_community.articles.find(:all, :conditions=>"name ILIKE '%#{search}%' or path ILIKE '%#{search}%'", :limit=>20).map { |content| "/{portal}/"+content.path }
  88 + elsif boxes_holder.is_a?(Profile)
  89 + boxes_holder.articles.find(:all, :conditions=>"name ILIKE '%#{search}%' or path ILIKE '%#{search}%'", :limit=>20).map { |content| "/{profile}/"+content.path }
  90 + else
  91 + []
  92 + end
  93 + render :json => path_list.to_json
  94 + else
  95 + redirect_to "/"
  96 + end
  97 + end
  98 +
83 99 def save
84 100 @block = boxes_holder.blocks.find(params[:id])
85 101 @block.update_attributes(params[:block])
... ... @@ -99,6 +115,12 @@ class BoxOrganizerController &lt; ApplicationController
99 115 end
100 116 end
101 117  
  118 + def clone_block
  119 + block = Block.find(params[:id])
  120 + block.duplicate
  121 + redirect_to :action => 'index'
  122 + end
  123 +
102 124 protected :boxes_editor?
103 125  
104 126 end
... ...
app/controllers/embed_controller.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +class EmbedController < ApplicationController
  2 + layout 'embed'
  3 +
  4 + def block
  5 + @block = Block.find(params[:id])
  6 + if !@block.embedable? || !@block.visible?
  7 + render 'unavailable', :status => 403
  8 + end
  9 + rescue ActiveRecord::RecordNotFound
  10 + render 'not_found', :status => 404
  11 + end
  12 +
  13 +end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -24,10 +24,16 @@ class CmsController &lt; MyProfileController
24 24 (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)))
25 25 end
26 26  
27   - protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :upload_files] do |c, user, profile|
  27 + protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :upload_files, :new] do |c, user, profile|
28 28 user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))
29 29 end
30 30  
  31 + protect_if :only => :new do |c, user, profile|
  32 + article = profile.articles.find_by_id(c.params[:parent_id])
  33 + (!article.nil? && (article.allow_create?(user) || article.parent.allow_create?(user))) ||
  34 + (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)))
  35 + end
  36 +
31 37 protect_if :only => [:destroy, :publish] do |c, user, profile|
32 38 profile.articles.find(c.params[:id]).allow_post_content?(user)
33 39 end
... ... @@ -47,8 +53,7 @@ class CmsController &lt; MyProfileController
47 53 conditions = ['type != ?', 'RssFeed']
48 54 end
49 55  
50   - @articles = @article.children.paginate(
51   - :order => "case when type = 'Folder' then 0 when type ='Blog' then 1 else 2 end, updated_at DESC",
  56 + @articles = @article.children.reorder("case when type = 'Folder' then 0 when type ='Blog' then 1 else 2 end, updated_at DESC, name").paginate(
52 57 :conditions => conditions,
53 58 :per_page => per_page,
54 59 :page => params[:npage]
... ... @@ -182,7 +187,7 @@ class CmsController &lt; MyProfileController
182 187 end
183 188 if request.post? && params[:uploaded_files]
184 189 params[:uploaded_files].each do |file|
185   - @uploaded_files << UploadedFile.create(:uploaded_data => file, :profile => profile, :parent => @parent, :last_changed_by => user) unless file == ''
  190 + @uploaded_files << UploadedFile.create({:uploaded_data => file, :profile => profile, :parent => @parent, :last_changed_by => user}, :without_protection => true) unless file == ''
186 191 end
187 192 @errors = @uploaded_files.select { |f| f.errors.any? }
188 193 if @errors.any?
... ... @@ -204,7 +209,7 @@ class CmsController &lt; MyProfileController
204 209 if request.post?
205 210 @article.destroy
206 211 session[:notice] = _("\"#{@article.name}\" was removed.")
207   - referer = ActionController::Routing::Routes.recognize_path URI.parse(request.referer).path rescue nil
  212 + referer = Rails.application.routes.recognize_path URI.parse(request.referer).path rescue nil
208 213 if referer and referer[:controller] == 'cms' and referer[:action] != 'edit'
209 214 redirect_to referer
210 215 elsif @article.parent
... ... @@ -221,13 +226,12 @@ class CmsController &lt; MyProfileController
221 226  
222 227 def update_categories
223 228 @object = params[:id] ? @profile.articles.find(params[:id]) : Article.new
  229 + @categories = @toplevel_categories = environment.top_level_categories
224 230 if params[:category_id]
225 231 @current_category = Category.find(params[:category_id])
226 232 @categories = @current_category.children
227   - else
228   - @categories = environment.top_level_categories.select{|i| !i.children.empty?}
229 233 end
230   - render :partial => 'shared/select_categories', :locals => {:object_name => 'article', :multiple => true}, :layout => false
  234 + render :template => 'shared/update_categories', :locals => { :category => @current_category }
231 235 end
232 236  
233 237 def publish
... ... @@ -248,7 +252,7 @@ class CmsController &lt; MyProfileController
248 252 begin
249 253 task.finish unless item[:group].moderated_articles?
250 254 rescue Exception => ex
251   - @failed[ex.clean_message] ? @failed[ex.clean_message] << item[:group].name : @failed[ex.clean_message] = [item[:group].name]
  255 + @failed[ex.message] ? @failed[ex.message] << item[:group].name : @failed[ex.message] = [item[:group].name]
252 256 end
253 257 end
254 258 if @failed.blank?
... ...
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -48,6 +48,7 @@ class ManageProductsController &lt; ApplicationController
48 48 end
49 49  
50 50 def new
  51 + @no_design_blocks = true
51 52 @category = params[:selected_category_id] ? Category.find(params[:selected_category_id]) : nil
52 53 @product = @profile.products.build(:product_category => @category)
53 54 @categories = ProductCategory.top_level_for(environment)
... ... @@ -85,7 +86,7 @@ class ManageProductsController &lt; ApplicationController
85 86 @edit = true
86 87 @level = @category.level
87 88 if request.post?
88   - if @product.update_attributes(:product_category_id => params[:selected_category_id])
  89 + if @product.update_attributes({:product_category_id => params[:selected_category_id]}, :without_protection => true)
89 90 render :partial => 'shared/redirect_via_javascript',
90 91 :locals => { :url => url_for(:controller => 'manage_products', :action => 'show', :id => @product) }
91 92 else
... ... @@ -207,7 +208,7 @@ class ManageProductsController &lt; ApplicationController
207 208 }.to_json
208 209 else
209 210 render :text => {:ok => false,
210   - :error_msg => _(cost.errors['name']) % {:fn => _('Name')}
  211 + :error_msg => _(cost.errors['name'].join('\n')) % {:fn => _('Name')}
211 212 }.to_json
212 213 end
213 214 end
... ...
app/controllers/my_profile/maps_controller.rb
... ... @@ -31,23 +31,11 @@ class MapsController &lt; MyProfileController
31 31 end
32 32  
33 33 def search_city
34   -
35   - term = params[:term];
36   -
37   - regions = NationalRegion.search_city(term + "%", true).map {|r|{ :label => r.city , :category => r.state}}
38   -
39   - render :json => regions
40   -
  34 + render :json => MapsHelper.search_city(params[:term])
41 35 end
42 36  
43 37 def search_state
44   -
45   - term = params[:term];
46   -
47   - regions = NationalRegion.search_state(term + "%", true).map {|r|{ :label => r.state}}
48   -
49   - render :json => regions
50   -
  38 + render :json => MapsHelper.search_state(params[:term])
51 39 end
52 40  
53 41 end
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -20,7 +20,7 @@ class MembershipsController &lt; MyProfileController
20 20 @community.environment = environment
21 21 @back_to = params[:back_to] || url_for(:action => 'index')
22 22 if request.post? && @community.valid?
23   - @community = Community.create_after_moderation(user, {:environment => environment}.merge(params[:community]))
  23 + @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment}))
24 24 redirect_to @back_to
25 25 return
26 26 end
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -55,10 +55,4 @@ class ProfileDesignController &lt; BoxOrganizerController
55 55 blocks
56 56 end
57 57  
58   - def clone
59   - block = Block.find(params[:id])
60   - block.duplicate
61   - redirect_to :action => 'index'
62   - end
63   -
64 58 end
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -15,20 +15,14 @@ class ProfileEditorController &lt; MyProfileController
15 15 @possible_domains = profile.possible_domains
16 16 if request.post?
17 17 params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash)
18   - begin
19   - Profile.transaction do
20   - Image.transaction do
21   - if profile.update_attributes!(params[:profile_data])
22   - redirect_to :action => 'index', :profile => profile.identifier
23   - end
  18 + Profile.transaction do
  19 + Image.transaction do
  20 + if @profile_data.update_attributes(params[:profile_data])
  21 + redirect_to :action => 'index', :profile => profile.identifier
  22 + else
  23 + profile.identifier = params[:profile] if profile.identifier.blank?
24 24 end
25   - end
26   - rescue Exception => ex
27   - if profile.identifier.blank?
28   - profile.identifier = params[:profile]
29   - end
30   - session[:notice] = _('Cannot update profile')
31   - logger.error ex.to_s
  25 + end
32 26 end
33 27 end
34 28 end
... ... @@ -55,13 +49,12 @@ class ProfileEditorController &lt; MyProfileController
55 49  
56 50 def update_categories
57 51 @object = profile
  52 + @categories = @toplevel_categories = environment.top_level_categories
58 53 if params[:category_id]
59 54 @current_category = Category.find(params[:category_id])
60 55 @categories = @current_category.children
61   - else
62   - @categories = environment.top_level_categories.select{|i| !i.children.empty?}
63 56 end
64   - render :partial => 'shared/select_categories', :locals => {:object_name => 'profile_data', :multiple => true}, :layout => false
  57 + render :template => 'shared/update_categories', :locals => { :category => @current_category }
65 58 end
66 59  
67 60 def header_footer
... ...
app/controllers/my_profile/tasks_controller.rb
... ... @@ -27,7 +27,7 @@ class TasksController &lt; MyProfileController
27 27 task.send(decision)
28 28 rescue Exception => ex
29 29 message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
30   - failed[ex.clean_message] ? failed[ex.clean_message] << message : failed[ex.clean_message] = [message]
  30 + failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
31 31 end
32 32 end
33 33 end
... ...
app/controllers/public/account_controller.rb
... ... @@ -17,6 +17,8 @@ class AccountController &lt; ApplicationController
17 17 @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code]
18 18 if @user and @user.activate
19 19 @message = _("Your account has been activated, now you can log in!")
  20 + check_redirection
  21 + session[:join] = params[:join] unless params[:join].blank?
20 22 render :action => 'login', :userlogin => @user.login
21 23 else
22 24 session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
... ... @@ -35,6 +37,7 @@ class AccountController &lt; ApplicationController
35 37 self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user]
36 38  
37 39 if logged_in?
  40 + check_join_in_community(self.current_user)
38 41 if params[:remember_me] == "1"
39 42 self.current_user.remember_me
40 43 cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
... ... @@ -69,6 +72,8 @@ class AccountController &lt; ApplicationController
69 72 session[:notice] = _("This environment doesn't allow user registration.")
70 73 end
71 74  
  75 + store_location(request.referer) unless params[:return_to] or session[:return_to]
  76 +
72 77 @block_bot = !!session[:may_be_a_bot]
73 78 @invitation_code = params[:invitation_code]
74 79 begin
... ... @@ -77,6 +82,7 @@ class AccountController &lt; ApplicationController
77 82 @user.environment = environment
78 83 @terms_of_use = environment.terms_of_use
79 84 @user.person_data = params[:profile_data]
  85 + @user.return_to = session[:return_to]
80 86 @person = Person.new(params[:profile_data])
81 87 @person.environment = @user.environment
82 88 if request.post?
... ... @@ -88,6 +94,7 @@ class AccountController &lt; ApplicationController
88 94 if session[:may_be_a_bot]
89 95 return false unless verify_recaptcha :model=>@user, :message=>_('Captcha (the human test)')
90 96 end
  97 + @user.community_to_join = session[:join]
91 98 @user.signup!
92 99 owner_role = Role.find_by_name('owner')
93 100 @user.person.affiliate(@user.person, [owner_role]) if owner_role
... ... @@ -98,7 +105,8 @@ class AccountController &lt; ApplicationController
98 105 end
99 106 if @user.activated?
100 107 self.current_user = @user
101   - redirect_to '/'
  108 + check_join_in_community(@user)
  109 + go_to_signup_initial_page
102 110 else
103 111 @register_pending = true
104 112 end
... ... @@ -132,12 +140,8 @@ class AccountController &lt; ApplicationController
132 140 params[:new_password_confirmation])
133 141 session[:notice] = _('Your password has been changed successfully!')
134 142 redirect_to :action => 'index'
135   - rescue User::IncorrectPassword => e
136   - session[:notice] = _('The supplied current password is incorrect.')
137   - render :action => 'change_password'
  143 + rescue Exception
138 144 end
139   - else
140   - render :action => 'change_password'
141 145 end
142 146 end
143 147  
... ... @@ -163,12 +167,12 @@ class AccountController &lt; ApplicationController
163 167 render :action => 'password_recovery_sent'
164 168 rescue ActiveRecord::RecordNotFound
165 169 if params[:value].blank?
166   - @change_password.errors.add_to_base(_('Can not recover user password with blank value.'))
  170 + @change_password.errors[:base] << _('Can not recover user password with blank value.')
167 171 else
168   - @change_password.errors.add_to_base(_('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]])
  172 + @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]]
169 173 end
170 174 rescue ActiveRecord::RecordInvald
171   - @change_password.errors.add_to_base(_('Could not perform password recovery for the user.'))
  175 + @change_password.errors[:base] << _('Could not perform password recovery for the user.')
172 176 end
173 177 end
174 178 end
... ... @@ -247,15 +251,19 @@ class AccountController &lt; ApplicationController
247 251 end
248 252 end
249 253  
250   - def check_url
  254 + def check_valid_name
251 255 @identifier = params[:identifier]
252 256 valid = Person.is_available?(@identifier, environment)
253 257 if valid
254 258 @status = _('This login name is available')
255 259 @status_class = 'validated'
256   - else
  260 + elsif !@identifier.empty?
  261 + @suggested_usernames = suggestion_based_on_username(@identifier)
257 262 @status = _('This login name is unavailable')
258 263 @status_class = 'invalid'
  264 + else
  265 + @status_class = 'invalid'
  266 + @status = _('This field can\'t be blank')
259 267 end
260 268 render :partial => 'identifier_status'
261 269 end
... ... @@ -288,6 +296,23 @@ class AccountController &lt; ApplicationController
288 296 render :text => user_data.to_json, :layout => false, :content_type => "application/javascript"
289 297 end
290 298  
  299 + def search_cities
  300 + if request.xhr? and params[:state_name] and params[:city_name]
  301 + render :json => MapsHelper.search_city(params[:city_name], params[:state_name])
  302 + else
  303 + render :json => [].to_json
  304 + end
  305 + end
  306 +
  307 + def search_state
  308 + if request.xhr? and params[:state_name]
  309 + render :json => MapsHelper.search_state(params[:state_name])
  310 + else
  311 + render :json => [].to_json
  312 + end
  313 + end
  314 +
  315 +
291 316 protected
292 317  
293 318 def redirect?
... ... @@ -371,29 +396,20 @@ class AccountController &lt; ApplicationController
371 396 if params[:return_to]
372 397 redirect_to params[:return_to]
373 398 elsif environment.enabled?('allow_change_of_redirection_after_login')
374   - case user.preferred_login_redirection
375   - when 'keep_on_same_page'
376   - redirect_back_or_default(user.admin_url)
377   - when 'site_homepage'
378   - redirect_to :controller => :home
379   - when 'user_profile_page'
380   - redirect_to user.public_profile_url
381   - when 'user_homepage'
382   - redirect_to user.url
383   - when 'user_control_panel'
384   - redirect_to user.admin_url
385   - else
386   - redirect_back_or_default(user.admin_url)
387   - end
  399 + check_redirection_options(user, user.preferred_login_redirection, user.admin_url)
388 400 else
389 401 if environment == current_user.environment
390   - redirect_back_or_default(user.admin_url)
  402 + check_redirection_options(user, environment.redirection_after_login, user.admin_url)
391 403 else
392 404 redirect_back_or_default(:controller => 'home')
393 405 end
394 406 end
395 407 end
396 408  
  409 + def go_to_signup_initial_page
  410 + check_redirection_options(user, user.environment.redirection_after_signup, user.url)
  411 + end
  412 +
397 413 def redirect_if_logged_in
398 414 if logged_in?
399 415 go_to_initial_page
... ... @@ -409,4 +425,37 @@ class AccountController &lt; ApplicationController
409 425 user
410 426 end
411 427  
  428 + protected
  429 +
  430 + def check_redirection_options(user, condition, default)
  431 + case condition
  432 + when 'keep_on_same_page'
  433 + redirect_back_or_default(user.admin_url)
  434 + when 'site_homepage'
  435 + redirect_to :controller => :home
  436 + when 'user_profile_page'
  437 + redirect_to user.public_profile_url
  438 + when 'user_homepage'
  439 + redirect_to user.url
  440 + when 'user_control_panel'
  441 + redirect_to user.admin_url
  442 + else
  443 + redirect_back_or_default(default)
  444 + end
  445 + end
  446 +
  447 + def check_redirection
  448 + unless params[:redirection].blank?
  449 + session[:return_to] = @user.return_to
  450 + @user.update_attributes(:return_to => nil)
  451 + end
  452 + end
  453 +
  454 + def check_join_in_community(user)
  455 + profile_to_join = session[:join]
  456 + unless profile_to_join.blank?
  457 + environment.profiles.find_by_identifier(profile_to_join).add_member(user.person)
  458 + session.delete(:join)
  459 + end
  460 + end
412 461 end
... ...
app/controllers/public/chat_controller.rb
... ... @@ -19,7 +19,7 @@ class ChatController &lt; PublicController
19 19 def avatar
20 20 profile = environment.profiles.find_by_identifier(params[:id])
21 21 filename, mimetype = profile_icon(profile, :minor, true)
22   - data = File.read(File.join(RAILS_ROOT, 'public', filename))
  22 + data = File.read(File.join(Rails.root, 'public', filename))
23 23 render :text => data, :layout => false, :content_type => mimetype
24 24 expires_in 24.hours
25 25 end
... ...
app/controllers/public/content_viewer_controller.rb
  1 +require 'diffy'
  2 +
1 3 class ContentViewerController < ApplicationController
2 4  
3 5 needs_profile
... ... @@ -6,7 +8,9 @@ class ContentViewerController &lt; ApplicationController
6 8 helper TagsHelper
7 9  
8 10 def view_page
9   - path = params[:page].join('/')
  11 + path = params[:page]
  12 + path = path.join('/') if path.kind_of?(Array)
  13 + path = "#{path}.#{params[:format]}" if params[:format]
10 14 @version = params[:version].to_i
11 15  
12 16 if path.blank?
... ... @@ -32,12 +36,12 @@ class ContentViewerController &lt; ApplicationController
32 36 return render_access_denied unless @page.display_versions?
33 37 @versioned_article = @page.versions.find_by_version(@version)
34 38 if @versioned_article && @page.versions.latest.version != @versioned_article.version
35   - render :template => 'content_viewer/versioned_article.rhtml'
  39 + render :template => 'content_viewer/versioned_article.html.erb'
36 40 return
37 41 end
38 42 end
39 43  
40   - redirect_to_translation if @page.profile.redirect_l10n
  44 + redirect_to_translation and return if @page.profile.redirect_l10n
41 45  
42 46 if request.post?
43 47 if @page.forum? && @page.has_terms_of_use && params[:terms_accepted] == "true"
... ... @@ -50,7 +54,7 @@ class ContentViewerController &lt; ApplicationController
50 54 end
51 55  
52 56 # At this point the page will be showed
53   - @page.hit
  57 + @page.hit unless user_is_a_bot?
54 58  
55 59 @page = FilePresenter.for @page
56 60  
... ... @@ -87,7 +91,7 @@ class ContentViewerController &lt; ApplicationController
87 91 blog_with_translation = @page.blog? && @page.display_posts_in_current_language?
88 92 posts = posts.native_translations if blog_with_translation
89 93  
90   - @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile)))
  94 + @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile))).to_a
91 95  
92 96 if blog_with_translation
93 97 @posts.replace @posts.map{ |p| p.get_translation_to(FastGettext.locale) }.compact
... ... @@ -111,15 +115,32 @@ class ContentViewerController &lt; ApplicationController
111 115 @comments = @plugins.filter(:unavailable_comments, @comments)
112 116 @comments_count = @comments.count
113 117 @comments = @comments.without_reply.paginate(:per_page => per_page, :page => params[:comment_page] )
  118 + @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order]
  119 +
  120 + if request.xhr? and params[:comment_order]
  121 + if @comment_order == 'newest'
  122 + @comments = @comments.reverse
  123 + end
  124 +
  125 + return render :partial => 'comment/comment', :collection => @comments
  126 + end
114 127  
115 128 if params[:slideshow]
116 129 render :action => 'slideshow', :layout => 'slideshow'
  130 + return
117 131 end
  132 + render :view_page, :formats => [:html]
118 133 end
119 134  
120   - def article_versions
  135 + def versions_diff
121 136 path = params[:page].join('/')
122 137 @page = profile.articles.find_by_path(path)
  138 + @v1, @v2 = @page.versions.find_by_version(params[:v1]), @page.versions.find_by_version(params[:v2])
  139 + end
  140 +
  141 + def article_versions
  142 + path = params[:page]
  143 + @page = profile.articles.find_by_path(path)
123 144 return unless allow_access_to_page(path)
124 145  
125 146 render_access_denied unless @page.display_versions?
... ... @@ -164,7 +185,7 @@ class ContentViewerController &lt; ApplicationController
164 185 elsif !@page.display_to?(user)
165 186 if !profile.public?
166 187 private_profile_partial_parameters
167   - render :template => 'profile/_private_profile.rhtml', :status => 403
  188 + render :template => 'profile/_private_profile', :status => 403
168 189 allowed = false
169 190 else #if !profile.visible?
170 191 render_access_denied
... ... @@ -174,4 +195,12 @@ class ContentViewerController &lt; ApplicationController
174 195 allowed
175 196 end
176 197  
  198 + def user_is_a_bot?
  199 + user_agent= request.env["HTTP_USER_AGENT"]
  200 + user_agent.blank? ||
  201 + user_agent.match(/bot/) ||
  202 + user_agent.match(/spider/) ||
  203 + user_agent.match(/crawler/) ||
  204 + user_agent.match(/\(.*https?:\/\/.*\)/)
  205 + end
177 206 end
... ...
app/controllers/public/events_controller.rb
... ... @@ -7,11 +7,11 @@ class EventsController &lt; PublicController
7 7 @date = build_date(params[:year], params[:month], params[:day])
8 8  
9 9 if !params[:year] && !params[:month] && !params[:day]
10   - @events = profile.events.next_events_from_month(@date)
  10 + @events = profile.events.next_events_from_month(@date).paginate(:per_page => per_page, :page => params[:page])
11 11 end
12 12  
13 13 if params[:year] || params[:month]
14   - @events = profile.events.by_month(@date)
  14 + @events = profile.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page])
15 15 end
16 16  
17 17 events_in_range = profile.events.by_range((@date - 1.month).at_beginning_of_month .. (@date + 1.month).at_end_of_month)
... ... @@ -21,7 +21,7 @@ class EventsController &lt; PublicController
21 21  
22 22 def events_by_day
23 23 @date = build_date(params[:year], params[:month], params[:day])
24   - @events = profile.events.by_day(@date)
  24 + @events = profile.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page])
25 25 render :partial => 'events'
26 26 end
27 27  
... ... @@ -29,4 +29,7 @@ class EventsController &lt; PublicController
29 29  
30 30 include EventsHelper
31 31  
  32 + def per_page
  33 + 20
  34 + end
32 35 end
... ...
app/controllers/public/profile_controller.rb
... ... @@ -3,7 +3,7 @@ class ProfileController &lt; PublicController
3 3 needs_profile
4 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
6   - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
  6 + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
7 7  
8 8 helper TagsHelper
9 9  
... ... @@ -32,7 +32,7 @@ class ProfileController &lt; PublicController
32 32 @tag = params[:id]
33 33 @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_#{profile.id.to_s}_page_#{params[:npage]}"
34 34 if is_cache_expired?(@tag_cache_key)
35   - @tagged = profile.find_tagged_with(@tag).paginate(:per_page => 20, :page => params[:npage])
  35 + @tagged = profile.tagged_with(@tag).paginate(:per_page => 20, :page => params[:npage])
36 36 end
37 37 end
38 38  
... ... @@ -97,21 +97,12 @@ class ProfileController &lt; PublicController
97 97 end
98 98  
99 99 def join_not_logged
100   - if request.post?
101   - profile.add_member(user)
102   - session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed?
103   - redirect_to_previous_location
  100 + session[:join] = profile.identifier
  101 +
  102 + if user
  103 + redirect_to :controller => 'profile', :action => 'join'
104 104 else
105   - if user.memberships.include?(profile)
106   - session[:notice] = _('You are already a member of %s.') % profile.name
107   - redirect_to profile.url
108   - return
109   - end
110   - if request.xhr?
111   - render :layout => false
112   - else
113   - redirect_to profile.url
114   - end
  105 + redirect_to :controller => '/account', :action => 'login'
115 106 end
116 107 end
117 108  
... ... @@ -167,7 +158,7 @@ class ProfileController &lt; PublicController
167 158 session[:notice] = _("You have unblocked %s successfully. ") % profile.name
168 159 redirect_to :controller => 'profile', :action => 'index'
169 160 else
170   - message = __('You are not allowed to unblock enterprises in this environment.')
  161 + message = _('You are not allowed to unblock enterprises in this environment.')
171 162 render_access_denied(message)
172 163 end
173 164 end
... ... @@ -219,7 +210,7 @@ class ProfileController &lt; PublicController
219 210  
220 211 render :update do |page|
221 212 page.insert_html :bottom, 'profile-wall-activities-comments-'+params[:activity],
222   - :partial => 'comment', :collection => activity.comments.paginate(:per_page => comments_per_page, :page => comment_page)
  213 + :partial => 'comment', :collection => activity.comments.flatten.paginate(:per_page => comments_per_page, :page => comment_page)
223 214  
224 215 if no_more_pages
225 216 page.remove 'profile-wall-activities-comments-more-'+params[:activity]
... ... @@ -304,14 +295,6 @@ class ProfileController &lt; PublicController
304 295 end
305 296 end
306 297  
307   - def profile_info
308   - begin
309   - @block = profile.blocks.find(params[:block_id])
310   - rescue
311   - render :text => _('Profile information could not be loaded')
312   - end
313   - end
314   -
315 298 def report_abuse
316 299 @abuse_report = AbuseReport.new
317 300 render :layout => false
... ...
app/controllers/public/search_controller.rb
... ... @@ -29,7 +29,7 @@ class SearchController &lt; PublicController
29 29 @asset = key
30 30 send(key)
31 31 @order << key
32   - @names[key] = getterm(description)
  32 + @names[key] = _(description)
33 33 end
34 34 @asset = nil
35 35  
... ... @@ -80,7 +80,7 @@ class SearchController &lt; PublicController
80 80 end
81 81  
82 82 def enterprises
83   - @scope = visible_profiles(Enterprise, [{:products => :product_category}])
  83 + @scope = visible_profiles(Enterprise)
84 84 full_text_search
85 85 end
86 86  
... ... @@ -99,14 +99,14 @@ class SearchController &lt; PublicController
99 99 @events = []
100 100 if params[:day] || !params[:year] && !params[:month]
101 101 @events = @category ?
102   - environment.events.by_day(@date).in_category(Category.find(@category_id)) :
103   - environment.events.by_day(@date)
  102 + environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
  103 + environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page])
104 104 end
105 105  
106 106 if params[:year] || params[:month]
107 107 @events = @category ?
108   - environment.events.by_month(@date).in_category(Category.find(@category_id)) :
109   - environment.events.by_month(@date)
  108 + environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
  109 + environment.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page])
110 110 end
111 111  
112 112 @scope = date_range && params[:action] == 'events' ? environment.events.by_range(date_range) : environment.events
... ... @@ -133,13 +133,13 @@ class SearchController &lt; PublicController
133 133 @tag = params[:tag]
134 134 @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_env_#{environment.id.to_s}_page_#{params[:npage]}"
135 135 if is_cache_expired?(@tag_cache_key)
136   - @searches[@asset] = {:results => environment.articles.find_tagged_with(@tag).paginate(paginate_options)}
  136 + @searches[@asset] = {:results => environment.articles.tagged_with(@tag).paginate(paginate_options)}
137 137 end
138 138 end
139 139  
140 140 def events_by_day
141 141 @date = build_date(params[:year], params[:month], params[:day])
142   - @events = environment.events.by_day(@date)
  142 + @events = environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page])
143 143 render :partial => 'events/events'
144 144 end
145 145  
... ... @@ -159,7 +159,7 @@ class SearchController &lt; PublicController
159 159 if params[:category_path].blank?
160 160 render_not_found if params[:action] == 'category_index'
161 161 else
162   - path = params[:category_path].join('/')
  162 + path = params[:category_path]
163 163 @category = environment.categories.find_by_path(path)
164 164 if @category.nil?
165 165 render_not_found(path)
... ... @@ -224,4 +224,8 @@ class SearchController &lt; PublicController
224 224 @environment.send(klass.name.underscore.pluralize).visible.includes(relations)
225 225 end
226 226  
  227 + def per_page
  228 + 20
  229 + end
  230 +
227 231 end
... ...
app/controllers/themes_controller.rb
... ... @@ -12,7 +12,7 @@ class ThemesController &lt; ApplicationController
12 12  
13 13 def index
14 14 @environment = environment
15   - @themes = environment.themes + Theme.approved_themes(target)
  15 + @themes = (environment.themes + Theme.approved_themes(target)).sort_by { |t| t.name }
16 16  
17 17 @current_theme = target.theme
18 18  
... ...
app/helpers/account_helper.rb
... ... @@ -12,4 +12,22 @@ module AccountHelper
12 12 _('Checking if e-mail address is already taken...')
13 13 end
14 14 end
  15 +
  16 + def suggestion_based_on_username(requested_username='')
  17 + return "" if requested_username.empty?
  18 +
  19 + requested_username = requested_username.downcase.tr("^#{Profile::IDENTIFIER_FORMAT}", '')
  20 + usernames = []
  21 + tries = 0
  22 + 3.times do
  23 + begin
  24 + valid_name = requested_username + rand(1000).to_s
  25 + tries += 1
  26 + invalid = usernames.include?(valid_name) || !Person.is_available?(valid_name, environment)
  27 + end while tries <= 10 && invalid
  28 + usernames << valid_name unless invalid
  29 + end
  30 + usernames
  31 + end
  32 +
15 33 end
... ...
app/helpers/application_helper.rb
  1 +# encoding: UTF-8
  2 +
1 3 require 'redcloth'
2 4  
3 5 # Methods added to this helper will be available to all templates in the
... ... @@ -175,7 +177,7 @@ module ApplicationHelper
175 177 # should be a current profile (i.e. while viewing some profile's pages, or the
176 178 # profile info, etc), because if there is no profile an exception is thrown.
177 179 def profile
178   - @controller.send(:profile)
  180 + controller.send(:profile)
179 181 end
180 182  
181 183 def category_color
... ... @@ -277,10 +279,9 @@ module ApplicationHelper
277 279 options[:class].nil? ?
278 280 options[:class]='button-bar' :
279 281 options[:class]+=' button-bar'
280   - concat(content_tag('div', capture(&block) + tag('br', :style => 'clear: left;'), options))
  282 + concat(content_tag('div', capture(&block).to_s + tag('br', :style => 'clear: left;'), options))
281 283 end
282 284  
283   - VIEW_EXTENSIONS = %w[.rhtml .html.erb]
284 285  
285 286 def partial_for_class_in_view_path(klass, view_path, prefix = nil, suffix = nil)
286 287 return nil if klass.nil?
... ... @@ -294,10 +295,8 @@ module ApplicationHelper
294 295 search_name = "_" + search_name
295 296 end
296 297  
297   - VIEW_EXTENSIONS.each do |ext|
298   - path = defined?(params) && params[:controller] ? File.join(view_path, params[:controller], search_name+ext) : File.join(view_path, search_name+ext)
299   - return name if File.exists?(File.join(path))
300   - end
  298 + path = defined?(params) && params[:controller] ? File.join(view_path, params[:controller], search_name + '.html.erb') : File.join(view_path, search_name + '.html.erb')
  299 + return name if File.exists?(File.join(path))
301 300  
302 301 partial_for_class_in_view_path(klass.superclass, view_path, prefix, suffix)
303 302 end
... ... @@ -305,7 +304,7 @@ module ApplicationHelper
305 304 def partial_for_class(klass, prefix=nil, suffix=nil)
306 305 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
307 306 name = klass.name.underscore
308   - @controller.view_paths.each do |view_path|
  307 + controller.view_paths.reverse_each do |view_path|
309 308 partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix)
310 309 return partial if partial
311 310 end
... ... @@ -317,15 +316,13 @@ module ApplicationHelper
317 316 raise ArgumentError, 'No profile actions view for this class.' if klass.nil?
318 317  
319 318 name = klass.name.underscore
320   - VIEW_EXTENSIONS.each do |ext|
321   - return "blocks/profile_info_actions/"+name+ext if File.exists?(File.join(RAILS_ROOT, 'app', 'views', 'blocks', 'profile_info_actions', name+ext))
322   - end
  319 + return "blocks/profile_info_actions/" + name + '.html.erb' if File.exists?(Rails.root.join('app', 'views', 'blocks', 'profile_info_actions', name + '.html.erb'))
323 320  
324 321 view_for_profile_actions(klass.superclass)
325 322 end
326 323  
327 324 def user
328   - @controller.send(:user)
  325 + controller.send(:user)
329 326 end
330 327  
331 328 # DEPRECATED. Do not use this.
... ... @@ -337,7 +334,7 @@ module ApplicationHelper
337 334 "\n" +
338 335 sources.flatten.map do |source|
339 336 filename = filename_for_stylesheet(source.to_s, themed_source)
340   - if File.exists?(File.join(RAILS_ROOT, 'public', filename))
  337 + if File.exists?(Rails.root.join('public', filename[1..-1]))
341 338 "@import url(#{filename});\n"
342 339 else
343 340 "/* Not included: url(#{filename}) */\n"
... ... @@ -378,10 +375,10 @@ module ApplicationHelper
378 375 # utility for developers: set the theme to 'random' in development mode and
379 376 # you will get a different theme every request. This is interesting for
380 377 # testing
381   - if ENV['RAILS_ENV'] == 'development' && environment.theme == 'random'
  378 + if Rails.env.development? && environment.theme == 'random'
382 379 @random_theme ||= Dir.glob('public/designs/themes/*').map { |f| File.basename(f) }.rand
383 380 @random_theme
384   - elsif ENV['RAILS_ENV'] == 'development' && respond_to?(:params) && params[:theme] && File.exists?(File.join(Rails.root, 'public/designs/themes', params[:theme]))
  381 + elsif Rails.env.development? && respond_to?(:params) && params[:theme] && File.exists?(Rails.root.join('public/designs/themes', params[:theme]))
385 382 params[:theme]
386 383 else
387 384 if profile && !profile.theme.nil?
... ... @@ -404,10 +401,10 @@ module ApplicationHelper
404 401 end
405 402  
406 403 def theme_view_file(template)
407   - ['.rhtml', '.html.erb'].each do |ext|
408   - file = (RAILS_ROOT + '/public' + theme_path + '/' + template + ext)
409   - return file if File.exists?(file)
410   - end
  404 + # Since we cannot control what people are doing in external themes, we
  405 + # will keep looking for the deprecated .rhtml extension here.
  406 + file = Rails.root.join('public', theme_path[1..-1], template + '.html.erb')
  407 + return file if File.exists?(file)
411 408 nil
412 409 end
413 410  
... ... @@ -423,7 +420,7 @@ module ApplicationHelper
423 420  
424 421 def theme_favicon
425 422 return '/designs/themes/' + current_theme + '/favicon.ico' if profile.nil? || profile.theme.nil?
426   - if File.exists?(File.join(RAILS_ROOT, 'public', theme_path, 'favicon.ico'))
  423 + if File.exists?(Rails.root.join('public', theme_path, 'favicon.ico'))
427 424 '/designs/themes/' + profile.theme + '/favicon.ico'
428 425 else
429 426 favicon = profile.articles.find_by_path('favicon.ico')
... ... @@ -452,7 +449,7 @@ module ApplicationHelper
452 449 end
453 450  
454 451 def is_testing_theme
455   - !@controller.session[:theme].nil?
  452 + !controller.session[:theme].nil?
456 453 end
457 454  
458 455 def theme_owner
... ... @@ -493,7 +490,7 @@ module ApplicationHelper
493 490 end
494 491  
495 492 def default_or_themed_icon(icon)
496   - if File.exists?(File.join(Rails.root, 'public', theme_path, icon))
  493 + if File.exists?(Rails.root.join('public', theme_path, icon))
497 494 theme_path + icon
498 495 else
499 496 icon
... ... @@ -514,24 +511,25 @@ module ApplicationHelper
514 511  
515 512 def profile_cat_icons( profile )
516 513 if profile.class == Enterprise
517   - icons = profile.product_categories.map{ |c| c.size > 1 ? c[1] : nil }.
518   - compact.uniq.map do |c|
519   - cat_name = c.gsub( /[-_\s,.;'"]+/, '_' )
520   - cat_icon = "/images/icons-cat/#{cat_name}.png"
521   - if ! File.exists? RAILS_ROOT.to_s() + '/public/' + cat_icon
522   - cat_icon = '/images/icons-cat/undefined.png'
523   - end
524   - content_tag('span',
525   - content_tag( 'span', c ),
526   - :title => c,
527   - :class => 'product-cat-icon cat_icon_' + cat_name,
528   - :style => "background-image:url(#{cat_icon})"
529   - )
530   - end.join("\n").html_safe
531   - content_tag('div',
532   - content_tag( 'span', _('Principal Product Categories'), :class => 'header' ) +"\n"+ icons,
533   - :class => 'product-category-icons'
  514 + icons = profile.product_categories.unique_by_level(2).limit(3).map do |c|
  515 + filtered_category = c.filtered_category.blank? ? c.path.split('/').last : c.filtered_category
  516 + category_title = filtered_category.split(/[-_\s,.;'"]+/).map(&:capitalize).join(' ')
  517 + category_name = category_title.gsub(' ', '_' )
  518 + category_icon = "/images/icons-cat/#{category_name}.png"
  519 + if ! File.exists?(Rails.root.join('public', category_icon))
  520 + category_icon = '/images/icons-cat/undefined.png'
  521 + end
  522 + content_tag('span',
  523 + content_tag( 'span', category_title ),
  524 + :title => category_title,
  525 + :class => 'product-cat-icon cat_icon_' + category_name,
  526 + :style => "background-image:url(#{category_icon})"
534 527 )
  528 + end.join("\n").html_safe
  529 + content_tag('div',
  530 + content_tag( 'span', _('Principal Product Categories'), :class => 'header' ) +"\n"+ icons,
  531 + :class => 'product-category-icons'
  532 + )
535 533 else
536 534 ''
537 535 end
... ... @@ -573,7 +571,7 @@ module ApplicationHelper
573 571 # #profile_image) and its name below it.
574 572 def profile_image_link( profile, size=:portrait, tag='li', extra_info = nil )
575 573 if content = @plugins.dispatch_first(:profile_image_link, profile, size, tag, extra_info)
576   - return instance_eval(&content)
  574 + return instance_exec(&content)
577 575 end
578 576 name = profile.short_name
579 577 if profile.person?
... ... @@ -591,7 +589,7 @@ module ApplicationHelper
591 589 extra_info = extra_info.nil? ? '' : content_tag( 'span', extra_info, :class => 'extra_info' )
592 590 links = links_for_balloon(profile)
593 591 content_tag('div', content_tag(tag,
594   - (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{links.to_json}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") +
  592 + (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? link_to( content_tag( 'span', _('Profile links')), '#', :onclick => "toggleSubmenu(this, '#{profile.short_name}', #{CGI::escapeHTML(links.to_json)}); return false", :class => "menu-submenu-trigger #{trigger_class}", :url => url) : "") +
595 593 link_to(
596 594 content_tag( 'span', profile_image( profile, size ), :class => 'profile-image' ) +
597 595 content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) +
... ... @@ -608,53 +606,22 @@ module ApplicationHelper
608 606 end
609 607  
610 608 attr_reader :environment
  609 +
611 610 def select_categories(object_name, title=nil, title_size=4)
612 611 return nil if environment.enabled?(:disable_categories)
613 612 if title.nil?
614 613 title = _('Categories')
615 614 end
616 615  
617   - object = instance_variable_get("@#{object_name}")
618   -
619   - result = content_tag 'h'+title_size.to_s(), title
620   - result << javascript_tag( 'function open_close_cat( link ) {
621   - var div = link.parentNode.getElementsByTagName("div")[0];
622   - var end = function(){
623   - if ( div.style.display == "none" ) {
624   - this.link.className="button icon-button icon-down"
625   - } else {
626   - this.link.className="button icon-button icon-up-red"
627   - }
628   - }
629   - Effect.toggle( div, "slide", { link:link, div:div, afterFinish:end } )
630   - }')
631   - environment.top_level_categories.select{|i| !i.children.empty?}.each do |toplevel|
632   - next unless object.accept_category?(toplevel)
633   - # FIXME
634   - ([toplevel] + toplevel.children_for_menu).each do |cat|
635   - if cat.top_level?
636   - result << '<div class="categorie_box">'.html_safe
637   - result << icon_button( :down, _('open'), '#', :onclick => 'open_close_cat(this); return false' )
638   - result << content_tag('h5', toplevel.name)
639   - result << '<div style="display:none"><ul class="categories">'.html_safe
640   - else
641   - checkbox_id = "#{object_name}_#{cat.full_name.downcase.gsub(/\s+|\//, '_')}"
642   - result << content_tag('li', labelled_check_box(
643   - cat.full_name_without_leading(1, " &rarr; "),
644   - "#{object_name}[category_ids][]", cat.id,
645   - object.category_ids.include?(cat.id), :id => checkbox_id,
646   - :onchange => 'this.parentNode.className=(this.checked?"cat_checked":"")' ),
647   - :class => ( object.category_ids.include?(cat.id) ? 'cat_checked' : '' ) ) + "\n"
648   - end
649   - end
650   - result << '</ul></div></div>'.html_safe
651   - end
  616 + @object = instance_variable_get("@#{object_name}")
  617 + @categories = environment.top_level_categories
652 618  
653   - content_tag('div', result)
  619 + @current_categories = environment.top_level_categories.select{|i| !i.children.empty?}
  620 + render :partial => 'shared/select_categories_top', :locals => {:object_name => object_name, :title => title, :title_size => title_size, :multiple => true, :categories_selected => @object.categories }, :layout => false
654 621 end
655 622  
656 623 def theme_option(opt = nil)
657   - conf = RAILS_ROOT.to_s() +
  624 + conf = Rails.root.to_s() +
658 625 '/public' + theme_path +
659 626 '/theme.yml'
660 627 if File.exists?(conf)
... ... @@ -681,7 +648,7 @@ module ApplicationHelper
681 648 lightbox_link_to '<span class="icon-menu-search"></span>'+ _('Search'), {
682 649 :controller => 'search',
683 650 :action => 'popup',
684   - :category_path => (@category ? @category.explode_path : []) },
  651 + :category_path => (@category ? @category.explode_path : nil)},
685 652 :id => 'open_search'
686 653 end
687 654 end
... ... @@ -693,7 +660,7 @@ module ApplicationHelper
693 660 option.each do |file|
694 661 file = theme_path +
695 662 '/javascript/'+ file +'.js'
696   - if File.exists? RAILS_ROOT.to_s() +'/public'+ file
  663 + if File.exists? Rails.root.to_s() +'/public'+ file
697 664 html << javascript_src_tag( file, {} )
698 665 else
699 666 html << '<!-- Not included: '+ file +' -->'
... ... @@ -704,7 +671,7 @@ module ApplicationHelper
704 671  
705 672 def theme_javascript_ng
706 673 script = File.join(theme_path, 'theme.js')
707   - if File.exists?(File.join(Rails.root, 'public', script))
  674 + if File.exists?(Rails.root.join('public', script))
708 675 javascript_include_tag script
709 676 else
710 677 nil
... ... @@ -767,6 +734,10 @@ module ApplicationHelper
767 734 (field_helpers - %w(hidden_field)).each do |selector|
768 735 src = <<-END_SRC
769 736 def #{selector}(field, *args, &proc)
  737 + begin
  738 + object ||= @template.instance_variable_get("@"+object_name.to_s)
  739 + rescue
  740 + end
770 741 text = object.class.respond_to?(:human_attribute_name) && object.class.human_attribute_name(field.to_s) || field.to_s.humanize
771 742 NoosferoFormBuilder::output_field(text, super)
772 743 end
... ... @@ -798,7 +769,7 @@ module ApplicationHelper
798 769 end
799 770 }
800 771 html += "<br />\n".html_safe if line_size == 0 || ( values.size % line_size ) > 0
801   - column = object.class.columns_hash[method.to_s]
  772 + column = object.class.columns_hash[method.to_s] if object
802 773 text =
803 774 ( column ?
804 775 column.human_name :
... ... @@ -834,9 +805,8 @@ module ApplicationHelper
834 805 fields_for(name, object, { :builder => NoosferoFormBuilder }.merge(options), &proc)
835 806 end
836 807  
837   - def labelled_form_for(name, object = nil, options = {}, &proc)
838   - object ||= instance_variable_get("@#{name}")
839   - form_for(name, object, { :builder => NoosferoFormBuilder }.merge(options), &proc)
  808 + def labelled_form_for(name, options = {}, &proc)
  809 + form_for(name, { :builder => NoosferoFormBuilder }.merge(options), &proc)
840 810 end
841 811  
842 812 def optional_field(profile, name, field_html = nil, only_required = false, &block)
... ... @@ -893,6 +863,7 @@ module ApplicationHelper
893 863 article_helper = ActionView::Base.new
894 864 article_helper.controller = controller
895 865 article_helper.extend ArticleHelper
  866 + article_helper.extend Rails.application.routes.url_helpers
896 867 begin
897 868 class_name = article.class.name + 'Helper'
898 869 klass = class_name.constantize
... ... @@ -918,20 +889,31 @@ module ApplicationHelper
918 889 end
919 890 end
920 891  
  892 + def icon_theme_stylesheet_path
  893 + icon_themes = []
  894 + theme_icon_themes = theme_option(:icon_theme) || []
  895 + for icon_theme in theme_icon_themes do
  896 + theme_path = "/designs/icons/#{icon_theme}/style.css"
  897 + if File.exists?(Rails.root.join('public', theme_path[1..-1]))
  898 + icon_themes << theme_path
  899 + end
  900 + end
  901 + icon_themes
  902 + end
  903 +
921 904 def page_title
922 905 (@page ? @page.title + ' - ' : '') +
923   - (profile ? profile.short_name + ' - ' : '') +
924 906 (@topic ? @topic.title + ' - ' : '') +
925 907 (@section ? @section.title + ' - ' : '') +
926 908 (@toc ? _('Online Manual') + ' - ' : '') +
927   - (@controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') +
928   - environment.name +
  909 + (controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') +
  910 + (profile ? profile.short_name : environment.name) +
929 911 (@category ? " - #{@category.full_name}" : '')
930 912 end
931 913  
932 914 # DEPRECATED. Do not use this.
933 915 def import_controller_stylesheets(options = {})
934   - stylesheet_import( "controller_"+ @controller.controller_name(), options )
  916 + stylesheet_import( "controller_"+ controller.controller_name(), options )
935 917 end
936 918  
937 919 def link_to_email(email)
... ... @@ -945,7 +927,7 @@ module ApplicationHelper
945 927 def article_to_html(article, options = {})
946 928 options.merge!(:page => params[:npage])
947 929 content = article.to_html(options)
948   - content = content.kind_of?(Proc) ? self.instance_eval(&content).html_safe : content.html_safe
  930 + content = content.kind_of?(Proc) ? self.instance_exec(&content).html_safe : content.html_safe
949 931 filter_html(content, article)
950 932 end
951 933  
... ... @@ -979,14 +961,6 @@ module ApplicationHelper
979 961 html
980 962 end
981 963  
982   - def colorpicker_field(object_name, method, options = {})
983   - text_field(object_name, method, options.merge(:class => 'colorpicker_field'))
984   - end
985   -
986   - def colorpicker_field_tag(name, value = nil, options = {})
987   - text_field_tag(name, value, options.merge(:class => 'colorpicker_field'))
988   - end
989   -
990 964 def ui_icon(icon_class, extra_class = '')
991 965 "<span class='ui-icon #{icon_class} #{extra_class}' style='float:left; margin-right:7px;'></span>".html_safe
992 966 end
... ... @@ -1000,7 +974,7 @@ module ApplicationHelper
1000 974 end
1001 975  
1002 976 def jquery_theme
1003   - theme_option(:jquery_theme) || 'smoothness_mod'
  977 + theme_option(:jquery_theme) || 'smoothness'
1004 978 end
1005 979  
1006 980 def ui_error(message)
... ... @@ -1059,8 +1033,8 @@ module ApplicationHelper
1059 1033 links.push(_('New content') => colorbox_options({:href => url_for({:controller => 'cms', :action => 'new', :profile => current_user.login, :cms => true})}))
1060 1034 end
1061 1035  
1062   - link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => ''}, :id => 'submenu-contents') +
1063   - link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
  1036 + link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') +
  1037 + link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
1064 1038 end
1065 1039 alias :browse_contents_menu :search_contents_menu
1066 1040  
... ... @@ -1076,7 +1050,7 @@ module ApplicationHelper
1076 1050 end
1077 1051  
1078 1052 link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') +
1079   - link_to(content_tag(:span, _('People menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger')
  1053 + link_to(content_tag(:span, _('People menu')), '#', :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger')
1080 1054 end
1081 1055 alias :browse_people_menu :search_people_menu
1082 1056  
... ... @@ -1092,7 +1066,7 @@ module ApplicationHelper
1092 1066 end
1093 1067  
1094 1068 link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') +
1095   - link_to(content_tag(:span, _('Communities menu')), '#', :onclick => "toggleSubmenu(this,'',#{links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
  1069 + link_to(content_tag(:span, _('Communities menu')), '#', :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
1096 1070 end
1097 1071 alias :browse_communities_menu :search_communities_menu
1098 1072  
... ... @@ -1104,7 +1078,7 @@ module ApplicationHelper
1104 1078 def render_environment_features(folder)
1105 1079 result = ''
1106 1080 environment.enabled_features.keys.each do |feature|
1107   - file = File.join(@controller.view_paths.last, 'shared', folder.to_s, "#{feature}.rhtml")
  1081 + file = Rails.root.join('app/views/shared', folder.to_s, "#{feature}.html.erb")
1108 1082 if File.exists?(file)
1109 1083 result << render(:file => file, :use_full_path => false)
1110 1084 end
... ... @@ -1117,10 +1091,10 @@ module ApplicationHelper
1117 1091 link_to_all = nil
1118 1092 if list.count > 5
1119 1093 list = list.first(5)
1120   - link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => current_user.login)
  1094 + link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => user.identifier)
1121 1095 end
1122 1096 link = list.map do |element|
1123   - link_to(content_tag('strong', [_('<span>Manage</span> %s') % element.short_name(25)]), @environment.top_url + "/myprofile/#{element.identifier}", :class => "icon-menu-"+element.class.identification.underscore, :title => [_('Manage %s') % element.short_name])
  1097 + link_to(content_tag('strong', _('<span>Manage</span> %s') % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s') % element.short_name)
1124 1098 end
1125 1099 if link_to_all
1126 1100 link << link_to_all
... ... @@ -1144,15 +1118,15 @@ module ApplicationHelper
1144 1118 pending_tasks_count = ''
1145 1119 count = user ? Task.to(user).pending.count : -1
1146 1120 if count > 0
1147   - pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
  1121 + pending_tasks_count = link_to(count.to_s, user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1148 1122 end
1149 1123  
1150   - (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i style="background-image:url({avatar})"></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) +
  1124 + (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage'))) +
1151 1125 render_environment_features(:usermenu) +
1152   - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +
  1126 + link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') +
1153 1127 manage_enterprises.to_s +
1154 1128 manage_communities.to_s +
1155   - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :class => 'ctrl-panel', :title => _("Configure your personal account and content")) +
  1129 + link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content")) +
1156 1130 pending_tasks_count +
1157 1131 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
1158 1132 end
... ... @@ -1162,7 +1136,7 @@ module ApplicationHelper
1162 1136 text_area(object_name, method, { :id => text_area_id, :onkeyup => "limited_text_area('#{text_area_id}', #{limit})" }.merge(options)),
1163 1137 content_tag(:p, content_tag(:span, limit) + ' ' + _(' characters left'), :id => text_area_id + '_left'),
1164 1138 content_tag(:p, _('Limit of characters reached'), :id => text_area_id + '_limit', :style => 'display: none')
1165   - ], :class => 'limited-text-area')
  1139 + ].join, :class => 'limited-text-area')
1166 1140 end
1167 1141  
1168 1142 def expandable_text_area(object_name, method, text_area_id, options = {})
... ... @@ -1180,6 +1154,7 @@ module ApplicationHelper
1180 1154 #FIXME Use time_ago_in_words instead of this method if you're using Rails 2.2+
1181 1155 def time_ago_as_sentence(from_time, include_seconds = false)
1182 1156 to_time = Time.now
  1157 + from_time = Time.parse(from_time.to_s)
1183 1158 from_time = from_time.to_time if from_time.respond_to?(:to_time)
1184 1159 to_time = to_time.to_time if to_time.respond_to?(:to_time)
1185 1160 distance_in_minutes = (((to_time - from_time).abs)/60).round
... ... @@ -1360,6 +1335,25 @@ module ApplicationHelper
1360 1335 expirable_content_reference content, action, text, url, options
1361 1336 end
1362 1337  
  1338 + def error_messages_for(*args)
  1339 + options = args.pop if args.last.is_a?(Hash)
  1340 + errors = []
  1341 + args.each do |name|
  1342 + object = instance_variable_get("@#{name}")
  1343 + object.errors.full_messages.each do |msg|
  1344 + errors << msg
  1345 + end if object
  1346 + end
  1347 + return '' if errors.empty?
  1348 +
  1349 + content_tag(:div, :class => 'errorExplanation', :id => 'errorExplanation') do
  1350 + content_tag(:h2, _('Errors while saving')) +
  1351 + content_tag(:ul) do
  1352 + errors.map { |err| content_tag(:li, err) }.join
  1353 + end
  1354 + end
  1355 + end
  1356 +
1363 1357 def private_profile_partial_parameters
1364 1358 if profile.person?
1365 1359 @action = :add_friend
... ... @@ -1389,7 +1383,7 @@ module ApplicationHelper
1389 1383 doc.search('.macro').each do |macro|
1390 1384 macro_name = macro['data-macro']
1391 1385 result = @plugins.parse_macro(macro_name, macro, source)
1392   - macro.inner_html = result.kind_of?(Proc) ? self.instance_eval(&result) : result
  1386 + macro.inner_html = result.kind_of?(Proc) ? self.instance_exec(&result) : result
1393 1387 end
1394 1388 doc.html
1395 1389 end
... ...
app/helpers/article_helper.rb
1 1 module ArticleHelper
2 2  
  3 + include PrototypeHelper
3 4 include TokenHelper
4 5  
5 6 def custom_options_for_article(article, tokenized_children)
... ... @@ -49,8 +50,14 @@ module ArticleHelper
49 50 'div',
50 51 check_box(:article, :display_versions) +
51 52 content_tag('label', _('I want this article to display a link to older versions'), :for => 'article_display_versions')
52   - ) : '')
  53 + ) : '') +
53 54  
  55 + (article.forum? && article.profile.community? ?
  56 + content_tag(
  57 + 'div',
  58 + check_box(:article, :allows_members_to_create_topics) +
  59 + content_tag('label', _('Allow members to create topics'), :for => 'article_allows_members_to_create_topics')
  60 + ) : '')
54 61 )
55 62 end
56 63  
... ...
app/helpers/assets_helper.rb
... ... @@ -7,9 +7,9 @@ module AssetsHelper
7 7 [ options.merge(:asset => 'articles'), "icon-menu-articles", _('Articles') ],
8 8 [ options.merge(:asset => 'people'), "icon-menu-people", _('People') ],
9 9 [ options.merge(:asset => 'products'), "icon-menu-product", _('Products') ],
10   - [ options.merge(:asset => 'enterprises'), "icon-menu-enterprise", __('Enterprises') ],
11   - [ options.merge(:asset => 'communities'), "icon-menu-community", __('Communities') ],
12   - [ options.merge(:asset => 'events'), "icon-event", __('Events') ],
  10 + [ options.merge(:asset => 'enterprises'), "icon-menu-enterprise", _('Enterprises') ],
  11 + [ options.merge(:asset => 'communities'), "icon-menu-community", _('Communities') ],
  12 + [ options.merge(:asset => 'events'), "icon-event", _('Events') ],
13 13  
14 14 ].select do |target, css_class, name|
15 15 !environment.enabled?('disable_asset_' + target[:asset])
... ...
app/helpers/boxes_helper.rb
1 1 module BoxesHelper
2 2  
3 3 def insert_boxes(content)
4   - if @controller.send(:boxes_editor?) && @controller.send(:uses_design_blocks?)
5   - content + display_boxes_editor(@controller.boxes_holder)
  4 + if controller.send(:boxes_editor?) && controller.send(:uses_design_blocks?)
  5 + content + display_boxes_editor(controller.boxes_holder)
6 6 else
7   - maybe_display_custom_element(@controller.boxes_holder, :custom_header_expanded, :id => 'profile-header') +
8   - if @controller.send(:uses_design_blocks?)
9   - display_boxes(@controller.boxes_holder, content)
  7 + maybe_display_custom_element(controller.boxes_holder, :custom_header_expanded, :id => 'profile-header') +
  8 + if controller.send(:uses_design_blocks?)
  9 + display_boxes(controller.boxes_holder, content)
10 10 else
11 11 content_tag('div',
12 12 content_tag('div',
... ... @@ -16,7 +16,7 @@ module BoxesHelper
16 16 :class => 'no-boxes'
17 17 )
18 18 end +
19   - maybe_display_custom_element(@controller.boxes_holder, :custom_footer_expanded, :id => 'profile-footer')
  19 + maybe_display_custom_element(controller.boxes_holder, :custom_footer_expanded, :id => 'profile-footer')
20 20 end
21 21 end
22 22  
... ... @@ -65,7 +65,7 @@ module BoxesHelper
65 65 end
66 66  
67 67 def display_box_content(box, main_content)
68   - context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params }
  68 + context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params, :user => user }
69 69 box_decorator.select_blocks(box.blocks.includes(:box), context).map { |item| display_block(item, main_content) }.join("\n") + box_decorator.block_target(box)
70 70 end
71 71  
... ... @@ -212,18 +212,29 @@ module BoxesHelper
212 212  
213 213 if !block.main?
214 214 buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})
215   - buttons << icon_button(:clone, _('Clone'), { :action => 'clone', :id => block.id }, { :method => 'post' })
  215 + buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })
216 216 end
217 217  
218 218 if block.respond_to?(:help)
219 219 buttons << thickbox_inline_popup_icon(:help, _('Help on this block'), {}, "help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + thickbox_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}")
220 220 end
221 221  
  222 + if block.embedable?
  223 + embed_code = block.embed_code
  224 + embed_code = instance_exec(&embed_code) if embed_code.respond_to?(:call)
  225 + html = content_tag('div',
  226 + content_tag('h2', _('Embed block code')) +
  227 + content_tag('div', _('Below, you''ll see a field containing embed code for the block. Just copy the code and paste it into your website or blogging software.'), :style => 'margin-bottom: 1em;') +
  228 + content_tag('textarea', embed_code, :style => 'margin-bottom: 1em; width:100%; height:40%;', :readonly => 'readonly') +
  229 + thickbox_close_button(_('Close')), :style => 'display: none;', :id => "embed-code-box-#{block.id}")
  230 + buttons << thickbox_inline_popup_icon(:embed, _('Embed code'), {}, "embed-code-box-#{block.id}") << html
  231 + end
  232 +
222 233 content_tag('div', buttons.join("\n") + tag('br', :style => 'clear: left'), :class => 'button-bar')
223 234 end
224 235  
225 236 def current_blocks
226   - @controller.boxes_holder.boxes.map(&:blocks).inject([]){|ac, a| ac + a}
  237 + controller.boxes_holder.boxes.map(&:blocks).inject([]){|ac, a| ac + a}
227 238 end
228 239  
229 240 # DEPRECATED. Do not use this.
... ...
app/helpers/cache_counter_helper.rb 0 → 100644
... ... @@ -0,0 +1,7 @@
  1 +module CacheCounterHelper
  2 + def update_cache_counter(name, object, value)
  3 + if object.present?
  4 + object.class.update_counters(object.id, name => value)
  5 + end
  6 + end
  7 +end
... ...
app/helpers/catalog_helper.rb
... ... @@ -9,11 +9,9 @@ module CatalogHelper
9 9 @categories = ProductCategory.on_level(params[:level]).order(:name)
10 10 end
11 11  
12   - @products = profile.products.from_category(@category).paginate(
13   - :order => 'available desc, highlighted desc, name asc',
14   - :per_page => @profile.products_per_catalog_page,
15   - :page => options[:page]
16   - )
  12 + @products = profile.products.from_category(@category).
  13 + reorder('available desc, highlighted desc, name asc').
  14 + paginate(:per_page => @profile.products_per_catalog_page, :page => options[:page])
17 15 end
18 16  
19 17 def breadcrumb(category)
... ... @@ -41,7 +39,7 @@ module CatalogHelper
41 39 cat_link = category_link sub_category
42 40 sub_categories << content_tag('li', cat_link) unless cat_link.nil?
43 41 end
44   - content_tag('ul', sub_categories) if sub_categories.size > 0
  42 + content_tag('ul', sub_categories.join) if sub_categories.size > 0
45 43 end
46 44  
47 45 end
... ...
app/helpers/categories_helper.rb
... ... @@ -48,4 +48,19 @@ module CategoriesHelper
48 48 labelled_form_field(_('Type of category'), select_tag('type', options_for_select(TYPES, value)))
49 49 end
50 50  
  51 + #FIXME make this test
  52 + def selected_category_link(cat)
  53 + js_remove = "jQuery('#selected-category-#{cat.id}').remove();"
  54 + content_tag('div', button_to_function_without_text(:remove, _('Remove'), js_remove) +
  55 + link_to_function(cat.full_name(' &rarr; '), js_remove, :id => "remove-selected-category-#{cat.id}-button", :class => 'select-subcategory-link'),
  56 + :class => 'selected-category'
  57 + )
  58 + end
  59 +
  60 + def update_categories_link(body, category_id=nil, html_options={})
  61 + link_to body,
  62 + { :action => "update_categories", :category_id => category_id, :id => @object },
  63 + {:id => category_id ? "select-category-#{category_id}-link" : nil, :remote => true, :class => 'select-subcategory-link'}.merge(html_options)
  64 + end
  65 +
51 66 end
... ...
app/helpers/cms_helper.rb
... ... @@ -11,7 +11,7 @@ module CmsHelper
11 11  
12 12 def add_upload_file_field(name, locals)
13 13 button_to_function :add, name, nil do |page|
14   - page.insert_html :bottom, :uploaded_files, :partial => 'upload_file', :locals => locals, :object => UploadedFile.new
  14 + page.insert_html :bottom, :uploaded_files, CGI::escapeHTML(render(:partial => 'upload_file', :locals => locals, :object => UploadedFile.new))
15 15 end
16 16 end
17 17  
... ...
app/helpers/comment_helper.rb
... ... @@ -2,7 +2,6 @@ module CommentHelper
2 2  
3 3 def article_title(article, args = {})
4 4 title = article.title
5   - title = article.display_title if article.kind_of?(UploadedFile) && article.image?
6 5 title = content_tag('h1', h(title), :class => 'title')
7 6 if article.belongs_to_blog?
8 7 unless args[:no_link]
... ... @@ -22,6 +21,12 @@ module CommentHelper
22 21 title
23 22 end
24 23  
  24 + def comment_extra_contents(comment)
  25 + @plugins.dispatch(:comment_extra_contents, comment).collect do |extra_content|
  26 + extra_content.kind_of?(Proc) ? self.instance_exec(&extra_content) : extra_content
  27 + end.join('\n')
  28 + end
  29 +
25 30 def comment_actions(comment)
26 31 url = url_for(:profile => profile.identifier, :controller => :comment, :action => :check_actions, :id => comment.id)
27 32 links = links_for_comment_actions(comment)
... ... @@ -36,7 +41,7 @@ module CommentHelper
36 41 def links_for_comment_actions(comment)
37 42 actions = [link_for_report_abuse(comment), link_for_spam(comment), link_for_edit(comment), link_for_remove(comment)]
38 43 @plugins.dispatch(:comment_actions, comment).collect do |action|
39   - actions << (action.kind_of?(Proc) ? self.instance_eval(&action) : action)
  44 + actions << (action.kind_of?(Proc) ? self.instance_exec(&action) : action)
40 45 end
41 46 actions.flatten.compact
42 47 end
... ... @@ -51,9 +56,9 @@ module CommentHelper
51 56 def link_for_spam(comment)
52 57 if comment.can_be_marked_as_spam_by?(user)
53 58 if comment.spam?
54   - {:link => link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, %s); return false;' % url_for(:profile => profile.identifier, :mark_comment_as_ham => comment.id).to_json, :class => 'comment-footer comment-footer-link comment-footer-hide')}
  59 + {:link => link_to_function(_('Mark as NOT SPAM'), 'remove_comment(this, \'%s\'); return false;' % url_for(:profile => profile.identifier, :mark_comment_as_ham => comment.id), :class => 'comment-footer comment-footer-link comment-footer-hide')}
55 60 else
56   - {:link => link_to_function(_('Mark as SPAM'), 'remove_comment(this, %s, %s); return false;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :mark_as_spam, :id => comment.id).to_json, _('Are you sure you want to mark this comment as SPAM?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide')}
  61 + {:link => link_to_function(_('Mark as SPAM'), 'remove_comment(this, \'%s\', \'%s\'); return false;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :mark_as_spam, :id => comment.id), _('Are you sure you want to mark this comment as SPAM?')], :class => 'comment-footer comment-footer-link comment-footer-hide')}
57 62 end
58 63 end
59 64 end
... ... @@ -66,7 +71,7 @@ module CommentHelper
66 71  
67 72 def link_for_remove(comment)
68 73 if comment.can_be_destroyed_by?(user)
69   - {:link => link_to_function(_('Remove'), 'remove_comment(this, %s, %s); return false ;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :destroy, :id => comment.id).to_json, _('Are you sure you want to remove this comment and all its replies?').to_json], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children')}
  74 + {:link => link_to_function(_('Remove'), 'remove_comment(this, \'%s\', \'%s\'); return false ;' % [url_for(:profile => profile.identifier, :controller => 'comment', :action => :destroy, :id => comment.id), _('Are you sure you want to remove this comment and all its replies?')], :class => 'comment-footer comment-footer-link comment-footer-hide remove-children')}
70 75 end
71 76 end
72 77  
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -14,8 +14,7 @@ module ContentViewerHelper
14 14 end
15 15  
16 16 def article_title(article, args = {})
17   - title = article.display_title if article.kind_of?(UploadedFile) && article.image?
18   - title = article.title if title.blank?
  17 + title = article.title
19 18 title = content_tag('h1', h(title), :class => 'title')
20 19 if article.belongs_to_blog? || article.belongs_to_forum?
21 20 unless args[:no_link]
... ... @@ -27,7 +26,7 @@ module ContentViewerHelper
27 26 end
28 27 title << content_tag('span',
29 28 content_tag('span', show_date(article.published_at), :class => 'date') +
30   - content_tag('span', [_(", by %s") % link_to(article.author_name, article.author_url)], :class => 'author') +
  29 + content_tag('span', _(", by %s") % link_to(article.author_name, article.author_url), :class => 'author') +
31 30 content_tag('span', comments, :class => 'comments'),
32 31 :class => 'created-at'
33 32 )
... ... @@ -52,17 +51,8 @@ module ContentViewerHelper
52 51 end
53 52 end
54 53  
55   - def addthis_facebook_url(article)
56   - "http://www.facebook.com/sharer.php?s=100&p[title]=%{title}&p[summary]=%{summary}&p[url]=%{url}&p[images][0]=%{image}" % {
57   - :title => CGI.escape(article.title),
58   - :url => CGI.escape(url_for(article.url)),
59   - :summary => CGI.escape(truncate(strip_tags(article.body.to_s), :length => 300)),
60   - :image => CGI.escape(article.body_images_paths.first.to_s)
61   - }
62   - end
63   -
64 54 def addthis_image_tag
65   - if File.exists?(File.join(Rails.root, 'public', theme_path, 'images', 'addthis.gif'))
  55 + if File.exists?(Rails.root.join('public', theme_path, 'images', 'addthis.gif'))
66 56 image_tag(File.join(theme_path, 'images', 'addthis.gif'), :border => 0, :alt => '')
67 57 else
68 58 image_tag("/images/bt-bookmark.gif", :width => 53, :height => 16, :border => 0, :alt => '')
... ...
app/helpers/countries_helper.rb
1   -class CountriesHelper
  1 +# encoding: UTF-8
2 2  
3   - include Singleton
  3 +module CountriesHelper
  4 +
  5 + class Object
  6 + include ::CountriesHelper
  7 + include Singleton
  8 + end
4 9  
5 10 # a dump of iso_3166.xml from Debian source package iso-codes
6 11 COUNTRIES = [
... ... @@ -262,7 +267,7 @@ class CountriesHelper
262 267 end
263 268  
264 269 def countries
265   - self.class.countries.map {|item| [gettext(item[0]), item[1] ]}.sort_by { |entry| entry.first.transliterate }
  270 + CountriesHelper.countries.map {|item| [gettext(item[0]), item[1] ]}.sort_by { |entry| entry.first.transliterate }
266 271 end
267 272  
268 273 def lookup(code)
... ...
app/helpers/folder_helper.rb
  1 +require 'short_filename'
  2 +
1 3 module FolderHelper
2 4  
3 5 include ShortFilename
... ...
app/helpers/forms_helper.rb
1 1 module FormsHelper
2   -
3   - def generate_form( name, obj, fields={} )
4   - labelled_form_for name, obj do |f|
5   - f.text_field(:name)
6   - end
7   - end
8   -
9 2 def labelled_radio_button( human_name, name, value, checked = false, options = {} )
10 3 options[:id] ||= 'radio-' + FormsHelper.next_id_number
11 4 radio_button_tag( name, value, checked, options ) +
... ... @@ -41,6 +34,7 @@ module FormsHelper
41 34 the_class << ' ' << html_options[:class]
42 35 end
43 36  
  37 + html_options.delete(:cancel)
44 38 bt_submit = submit_tag(label, html_options.merge(:class => the_class))
45 39  
46 40 bt_submit + bt_cancel
... ...
app/helpers/forum_helper.rb
... ... @@ -36,7 +36,7 @@ module ForumHelper
36 36 :id => "post-#{art.id}"
37 37 )
38 38 }
39   - content_tag('table', content) + (pagination or '')
  39 + content_tag('table', content.join) + (pagination or '')
40 40 end
41 41  
42 42 def last_topic_update(article)
... ...
app/helpers/language_helper.rb
... ... @@ -22,7 +22,7 @@ module LanguageHelper
22 22 if options[:element] == 'dropdown'
23 23 select_tag('lang',
24 24 options_for_select(locales.map{|code,name| [name, code]}, current),
25   - :onchange => "document.location.href= #{url_for(params.merge(:lang => 'LANGUAGE')).inspect}.replace(/LANGUAGE/, this.value) ;",
  25 + :onchange => "document.location.href= #{url_for(params.merge(:lang => 'LANGUAGE'))}.replace(/LANGUAGE/, this.value) ;",
26 26 :help => _('The language you choose here is the language used for options, buttons, etc. It does not affect the language of the content created by other users.')
27 27 )
28 28 else
... ...
app/helpers/layout_helper.rb
... ... @@ -2,14 +2,14 @@ module LayoutHelper
2 2  
3 3 def body_classes
4 4 # Identify the current controller and action for the CSS:
5   - " controller-#{@controller.controller_name}" +
6   - " action-#{@controller.controller_name}-#{@controller.action_name}" +
7   - " template-#{profile.nil? ? "default" : profile.layout_template}" +
  5 + " controller-#{controller.controller_name}" +
  6 + " action-#{controller.controller_name}-#{controller.action_name}" +
  7 + " template-#{@layout_template || if profile.blank? then 'default' else profile.layout_template end}" +
8 8 (!profile.nil? && profile.is_on_homepage?(request.path,@page) ? " profile-homepage" : "")
9 9 end
10 10  
11 11 def noosfero_javascript
12   - plugins_javascripts = @plugins.map { |plugin| plugin.js_files.map { |js| plugin.class.public_path(js) } }.flatten
  12 + plugins_javascripts = @plugins.map { |plugin| [plugin.js_files].flatten.map { |js| plugin.class.public_path(js) } }.flatten
13 13  
14 14 output = ''
15 15 output += render :file => 'layouts/_javascript'
... ... @@ -26,14 +26,13 @@ module LayoutHelper
26 26 'search',
27 27 'thickbox',
28 28 'lightbox',
29   - 'colorpicker',
30 29 'colorbox',
31 30 pngfix_stylesheet_path,
32 31 ] + tokeninput_stylesheets
33 32 plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }
34 33  
35 34 output = ''
36   - output += stylesheet_link_tag standard_stylesheets, :cache => 'cache'
  35 + output += stylesheet_link_tag standard_stylesheets, :cache => 'cache/application'
37 36 output += stylesheet_link_tag template_stylesheet_path
38 37 output += stylesheet_link_tag icon_theme_stylesheet_path
39 38 output += stylesheet_link_tag jquery_ui_theme_stylesheet_path
... ... @@ -69,7 +68,7 @@ module LayoutHelper
69 68 theme_icon_themes = theme_option(:icon_theme) || []
70 69 for icon_theme in theme_icon_themes do
71 70 theme_path = "/designs/icons/#{icon_theme}/style.css"
72   - if File.exists?(File.join(RAILS_ROOT, 'public', theme_path))
  71 + if File.exists?(Rails.root.join('public', theme_path))
73 72 icon_themes << theme_path
74 73 end
75 74 end
... ... @@ -77,7 +76,7 @@ module LayoutHelper
77 76 end
78 77  
79 78 def jquery_ui_theme_stylesheet_path
80   - 'jquery.ui/' + jquery_theme + '/jquery-ui-1.8.2.custom'
  79 + "https://code.jquery.com/ui/1.10.4/themes/#{jquery_theme}/jquery-ui.css"
81 80 end
82 81  
83 82 def theme_stylesheet_path
... ... @@ -86,9 +85,12 @@ module LayoutHelper
86 85  
87 86 def addthis_javascript
88 87 if NOOSFERO_CONF['addthis_enabled']
89   - '<script src="http://s7.addthis.com/js/152/addthis_widget.js"></script>'
  88 + '<script src="https://s7.addthis.com/js/152/addthis_widget.js"></script>'
90 89 end
91 90 end
92 91  
  92 + def meta_description_tag(article=nil)
  93 + article ? truncate(strip_tags(article.body.to_s), :length => 200) : environment.name
  94 + end
93 95 end
94 96  
... ...
app/helpers/macros_helper.rb
... ... @@ -20,14 +20,16 @@ module MacrosHelper
20 20 jQuery('<div>'+#{macro_configuration_dialog(macro).to_json}+'</div>').dialog({
21 21 title: #{macro_title(macro).to_json},
22 22 modal: true,
23   - buttons: [
24   - {text: #{_('Ok').to_json}, click: function(){
  23 + buttons: {
  24 + #{_('Ok').to_json}: function(){
25 25 tinyMCE.activeEditor.execCommand('mceInsertContent', false,
26 26 (function(dialog){ #{macro_generator(macro)} })(this));
27 27 jQuery(this).dialog('close');
28   - }},
29   - {text: #{_('Cancel').to_json}, click: function(){jQuery(this).dialog('close');}}
30   - ]
  28 + },
  29 + #{_('Cancel').to_json}: function(){
  30 + jQuery(this).dialog('close');
  31 + }
  32 + }
31 33 });
32 34 }"
33 35 end
... ... @@ -37,7 +39,7 @@ module MacrosHelper
37 39 plugins_javascripts = []
38 40 @plugins.dispatch(:macros).map do |macro|
39 41 if macro.configuration[:js_files]
40   - macro.configuration[:js_files].map { |js| plugins_javascripts << macro.plugin.public_path(js) }
  42 + [macro.configuration[:js_files]].flatten.map { |js| plugins_javascripts << macro.plugin.public_path(js) }
41 43 end
42 44 end
43 45 javascript_include_tag(plugins_javascripts, :cache => 'cache/plugins-' + Digest::MD5.hexdigest(plugins_javascripts.to_s)) unless plugins_javascripts.empty?
... ... @@ -47,7 +49,7 @@ module MacrosHelper
47 49 plugins_css = []
48 50 @plugins.dispatch(:macros).map do |macro|
49 51 if macro.configuration[:css_files]
50   - macro.configuration[:css_files].map { |css| plugins_css << macro.plugin.public_path(css) }
  52 + [macro.configuration[:css_files]].flatten.map { |css| plugins_css << macro.plugin.public_path(css) }
51 53 end
52 54 end
53 55 plugins_css.join(',')
... ... @@ -57,7 +59,11 @@ module MacrosHelper
57 59  
58 60 def macro_generator(macro)
59 61 if macro.configuration[:generator]
60   - macro.configuration[:generator]
  62 + if macro.configuration[:generator].respond_to?(:call)
  63 + macro.configuration[:generator].call(macro)
  64 + else
  65 + macro.configuration[:generator]
  66 + end
61 67 else
62 68 macro_default_generator(macro)
63 69 end
... ... @@ -66,8 +72,7 @@ module MacrosHelper
66 72  
67 73 def macro_default_generator(macro)
68 74 code = "var params = {};"
69   - configuration = macro_configuration(macro)
70   - configuration[:params].map do |field|
  75 + macro.configuration[:params].map do |field|
71 76 code += "params.#{field[:name]} = jQuery('*[name=#{field[:name]}]', dialog).val();"
72 77 end
73 78 code + "
... ...
app/helpers/manage_products_helper.rb
  1 +# encoding: UTF-8
  2 +
1 3 module ManageProductsHelper
2 4  
3 5 def remote_function_to_update_categories_selection(container_id, options = {})
... ... @@ -26,27 +28,10 @@ module ManageProductsHelper
26 28 def hierarchy_category_navigation(current_category, options = {})
27 29 hierarchy = []
28 30 if current_category
29   - count_chars = 0
30   - unless options[:hide_current_category]
31   - hierarchy << current_category.name
32   - count_chars += current_category.name.length
33   - end
  31 + hierarchy << current_category.name unless options[:hide_current_category]
34 32 ancestors = current_category.ancestors
35   - toplevel = ancestors.pop
36   - if toplevel
37   - count_chars += toplevel.name.length
38   - end
39 33 ancestors.each do |category|
40   - if count_chars > 55
41   - hierarchy << hierarchy_category_item(category, options[:make_links], '( … )')
42   - break
43   - else
44   - hierarchy << hierarchy_category_item(category, options[:make_links])
45   - end
46   - count_chars += category.name.length
47   - end
48   - if toplevel
49   - hierarchy << hierarchy_category_item(toplevel, options[:make_links])
  34 + hierarchy << hierarchy_category_item(category, options[:make_links])
50 35 end
51 36 end
52 37 hierarchy.reverse.join(options[:separator] || ' &rarr; ')
... ... @@ -55,7 +40,7 @@ module ManageProductsHelper
55 40 def options_for_select_categories(categories, selected = nil)
56 41 categories.sort_by{|cat| cat.name.transliterate}.map do |category|
57 42 selected_attribute = selected.nil? ? '' : (category == selected ? "selected='selected'" : '')
58   - "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{truncate(category.name, :length => 33) + (category.leaf? ? '': ' &raquo;')}</option>"
  43 + "<option value='#{category.id}' title='#{category.name}' #{selected_attribute}>#{category.name + (category.leaf? ? '': ' &raquo;')}</option>"
59 44 end.join("\n")
60 45 end
61 46  
... ... @@ -161,7 +146,7 @@ module ManageProductsHelper
161 146 def cancel_edit_product_link(product, field, html_options = {})
162 147 return '' unless (user && user.has_permission?('manage_products', profile))
163 148 button_to_function(:cancel, _('Cancel'), nil, html_options) do |page|
164   - page.replace_html "product-#{field}", :partial => "display_#{field}", :locals => {:product => product}
  149 + page.replace_html "product-#{field}", CGI::escapeHTML(render :partial => "display_#{field}", :locals => {:product => product})
165 150 end
166 151 end
167 152  
... ...
app/helpers/maps_helper.rb 0 → 100644
... ... @@ -0,0 +1,14 @@
  1 +module MapsHelper
  2 + def self.search_city term, state=""
  3 + cities = if state.empty?
  4 + NationalRegion.search_city(term + "%", true)
  5 + else
  6 + NationalRegion.search_city(term + "%", true, state)
  7 + end
  8 + cities.map {|r|{ :label => r.city , :category => r.state}}
  9 + end
  10 +
  11 + def self.search_state term
  12 + NationalRegion.search_state(term + "%", true).map {|r|{ :label => r.state}}
  13 + end
  14 +end
... ...
app/helpers/person_notifier_helper.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +module PersonNotifierHelper
  2 +
  3 + include ApplicationHelper
  4 +
  5 + private
  6 +
  7 + def path_to_image(source)
  8 + top_url + source
  9 + end
  10 +
  11 + def top_url
  12 + top_url = @profile.environment ? @profile.environment.top_url : ''
  13 + end
  14 +
  15 +end
... ...
app/helpers/profile_editor_helper.rb
... ... @@ -101,7 +101,7 @@ module ProfileEditorHelper
101 101 end
102 102  
103 103 def country_helper
104   - @country_helper ||= CountriesHelper.instance
  104 + @country_helper ||= CountriesHelper::Object.instance
105 105 end
106 106  
107 107 def select_country(title, object, method, html_options = {}, options = {})
... ... @@ -129,7 +129,7 @@ module ProfileEditorHelper
129 129 else
130 130 domains = environment.domains
131 131 end
132   - labelled_form_field(__('Preferred domain name:'), select(object, :preferred_domain_id, domains.map {|item| [item.name, item.id]}, :prompt => '&lt;' + _('Select domain') + '&gt;'))
  132 + labelled_form_field(_('Preferred domain name:'), select(object, :preferred_domain_id, domains.map {|item| [item.name, item.id]}, :prompt => '&lt;' + _('Select domain') + '&gt;'))
133 133 end
134 134  
135 135 def control_panel(&block)
... ...
app/helpers/tags_helper.rb
  1 +# encoding: UTF-8
  2 +
1 3 module TagsHelper
2 4  
3 5 module Cloud
... ... @@ -7,7 +9,7 @@ module TagsHelper
7 9  
8 10 # <tt>tags</tt> must be a hash where the keys are tag names and the values
9 11 # the count of elements tagged with the tag, as returned by
10   - # Profile#find_tagged_with. If not tags were returned, just returns
  12 + # Profile#tagged_with. If not tags were returned, just returns
11 13 # _('No tags yet.')
12 14 #
13 15 # <tagname_option> must be a symbol representing the key to be inserted in
... ... @@ -39,15 +41,11 @@ module TagsHelper
39 41 max = tags.values.max.to_f
40 42 min = tags.values.min.to_f
41 43  
42   - # Uses iconv to translate utf8 strings to ascii.
43   - # If can't translate a character, ignore it.
44   - require 'iconv'
45   - utf8_to_ascii = Iconv.new("ASCII//TRANSLIT//IGNORE","UTF8")
46 44 # Sorts first based on translated strings and then, if they are equal, based on the original form.
47 45 # This way variant characters falls on the same level as their base characters and don't end up
48 46 # at the end of the tag list.
49 47 # Example: AA ÁA AB Z instead of AA AB Z ÁA
50   - tags.collect{ |k,v| [utf8_to_ascii.iconv(k).downcase, [k,v]] }.sort.collect { |ascii, t| t }.map do |tag,count|
  48 + tags.collect{ |k,v| [ActiveSupport::Inflector.transliterate(k).downcase, [k,v]] }.sort.collect { |ascii, t| t }.map do |tag,count|
51 49 if ( max == min )
52 50 v = 0.5
53 51 else
... ...
app/helpers/token_helper.rb
... ... @@ -27,7 +27,7 @@ module TokenHelper
27 27 hintText: #{options[:hint_text].to_json},
28 28 noResultsText: #{options[:no_results_text].to_json},
29 29 searchingText: #{options[:searching_text].to_json},
30   - searchDelay: #{options[:serach_delay].to_json},
  30 + searchDelay: #{options[:search_delay].to_json},
31 31 preventDuplicates: #{options[:prevent_duplicates].to_json},
32 32 backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
33 33 queryParam: #{name.to_json},
... ...
app/helpers/users_helper.rb
... ... @@ -18,7 +18,7 @@ module UsersHelper
18 18 )
19 19 end
20 20  
21   - def filter_title(filter)
  21 + def users_filter_title(filter)
22 22 FILTER_TRANSLATION[filter]
23 23 end
24 24  
... ...
app/mailers/.gitkeep 0 → 100644
app/mailers/comment_notifier.rb 0 → 100644
... ... @@ -0,0 +1,40 @@
  1 +class Comment::Notifier < ActionMailer::Base
  2 + def notification(comment)
  3 + profile = comment.article.profile
  4 + @recipient = profile.nickname || profile.name
  5 + @sender = comment.author_name
  6 + @sender_link = comment.author_link
  7 + @article_title = comment.article.name
  8 + @comment_url = comment.url
  9 + @comment_title = comment.title
  10 + @comment_body = comment.body
  11 + @environment = profile.environment.name
  12 + @url = profile.environment.top_url
  13 +
  14 + mail(
  15 + to: comment.notification_emails,
  16 + from: "#{profile.environment.name} <#{profile.environment.noreply_email}>",
  17 + subject: _("[%s] you got a new comment!") % [profile.environment.name]
  18 + )
  19 + end
  20 +
  21 + def mail_to_followers(comment, emails)
  22 + profile = comment.article.profile
  23 + @recipient = profile.nickname || profile.name
  24 + @sender = comment.author_name
  25 + @sender_link = comment.author_link
  26 + @article_title = comment.article.name
  27 + @comment_url = comment.url
  28 + @unsubscribe_url = comment.article.view_url.merge({:unfollow => true})
  29 + @comment_title = comment.title
  30 + @comment_body = comment.body
  31 + @environment = profile.environment.name
  32 + @url = profile.environment.top_url
  33 +
  34 + mail(
  35 + bcc: emails,
  36 + from: "#{profile.environment.name} <#{profile.environment.noreply_email}>",
  37 + subject: _("[%s] %s commented on a content of %s") % [profile.environment.name, comment.author_name, profile.short_name]
  38 + )
  39 + end
  40 +end
... ...
app/mailers/contact.rb 0 → 100644
... ... @@ -0,0 +1,64 @@
  1 +class Contact
  2 +
  3 + include ActiveModel::Validations
  4 +
  5 + def initialize(attributes = nil)
  6 + if attributes
  7 + attributes.each do |attr,value|
  8 + self.send("#{attr}=", value)
  9 + end
  10 + end
  11 + end
  12 +
  13 + attr_accessor :name
  14 + attr_accessor :subject
  15 + attr_accessor :message
  16 + attr_accessor :email
  17 + attr_accessor :state
  18 + attr_accessor :city
  19 + attr_accessor :receive_a_copy
  20 + attr_accessor :dest
  21 + attr_accessor :sender
  22 +
  23 + N_('Subject'); N_('Message'); N_('City and state'); N_('e-Mail'); N_('Name')
  24 +
  25 + validates_presence_of :subject, :email, :message, :name
  26 + validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|o| !o.email.blank?})
  27 +
  28 + def deliver
  29 + return false unless self.valid?
  30 + Contact::Sender.notification(self).deliver
  31 + end
  32 +
  33 + class Sender < ActionMailer::Base
  34 + def notification(contact)
  35 + @name = contact.name
  36 + @email = contact.email
  37 + @city = contact.city
  38 + @state = contact.state
  39 + @message = contact.message
  40 + @environment = contact.dest.environment.name
  41 + @url = url_for(:host => contact.dest.environment.default_hostname, :controller => 'home')
  42 + @target = contact.dest.name
  43 +
  44 + options = {
  45 + content_type: 'text/html',
  46 + to: contact.dest.notification_emails,
  47 + reply_to: contact.email,
  48 + subject: "[#{contact.dest.short_name(30)}] " + contact.subject,
  49 + from: "#{contact.name} <#{contact.dest.environment.noreply_email}>"
  50 + }
  51 +
  52 + if contact.sender
  53 + options.merge!('X-Noosfero-Sender' => contact.sender.identifier)
  54 + end
  55 +
  56 + if contact.receive_a_copy
  57 + options.merge!(cc: "#{contact.name} <#{contact.email}>")
  58 + end
  59 +
  60 + mail(options)
  61 + end
  62 + end
  63 +
  64 +end
... ...
app/mailers/environment_mailing.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +class EnvironmentMailing < Mailing
  2 +
  3 + def recipients(offset=0, limit=100)
  4 + source.people.all(:order => :id, :offset => offset, :limit => limit, :joins => "LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)", :conditions => { "m.person_id" => nil })
  5 + end
  6 +
  7 + def each_recipient
  8 + offset = 0
  9 + limit = 100
  10 + while !(people = recipients(offset, limit)).empty?
  11 + people.each do |person|
  12 + yield person
  13 + end
  14 + offset = offset + limit
  15 + end
  16 + end
  17 +
  18 + def signature_message
  19 + _('Sent by %s.') % source.name
  20 + end
  21 +
  22 + def url
  23 + source.top_url
  24 + end
  25 +end
... ...
app/mailers/mailing.rb 0 → 100644
... ... @@ -0,0 +1,65 @@
  1 +require 'mailing_job'
  2 +
  3 +class Mailing < ActiveRecord::Base
  4 +
  5 + attr_accessible :subject, :body
  6 + validates_presence_of :source_id, :subject, :body
  7 + belongs_to :source, :foreign_key => :source_id, :polymorphic => true
  8 + belongs_to :person
  9 +
  10 + has_many :mailing_sents
  11 +
  12 + xss_terminate :only => [ :subject, :body ], :with => 'white_list', :on => 'validation'
  13 +
  14 + after_create do |mailing|
  15 + mailing.schedule
  16 + end
  17 +
  18 + def schedule
  19 + Delayed::Job.enqueue MailingJob.new(self.id)
  20 + end
  21 +
  22 + def generate_from
  23 + "#{source.name} <#{if source.is_a? Environment then source.noreply_email else source.contact_email end}>"
  24 + end
  25 +
  26 + def generate_subject
  27 + '[%s] %s' % [source.name, subject]
  28 + end
  29 +
  30 + def signature_message
  31 + _('Sent by Noosfero.')
  32 + end
  33 +
  34 + def url
  35 + ''
  36 + end
  37 +
  38 + def deliver
  39 + each_recipient do |recipient|
  40 + begin
  41 + Mailing::Sender.notification(self, recipient.email).deliver
  42 + self.mailing_sents.create(:person => recipient)
  43 + rescue Exception
  44 + # FIXME should not discard errors silently. An idea is to collect all
  45 + # errors and generate a task (notification) for the +source+
  46 + # (environment/organization) listing these errors.
  47 + end
  48 + end
  49 + end
  50 +
  51 + class Sender < ActionMailer::Base
  52 + def notification(mailing, recipient)
  53 + @message = mailing.body
  54 + @signature_message = mailing.signature_message
  55 + @url = mailing.url
  56 + mail(
  57 + :content_type => 'text/html',
  58 + :to => recipient,
  59 + :from => mailing.generate_from,
  60 + :reply_to => mailing.person.email,
  61 + :subject => mailing.generate_subject
  62 + )
  63 + end
  64 + end
  65 +end
... ...
app/mailers/organization_mailing.rb 0 → 100644
... ... @@ -0,0 +1,30 @@
  1 +class OrganizationMailing < Mailing
  2 +
  3 + def generate_from
  4 + "#{person.name} <#{source.environment.noreply_email}>"
  5 + end
  6 +
  7 + def recipients(offset=0, limit=100)
  8 + source.members.all(:order => :id, :offset => offset, :limit => limit, :joins => "LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)", :conditions => { "m.person_id" => nil })
  9 + end
  10 +
  11 + def each_recipient
  12 + offset = 0
  13 + limit = 50
  14 + while !(people = recipients(offset, limit)).empty?
  15 + people.each do |person|
  16 + yield person
  17 + end
  18 + offset = offset + limit
  19 + end
  20 + end
  21 +
  22 + def signature_message
  23 + _('Sent by community %s.') % source.name
  24 + end
  25 +
  26 + include Rails.application.routes.url_helpers
  27 + def url
  28 + url_for(source.url)
  29 + end
  30 +end
... ...
app/mailers/pending_task_notifier.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class PendingTaskNotifier < ActionMailer::Base
  2 +
  3 + def notification(person)
  4 + @person = person
  5 + @tasks = person.tasks.pending
  6 + @organizations_with_pending_tasks = person.organizations_with_pending_tasks
  7 + @environment = person.environment.name
  8 + @url = url_for(:host => person.environment.default_hostname, :controller => 'home')
  9 + @default_hostname = person.environment.default_hostname
  10 + @url_for_pending_tasks = url_for(:host => person.environment.default_hostname, :controller => 'tasks', :profile => person.identifier)
  11 +
  12 + mail(
  13 + to: person.email,
  14 + from: "#{person.environment.name} <#{person.environment.noreply_email}>",
  15 + subject: _("[%s] Pending tasks") % person.environment.name
  16 + )
  17 + end
  18 +
  19 +end
... ...
app/mailers/scrap_notifier.rb 0 → 100644
... ... @@ -0,0 +1,17 @@
  1 +class Scrap::Notifier < ActionMailer::Base
  2 + def notification(scrap)
  3 + sender, receiver = scrap.sender, scrap.receiver
  4 + @recipient = receiver.name
  5 + @sender = sender.name
  6 + @sender_link = sender.url
  7 + @scrap_content = scrap.content
  8 + @wall_url = scrap.scrap_wall_url
  9 + @environment = sender.environment.name
  10 + @url = sender.environment.top_url
  11 + mail(
  12 + to: receiver.email,
  13 + from: "#{sender.environment.name} <#{sender.environment.noreply_email}>",
  14 + subject: _("[%s] You received a scrap!") % [sender.environment.name]
  15 + )
  16 + end
  17 +end
... ...
app/mailers/task_mailer.rb 0 → 100644
... ... @@ -0,0 +1,62 @@
  1 +class TaskMailer < ActionMailer::Base
  2 +
  3 + def target_notification(task, message)
  4 + @message = extract_message(message)
  5 + @target = task.target.name
  6 + @environment = task.environment.name
  7 + @url = generate_environment_url(task, :controller => 'home')
  8 + url_for_tasks_list = task.target.kind_of?(Environment) ? '' : url_for(task.target.tasks_url)
  9 + @tasks_url = url_for_tasks_list
  10 +
  11 + mail(
  12 + to: task.target.notification_emails.compact,
  13 + from: self.class.generate_from(task),
  14 + subject: "[%s] %s" % [task.environment.name, task.target_notification_description]
  15 + )
  16 + end
  17 +
  18 + def invitation_notification(task)
  19 + msg = task.expanded_message
  20 + @message = msg.gsub /<url>/, generate_environment_url(task, :controller => 'account', :action => 'signup', :invitation_code => task.code)
  21 +
  22 + mail(
  23 + to: task.friend_email,
  24 + from: self.class.generate_from(task),
  25 + subject: '[%s] %s' % [ task.requestor.environment.name, task.target_notification_description ]
  26 + )
  27 + end
  28 +
  29 + def generic_message(name, task)
  30 + return if !task.respond_to?("#{name}_message")
  31 +
  32 + @message = extract_message(task.send("#{name}_message"))
  33 + @requestor = task.requestor.name
  34 + @environment = task.requestor.environment.name
  35 + @url = url_for(:host => task.requestor.environment.default_hostname, :controller => 'home')
  36 +
  37 + mail(
  38 + to: task.requestor.notification_emails,
  39 + from: self.class.generate_from(task),
  40 + subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description]
  41 + )
  42 + end
  43 +
  44 + protected
  45 +
  46 + def extract_message(message)
  47 + if message.kind_of?(Proc)
  48 + self.instance_exec(&message)
  49 + else
  50 + message.to_s
  51 + end
  52 + end
  53 +
  54 + def self.generate_from(task)
  55 + "#{task.environment.name} <#{task.environment.noreply_email}>"
  56 + end
  57 +
  58 + def generate_environment_url(task, url = {})
  59 + url_for(Noosfero.url_options.merge(:host => task.environment.default_hostname).merge(url))
  60 + end
  61 +
  62 +end
... ...
app/mailers/user_mailer.rb 0 → 100644
... ... @@ -0,0 +1,47 @@
  1 +class UserMailer < ActionMailer::Base
  2 + def activation_email_notify(user)
  3 + user_email = "#{user.login}@#{user.email_domain}"
  4 + @name = user.name
  5 + @email = user_email
  6 + @webmail = MailConf.webmail_url(user.login, user.email_domain)
  7 + @environment = user.environment.name
  8 + @url = url_for(:host => user.environment.default_hostname, :controller => 'home')
  9 +
  10 + mail(
  11 + to: user_email,
  12 + from: "#{user.environment.name} <#{user.environment.contact_email}>",
  13 + subject: _("[%{environment}] Welcome to %{environment} mail!") % { :environment => user.environment.name }
  14 + )
  15 + end
  16 +
  17 + def activation_code(user)
  18 + @recipient = user.name,
  19 + @activation_code = user.activation_code
  20 + @environment = user.environment.name
  21 + @url = user.environment.top_url
  22 +
  23 + mail(
  24 + from: "#{user.environment.name} <#{user.environment.contact_email}>",
  25 + to: user.email,
  26 + subject: _("[%s] Activate your account") % [user.environment.name],
  27 + )
  28 + end
  29 +
  30 + def signup_welcome_email(user)
  31 + @body = user.environment.signup_welcome_text_body.gsub('{user_name}', user.name)
  32 + email_subject = user.environment.signup_welcome_text_subject
  33 + mail(
  34 + content_type: 'text/html',
  35 + to: user.email,
  36 + from: "#{user.environment.name} <#{user.environment.contact_email}>",
  37 + subject: email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject,
  38 + body: @body
  39 + )
  40 + end
  41 +
  42 + class Job < Struct.new(:user, :method)
  43 + def perform
  44 + UserMailer.send(method, user).deliver
  45 + end
  46 + end
  47 +end
... ...
app/models/abuse_report.rb
1 1 class AbuseReport < ActiveRecord::Base
2 2  
  3 + attr_accessible :content, :reason
  4 +
3 5 belongs_to :reporter, :class_name => 'Person'
4 6 belongs_to :abuse_complaint
5 7 has_many :reported_images, :dependent => :destroy
... ...
app/models/action_tracker_notification.rb
... ... @@ -8,6 +8,8 @@ class ActionTrackerNotification &lt; ActiveRecord::Base
8 8 validates_presence_of :profile_id, :action_tracker_id
9 9 validates_uniqueness_of :action_tracker_id, :scope => :profile_id
10 10  
  11 + attr_accessible :profile_id, :action_tracker_id
  12 +
11 13 end
12 14  
13 15 ActionTracker::Record.has_many :action_tracker_notifications, :class_name => 'ActionTrackerNotification', :foreign_key => 'action_tracker_id', :dependent => :destroy
... ...
app/models/approve_comment.rb
... ... @@ -6,7 +6,11 @@ class ApproveComment &lt; Task
6 6 validates_presence_of :comment_attributes
7 7  
8 8 def comment
9   - @comment ||= Comment.new(ActiveSupport::JSON.decode(self.comment_attributes)) unless self.comment_attributes.nil?
  9 + unless @comment || self.comment_attributes.nil?
  10 + @comment = Comment.new
  11 + @comment.assign_attributes(ActiveSupport::JSON.decode(self.comment_attributes), :without_protection => true)
  12 + end
  13 + @comment
10 14 end
11 15  
12 16 def requestor_name
... ...
app/models/article.rb
... ... @@ -2,6 +2,8 @@ require &#39;hpricot&#39;
2 2  
3 3 class Article < ActiveRecord::Base
4 4  
  5 + attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, :allow_members_to_edit, :translation_of_id, :language, :license_id, :parent_id, :display_posts_in_current_language, :category_ids, :posts_per_page, :moderate_comments, :accept_comments, :feed, :published, :source, :highlighted, :notify_comments, :display_hits, :slug, :external_feed_builder, :display_versions
  6 +
5 7 acts_as_having_image
6 8  
7 9 SEARCHABLE_FIELDS = {
... ... @@ -96,11 +98,11 @@ class Article &lt; ActiveRecord::Base
96 98  
97 99 xss_terminate :only => [ :name ], :on => 'validation', :with => 'white_list'
98 100  
99   - named_scope :in_category, lambda { |category|
  101 + scope :in_category, lambda { |category|
100 102 {:include => 'categories_including_virtual', :conditions => { 'categories.id' => category.id }}
101 103 }
102 104  
103   - named_scope :by_range, lambda { |range| {
  105 + scope :by_range, lambda { |range| {
104 106 :conditions => [
105 107 'published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last }
106 108 ]
... ... @@ -148,7 +150,7 @@ class Article &lt; ActiveRecord::Base
148 150 self.profile
149 151 end
150 152  
151   - def self.human_attribute_name(attrib)
  153 + def self.human_attribute_name(attrib, options = {})
152 154 case attrib.to_sym
153 155 when :name
154 156 _('Title')
... ... @@ -219,14 +221,19 @@ class Article &lt; ActiveRecord::Base
219 221  
220 222 # retrieves all articles belonging to the given +profile+ that are not
221 223 # sub-articles of any other article.
222   - named_scope :top_level_for, lambda { |profile|
  224 + scope :top_level_for, lambda { |profile|
223 225 {:conditions => [ 'parent_id is null and profile_id = ?', profile.id ]}
224 226 }
225 227  
226   - named_scope :join_profile, :joins => [:profile]
  228 + scope :public,
  229 + :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ], :joins => [:profile]
227 230  
228   - named_scope :public,
229   - :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ]
  231 + scope :more_recent,
  232 + :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND
  233 + ((articles.type != ?) OR articles.type is NULL)",
  234 + true, true, true, true, 'RssFeed'
  235 + ],
  236 + :order => 'articles.published_at desc, articles.id desc'
230 237  
231 238 # retrives the most commented articles, sorted by the comment count (largest
232 239 # first)
... ... @@ -234,7 +241,8 @@ class Article &lt; ActiveRecord::Base
234 241 paginate(:order => 'comments_count DESC', :page => 1, :per_page => limit)
235 242 end
236 243  
237   - named_scope :relevant_as_recent, :conditions => ["(articles.type != 'UploadedFile' and articles.type != 'RssFeed' and articles.type != 'Blog') OR articles.type is NULL"]
  244 + scope :more_popular, :order => 'hits DESC'
  245 + scope :relevant_as_recent, :conditions => ["(articles.type != 'UploadedFile' and articles.type != 'RssFeed' and articles.type != 'Blog') OR articles.type is NULL"]
238 246  
239 247 def self.recent(limit = nil, extra_conditions = {}, pagination = true)
240 248 result = scoped({:conditions => extra_conditions}).
... ... @@ -243,13 +251,6 @@ class Article &lt; ActiveRecord::Base
243 251 limit(limit).
244 252 order(['articles.published_at desc', 'articles.id desc'])
245 253  
246   - if !( scoped_methods && scoped_methods.last &&
247   - scoped_methods.last[:find] &&
248   - scoped_methods.last[:find][:joins] &&
249   - scoped_methods.last[:find][:joins].index('profiles') )
250   - result = result.includes(:profile)
251   - end
252   -
253 254 pagination ? result.paginate({:page => 1, :per_page => limit}) : result
254 255 end
255 256  
... ... @@ -261,16 +262,18 @@ class Article &lt; ActiveRecord::Base
261 262 # (To override short format representation, override the lead method)
262 263 def to_html(options = {})
263 264 if options[:format] == 'short'
264   - display_short_format(self)
  265 + article = self
  266 + proc do
  267 + display_short_format(article)
  268 + end
265 269 else
266 270 body || ''
267 271 end
268 272 end
269 273  
270   - include ApplicationHelper
271 274 def reported_version(options = {})
272 275 article = self
273   - search_path = File.join(Rails.root, 'app', 'views', 'shared', 'reported_versions')
  276 + search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions')
274 277 partial_path = File.join('shared', 'reported_versions', partial_for_class_in_view_path(article.class, search_path))
275 278 lambda { render_to_string(:partial => partial_path, :locals => {:article => article}) }
276 279 end
... ... @@ -371,7 +374,7 @@ class Article &lt; ActiveRecord::Base
371 374 {}
372 375 end
373 376  
374   - named_scope :native_translations, :conditions => { :translation_of_id => nil }
  377 + scope :native_translations, :conditions => { :translation_of_id => nil }
375 378  
376 379 def translatable?
377 380 false
... ... @@ -407,7 +410,7 @@ class Article &lt; ActiveRecord::Base
407 410  
408 411 def native_translation_must_have_language
409 412 unless self.translation_of.nil?
410   - errors.add_to_base(N_('A language must be choosen for the native article')) if self.translation_of.language.blank?
  413 + errors.add(:base, N_('A language must be choosen for the native article')) if self.translation_of.language.blank?
411 414 end
412 415 end
413 416  
... ... @@ -449,17 +452,17 @@ class Article &lt; ActiveRecord::Base
449 452 ['TextArticle', 'TextileArticle', 'TinyMceArticle']
450 453 end
451 454  
452   - named_scope :published, :conditions => { :published => true }
453   - named_scope :folders, lambda {|profile|{:conditions => { :type => profile.folder_types} }}
454   - named_scope :no_folders, lambda {|profile|{:conditions => ['type NOT IN (?)', profile.folder_types]}}
455   - named_scope :galleries, :conditions => { :type => 'Gallery' }
456   - named_scope :images, :conditions => { :is_image => true }
457   - named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
458   - named_scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } }
  455 + scope :published, :conditions => { :published => true }
  456 + scope :folders, lambda {|profile|{:conditions => { :type => profile.folder_types} }}
  457 + scope :no_folders, lambda {|profile|{:conditions => ['type NOT IN (?)', profile.folder_types]}}
  458 + scope :galleries, :conditions => { :type => 'Gallery' }
  459 + scope :images, :conditions => { :is_image => true }
  460 + scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
  461 + scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } }
459 462  
460   - named_scope :more_popular, :order => 'hits DESC'
461   - named_scope :more_comments, :order => "comments_count DESC"
462   - named_scope :more_recent, :order => "created_at DESC"
  463 + scope :more_popular, :order => 'hits DESC'
  464 + scope :more_comments, :order => "comments_count DESC"
  465 + scope :more_recent, :order => "created_at DESC"
463 466  
464 467 def self.display_filter(user, profile)
465 468 return {:conditions => ['published = ?', true]} if !user
... ... @@ -531,13 +534,23 @@ class Article &lt; ActiveRecord::Base
531 534 def copy(options = {})
532 535 attrs = attributes.reject! { |key, value| ATTRIBUTES_NOT_COPIED.include?(key.to_sym) }
533 536 attrs.merge!(options)
534   - self.class.create(attrs)
  537 + object = self.class.new
  538 + attrs.each do |key, value|
  539 + object.send(key.to_s+'=', value)
  540 + end
  541 + object.save
  542 + object
535 543 end
536 544  
537 545 def copy!(options = {})
538 546 attrs = attributes.reject! { |key, value| ATTRIBUTES_NOT_COPIED.include?(key.to_sym) }
539 547 attrs.merge!(options)
540   - self.class.create!(attrs)
  548 + object = self.class.new
  549 + attrs.each do |key, value|
  550 + object.send(key.to_s+'=', value)
  551 + end
  552 + object.save!
  553 + object
541 554 end
542 555  
543 556 ATTRIBUTES_NOT_COPIED = [
... ... @@ -631,16 +644,18 @@ class Article &lt; ActiveRecord::Base
631 644 end
632 645  
633 646 def author_name(version_number = nil)
634   - person = version_number ? author(version_number) : author
  647 + person = author(version_number)
635 648 person ? person.name : (setting[:author_name] || _('Unknown'))
636 649 end
637 650  
638   - def author_url
639   - author ? author.url : nil
  651 + def author_url(version_number = nil)
  652 + person = author(version_number)
  653 + person ? person.url : nil
640 654 end
641 655  
642   - def author_id
643   - author ? author.id : nil
  656 + def author_id(version_number = nil)
  657 + person = author(version_number)
  658 + person ? person.id : nil
644 659 end
645 660  
646 661 def version_license(version_number = nil)
... ... @@ -734,7 +749,7 @@ class Article &lt; ActiveRecord::Base
734 749  
735 750 def sanitize_tag_list
736 751 sanitizer = HTML::FullSanitizer.new
737   - self.tag_list.names.map!{|i| strip_tag_name sanitizer.sanitize(i) }
  752 + self.tag_list.map!{|i| strip_tag_name sanitizer.sanitize(i) }
738 753 end
739 754  
740 755 def strip_tag_name(tag_name)
... ...
app/models/article_block.rb
1 1 class ArticleBlock < Block
2 2  
  3 + attr_accessible :article_id
  4 +
3 5 def self.description
4 6 _('Display one of your contents')
5 7 end
... ... @@ -10,7 +12,7 @@ class ArticleBlock &lt; Block
10 12  
11 13 def content(args={})
12 14 block = self
13   - lambda do
  15 + proc do
14 16 block_title(block.title) +
15 17 (block.article ? article_to_html(FilePresenter.for(block.article),
16 18 :gallery_view => false,
... ...
app/models/block.rb
1 1 class Block < ActiveRecord::Base
2 2  
  3 + attr_accessible :title, :display, :limit, :box_id, :posts_per_page, :visualization_format, :language, :display_user, :box
  4 +
3 5 # to be able to generate HTML
4 6 include ActionView::Helpers::UrlHelper
5 7 include ActionView::Helpers::TagHelper
... ... @@ -14,7 +16,24 @@ class Block &lt; ActiveRecord::Base
14 16  
15 17 acts_as_having_settings
16 18  
17   - named_scope :enabled, :conditions => { :enabled => true }
  19 + scope :enabled, :conditions => { :enabled => true }
  20 +
  21 + def embedable?
  22 + false
  23 + end
  24 +
  25 + def embed_code
  26 + me = self
  27 + proc do
  28 + content_tag('iframe', '',
  29 + :src => url_for(:controller => 'embed', :action => 'block', :id => me.id, :only_path => false),
  30 + :frameborder => 0,
  31 + :width => 1024,
  32 + :height => 768,
  33 + :class => "embed block #{me.class.name.to_css_class}"
  34 + )
  35 + end
  36 + end
18 37  
19 38 # Determines whether a given block must be visible. Optionally a
20 39 # <tt>context</tt> must be specified. <tt>context</tt> must be a hash, and
... ... @@ -22,11 +41,13 @@ class Block &lt; ActiveRecord::Base
22 41 #
23 42 # * <tt>:article</tt>: the article being viewed currently
24 43 # * <tt>:language</tt>: in which language the block will be displayed
  44 + # * <tt>:user</tt>: the logged user
25 45 def visible?(context = nil)
26 46 return false if display == 'never'
27 47  
28 48 if context
29 49 return false if language != 'all' && language != context[:locale]
  50 + return false unless display_to_user?(context[:user])
30 51  
31 52 begin
32 53 return self.send("display_#{display}", context)
... ... @@ -38,6 +59,10 @@ class Block &lt; ActiveRecord::Base
38 59 true
39 60 end
40 61  
  62 + def display_to_user?(user)
  63 + display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged')
  64 + end
  65 +
41 66 def display_always(context)
42 67 true
43 68 end
... ... @@ -68,6 +93,14 @@ class Block &lt; ActiveRecord::Base
68 93 # the homepage of its owner.
69 94 settings_items :display, :type => :string, :default => 'always'
70 95  
  96 +
  97 + # The condition for displaying a block to users. It can assume the following values:
  98 + #
  99 + # * <tt>'all'</tt>: the block is always displayed
  100 + # * <tt>'logged'</tt>: the block is displayed to logged users only
  101 + # * <tt>'not_logged'</tt>: the block is displayed only to not logged users
  102 + settings_items :display_user, :type => :string, :default => 'all'
  103 +
71 104 # The block can be configured to be displayed in all languages or in just one language. It can assume any locale of the environment:
72 105 #
73 106 # * <tt>'all'</tt>: the block is always displayed
... ... @@ -141,7 +174,7 @@ class Block &lt; ActiveRecord::Base
141 174 end
142 175  
143 176 alias :active_record_cache_key :cache_key
144   - def cache_key(language='en')
  177 + def cache_key(language='en', user=nil)
145 178 active_record_cache_key+'-'+language
146 179 end
147 180  
... ... @@ -165,22 +198,30 @@ class Block &lt; ActiveRecord::Base
165 198 end
166 199  
167 200 DISPLAY_OPTIONS = {
168   - 'always' => __('In all pages'),
169   - 'home_page_only' => __('Only in the homepage'),
170   - 'except_home_page' => __('In all pages, except in the homepage'),
171   - 'never' => __('Don\'t display'),
  201 + 'always' => _('In all pages'),
  202 + 'home_page_only' => _('Only in the homepage'),
  203 + 'except_home_page' => _('In all pages, except in the homepage'),
  204 + 'never' => _('Don\'t display'),
172 205 }
173 206  
174   - def display_options
  207 + def display_options_available
175 208 DISPLAY_OPTIONS.keys
176 209 end
177 210  
178   - def display_option_label(option)
179   - DISPLAY_OPTIONS[option]
  211 + def display_options
  212 + DISPLAY_OPTIONS.slice(*display_options_available)
  213 + end
  214 +
  215 + def display_user_options
  216 + @display_user_options ||= {
  217 + 'all' => _('All users'),
  218 + 'logged' => _('Logged'),
  219 + 'not_logged' => _('Not logged'),
  220 + }
180 221 end
181 222  
182 223 def duplicate
183   - duplicated_block = self.clone
  224 + duplicated_block = self.dup
184 225 duplicated_block.display = 'never'
185 226 duplicated_block.created_at = nil
186 227 duplicated_block.updated_at = nil
... ...
app/models/blog.rb
1 1 class Blog < Folder
2 2  
  3 + attr_accessible :visualization_format
  4 +
3 5 acts_as_having_posts
4 6 include PostsLimit
5 7  
... ... @@ -26,7 +28,7 @@ class Blog &lt; Folder
26 28 include ActionView::Helpers::TagHelper
27 29 def to_html(options = {})
28 30 me = self
29   - lambda do
  31 + proc do
30 32 render :file => 'content_viewer/blog_page', :locals => { :blog=>me, :inside_block=>options[:inside_block] }
31 33 end
32 34 end
... ... @@ -46,12 +48,14 @@ class Blog &lt; Folder
46 48 self.external_feed_data = efeed
47 49 end
48 50  
49   - def validate
  51 + validate :prepare_external_feed
  52 +
  53 + def prepare_external_feed
50 54 unless self.external_feed_data.nil?
51 55 if self.external_feed(true) && self.external_feed.id == self.external_feed_data[:id].to_i
52 56 self.external_feed.attributes = self.external_feed_data
53 57 else
54   - self.build_external_feed(self.external_feed_data)
  58 + self.build_external_feed(self.external_feed_data, :without_protection => true)
55 59 end
56 60 self.external_feed.valid?
57 61 self.external_feed.errors.delete(:blog_id) # dont validate here relation: external_feed <-> blog
... ...
app/models/blog_archives_block.rb
... ... @@ -2,7 +2,8 @@ class BlogArchivesBlock &lt; Block
2 2  
3 3 include ActionView::Helpers::TagHelper
4 4 include ActionView::Helpers::UrlHelper
5   - include ActionController::UrlWriter
  5 + include ActionView::Helpers
  6 + include Rails.application.routes.url_helpers
6 7 include ActionView::Helpers::AssetTagHelper
7 8 include DatesHelper
8 9  
... ... @@ -31,10 +32,10 @@ class BlogArchivesBlock &lt; Block
31 32 return nil unless owner_blog
32 33 results = ''
33 34 posts = visible_posts(args[:person])
34   - posts.count(:all, :group => 'EXTRACT(YEAR FROM published_at)').sort_by {|year, count| -year.to_i}.each do |year, count|
  35 + posts.except(:order).count(:all, :group => 'EXTRACT(YEAR FROM published_at)').sort_by {|year, count| -year.to_i}.each do |year, count|
35 36 results << content_tag('li', content_tag('strong', "#{year} (#{count})"))
36 37 results << "<ul class='#{year}-archive'>"
37   - posts.count(:all, :conditions => ['EXTRACT(YEAR FROM published_at)=?', year], :group => 'EXTRACT(MONTH FROM published_at)').sort_by {|month, count| -month.to_i}.each do |month, count|
  38 + posts.except(:order).count(:all, :conditions => ['EXTRACT(YEAR FROM published_at)=?', year], :group => 'EXTRACT(MONTH FROM published_at)').sort_by {|month, count| -month.to_i}.each do |month, count|
38 39 month_name = gettext(MONTHS[month.to_i - 1])
39 40 results << content_tag('li', link_to("#{month_name} (#{count})", owner_blog.url.merge(:year => year, :month => month)))
40 41 end
... ...
app/models/box.rb
... ... @@ -3,9 +3,11 @@ class Box &lt; ActiveRecord::Base
3 3 acts_as_list :scope => 'owner_id = #{owner_id} and owner_type = \'#{owner_type}\''
4 4 has_many :blocks, :dependent => :destroy, :order => 'position'
5 5  
  6 + attr_accessible :owner
  7 +
6 8 include Noosfero::Plugin::HotSpot
7 9  
8   - named_scope :with_position, :conditions => ['boxes.position > 0']
  10 + scope :with_position, :conditions => ['boxes.position > 0']
9 11  
10 12 def environment
11 13 owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil
... ... @@ -26,6 +28,8 @@ class Box &lt; ActiveRecord::Base
26 28 CategoriesBlock,
27 29 CommunitiesBlock,
28 30 EnterprisesBlock,
  31 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  32 + # the Noosfero core soon, see ActionItem3045
29 33 EnvironmentStatisticsBlock,
30 34 FansBlock,
31 35 FavoriteEnterprisesBlock,
... ... @@ -52,6 +56,8 @@ class Box &lt; ActiveRecord::Base
52 56 CommunitiesBlock,
53 57 DisabledEnterpriseMessageBlock,
54 58 EnterprisesBlock,
  59 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  60 + # the Noosfero core soon, see ActionItem3045
55 61 EnvironmentStatisticsBlock,
56 62 FansBlock,
57 63 FavoriteEnterprisesBlock,
... ...
app/models/categories_block.rb
... ... @@ -8,6 +8,8 @@ class CategoriesBlock &lt; Block
8 8  
9 9 settings_items :category_types, :type => Array, :default => []
10 10  
  11 + attr_accessible :category_types
  12 +
11 13 def self.description
12 14 _("Categories Menu")
13 15 end
... ... @@ -30,7 +32,7 @@ class CategoriesBlock &lt; Block
30 32  
31 33 def content(args={})
32 34 block = self
33   - lambda do
  35 + proc do
34 36 render :file => 'blocks/categories', :locals => { :block => block }
35 37 end
36 38 end
... ...
app/models/category.rb
1 1 class Category < ActiveRecord::Base
2 2  
  3 + attr_accessible :name, :parent_id, :display_color, :display_in_menu, :image_builder, :environment, :parent
  4 +
3 5 SEARCHABLE_FIELDS = {
4 6 :name => 10,
5 7 :acronym => 5,
... ... @@ -16,11 +18,11 @@ class Category &lt; ActiveRecord::Base
16 18 validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('{fn} was already assigned to another category.').fix_i18n
17 19  
18 20 # Finds all top level categories for a given environment.
19   - named_scope :top_level_for, lambda { |environment|
  21 + scope :top_level_for, lambda { |environment|
20 22 {:conditions => ['parent_id is null and environment_id = ?', environment.id ]}
21 23 }
22 24  
23   - named_scope :on_level, lambda { |parent| {:conditions => {:parent_id => parent}} }
  25 + scope :on_level, lambda { |parent| {:conditions => {:parent_id => parent}} }
24 26  
25 27 acts_as_filesystem
26 28  
... ... @@ -40,7 +42,7 @@ class Category &lt; ActiveRecord::Base
40 42  
41 43 acts_as_having_image
42 44  
43   - named_scope :from_types, lambda { |types|
  45 + scope :from_types, lambda { |types|
44 46 types.select{ |t| t.blank? }.empty? ?
45 47 { :conditions => { :type => types } } :
46 48 { :conditions => [ "type IN (?) OR type IS NULL", types.reject{ |t| t.blank? } ] }
... ... @@ -67,7 +69,7 @@ class Category &lt; ActiveRecord::Base
67 69 end
68 70  
69 71 def recent_comments(limit = 10)
70   - comments.paginate(:all, :order => 'created_at DESC, comments.id DESC', :page => 1, :per_page => limit)
  72 + comments.paginate(:order => 'created_at DESC, comments.id DESC', :page => 1, :per_page => limit)
71 73 end
72 74  
73 75 def most_commented_articles(limit = 10)
... ...
app/models/certifier.rb
1 1 class Certifier < ActiveRecord::Base
2 2  
  3 + attr_accessible :name, :environment
  4 +
3 5 SEARCHABLE_FIELDS = {
4 6 :name => 10,
5 7 :description => 3,
... ...
app/models/change_password.rb
... ... @@ -2,7 +2,7 @@ class ChangePassword &lt; Task
2 2  
3 3 attr_accessor :password, :password_confirmation
4 4  
5   - def self.human_attribute_name(attrib)
  5 + def self.human_attribute_name(attrib, options = {})
6 6 case attrib.to_sym
7 7 when :password
8 8 _('Password')
... ... @@ -58,13 +58,13 @@ class ChangePassword &lt; Task
58 58 _('Your password was changed successfully.')
59 59 end
60 60  
61   - include ActionController::UrlWriter
  61 + include Rails.application.routes.url_helpers
62 62 def task_created_message
63 63 hostname = self.requestor.environment.default_hostname
64 64 code = self.code
65 65 url = url_for(:host => hostname, :controller => 'account', :action => 'new_password', :code => code)
66 66  
67   - lambda do
  67 + proc do
68 68 _("In order to change your password, please visit the following address:\n\n%s\n\nIf you did not required any change to your password just desconsider this email.") % url
69 69 end
70 70 end
... ...
app/models/city.rb
1 1 class City < Region
  2 + attr_accessible :name, :parent_id
2 3 end
... ...
app/models/comment.rb
... ... @@ -6,6 +6,8 @@ class Comment &lt; ActiveRecord::Base
6 6 :body => 2,
7 7 }
8 8  
  9 + attr_accessible :body, :author, :name, :email, :title, :reply_of_id, :source
  10 +
9 11 validates_presence_of :body
10 12  
11 13 belongs_to :source, :counter_cache => true, :polymorphic => true
... ... @@ -16,7 +18,7 @@ class Comment &lt; ActiveRecord::Base
16 18 has_many :children, :class_name => 'Comment', :foreign_key => 'reply_of_id', :dependent => :destroy
17 19 belongs_to :reply_of, :class_name => 'Comment', :foreign_key => 'reply_of_id'
18 20  
19   - named_scope :without_reply, :conditions => ['reply_of_id IS NULL']
  21 + scope :without_reply, :conditions => ['reply_of_id IS NULL']
20 22  
21 23 # unauthenticated authors:
22 24 validates_presence_of :name, :if => (lambda { |record| !record.email.blank? })
... ... @@ -127,11 +129,11 @@ class Comment &lt; ActiveRecord::Base
127 129 def notify_by_mail
128 130 if source.kind_of?(Article) && article.notify_comments?
129 131 if !notification_emails.empty?
130   - Comment::Notifier.deliver_mail(self)
  132 + Comment::Notifier.notification(self).deliver
131 133 end
132 134 emails = article.followers - [author_email]
133 135 if !emails.empty?
134   - Comment::Notifier.deliver_mail_to_followers(self, emails)
  136 + Comment::Notifier.mail_to_followers(self, emails).deliver
135 137 end
136 138 end
137 139 end
... ... @@ -168,40 +170,6 @@ class Comment &lt; ActiveRecord::Base
168 170 body || ''
169 171 end
170 172  
171   - class Notifier < ActionMailer::Base
172   - def mail(comment)
173   - profile = comment.article.profile
174   - recipients comment.notification_emails
175   - from "#{profile.environment.name} <#{profile.environment.contact_email}>"
176   - subject _("[%s] you got a new comment!") % [profile.environment.name]
177   - body :recipient => profile.nickname || profile.name,
178   - :sender => comment.author_name,
179   - :sender_link => comment.author_link,
180   - :article_title => comment.article.name,
181   - :comment_url => comment.url,
182   - :comment_title => comment.title,
183   - :comment_body => comment.body,
184   - :environment => profile.environment.name,
185   - :url => profile.environment.top_url
186   - end
187   - def mail_to_followers(comment, emails)
188   - profile = comment.article.profile
189   - bcc emails
190   - from "#{profile.environment.name} <#{profile.environment.contact_email}>"
191   - subject _("[%s] %s commented on a content of %s") % [profile.environment.name, comment.author_name, profile.short_name]
192   - body :recipient => profile.nickname || profile.name,
193   - :sender => comment.author_name,
194   - :sender_link => comment.author_link,
195   - :article_title => comment.article.name,
196   - :comment_url => comment.url,
197   - :unsubscribe_url => comment.article.view_url.merge({:unfollow => true}),
198   - :comment_title => comment.title,
199   - :comment_body => comment.body,
200   - :environment => profile.environment.name,
201   - :url => profile.environment.top_url
202   - end
203   - end
204   -
205 173 def rejected?
206 174 @rejected
207 175 end
... ...
app/models/communities_block.rb
1 1 class CommunitiesBlock < ProfileListBlock
2 2  
  3 + attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type
  4 +
3 5 def self.description
4   - __('Communities')
  6 + _('Communities')
5 7 end
6 8  
7 9 def default_title
8   - n__('{#} community', '{#} communities', profile_count)
  10 + n_('{#} community', '{#} communities', profile_count)
9 11 end
10 12  
11 13 def help
12   - __('This block displays the communities in which the user is a member.')
  14 + _('This block displays the communities in which the user is a member.')
13 15 end
14 16  
15 17 def footer
16 18 owner = self.owner
17 19 case owner
18 20 when Profile
19   - lambda do
  21 + lambda do |context|
20 22 link_to s_('communities|View all'), :profile => owner.identifier, :controller => 'profile', :action => 'communities'
21 23 end
22 24 when Environment
23   - lambda do
  25 + lambda do |context|
24 26 link_to s_('communities|View all'), :controller => 'search', :action => 'communities'
25 27 end
26 28 else
... ...
app/models/community.rb
1 1 class Community < Organization
2 2  
  3 + attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type
  4 + after_destroy :check_invite_member_for_destroy
  5 +
3 6 def self.type_name
4 7 _('Community')
5 8 end
... ... @@ -8,7 +11,6 @@ class Community &lt; Organization
8 11 N_('Language')
9 12  
10 13 settings_items :language
11   - settings_items :zip_code, :city, :state, :country
12 14  
13 15 extend SetProfileRegionFromCityState::ClassMethods
14 16 set_profile_region_from_city_state
... ... @@ -17,12 +19,22 @@ class Community &lt; Organization
17 19 community.moderated_articles = true if community.environment.enabled?('organizations_are_moderated_by_default')
18 20 end
19 21  
  22 + def check_invite_member_for_destroy
  23 + InviteMember.pending.select { |task| task.community_id == self.id }.map(&:destroy)
  24 + end
  25 +
  26 + # Since it's not a good idea to add the environment as accessible through
  27 + # mass-assignment, we set it manually here. Note that this requires that the
  28 + # places that call this method are safe from mass-assignment by setting the
  29 + # environment key themselves.
20 30 def self.create_after_moderation(requestor, attributes = {})
  31 + environment = attributes.delete(:environment)
21 32 community = Community.new(attributes)
  33 + community.environment = environment
22 34 if community.environment.enabled?('admin_must_approve_new_communities')
23   - CreateCommunity.create(attributes.merge(:requestor => requestor))
  35 + CreateCommunity.create!(attributes.merge(:requestor => requestor, :environment => environment))
24 36 else
25   - community = Community.create(attributes)
  37 + community.save!
26 38 community.add_admin(requestor)
27 39 end
28 40 community
... ... @@ -38,8 +50,9 @@ class Community &lt; Organization
38 50 super + FIELDS
39 51 end
40 52  
41   - def validate
42   - super
  53 + validate :presence_of_required_fieds
  54 +
  55 + def presence_of_required_fieds
43 56 self.required_fields.each do |field|
44 57 if self.send(field).blank?
45 58 self.errors.add_on_blank(field)
... ... @@ -84,7 +97,7 @@ class Community &lt; Organization
84 97 end
85 98  
86 99 def control_panel_settings_button
87   - {:title => __('Community Info and settings'), :icon => 'edit-profile-group'}
  100 + {:title => _('Community Info and settings'), :icon => 'edit-profile-group'}
88 101 end
89 102  
90 103 def activities
... ...
app/models/contact.rb
... ... @@ -1,49 +0,0 @@
1   -class Contact < ActiveRecord::Base #WithoutTable
2   - tableless :columns => [
3   - [:name, :string],
4   - [:subject, :string],
5   - [:message, :string],
6   - [:email, :string],
7   - [:state, :string],
8   - [:city, :string],
9   - [:receive_a_copy, :boolean]
10   - ]
11   - attr_accessor :dest
12   - attr_accessor :sender
13   -
14   - N_('Subject'); N_('Message'); N_('City and state'); N_('e-Mail'); N_('Name')
15   -
16   - validates_presence_of :subject, :email, :message, :name
17   - validates_format_of :email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda {|o| !o.email.blank?})
18   -
19   - def deliver
20   - return false unless self.valid?
21   - Contact::Sender.deliver_mail(self)
22   - end
23   -
24   - class Sender < ActionMailer::Base
25   - def mail(contact)
26   - content_type 'text/html'
27   - emails = contact.dest.notification_emails
28   - recipients emails
29   - from "#{contact.name} <#{contact.dest.environment.contact_email}>"
30   - reply_to contact.email
31   - if contact.sender
32   - headers 'X-Noosfero-Sender' => contact.sender.identifier
33   - end
34   - if contact.receive_a_copy
35   - cc "#{contact.name} <#{contact.email}>"
36   - end
37   - subject "[#{contact.dest.short_name(30)}] " + contact.subject
38   - body :name => contact.name,
39   - :email => contact.email,
40   - :city => contact.city,
41   - :state => contact.state,
42   - :message => contact.message,
43   - :environment => contact.dest.environment.name,
44   - :url => url_for(:host => contact.dest.environment.default_hostname, :controller => 'home'),
45   - :target => contact.dest.name
46   - end
47   - end
48   -
49   -end
app/models/contact_list.rb
... ... @@ -16,12 +16,16 @@ class ContactList &lt; ActiveRecord::Base
16 16  
17 17 def register_auth_error
18 18 msg = _('There was an error while authenticating. Did you enter correct login and password?')
19   - self.update_attributes(:fetched => true, :error_fetching => msg)
  19 + self.fetched = true
  20 + self.error_fetching = msg
  21 + self.save!
20 22 end
21 23  
22 24 def register_error
23 25 msg = _('There was an error while looking for your contact list. Please, try again')
24   - self.update_attributes(:fetched => true, :error_fetching => msg)
  26 + self.fetched = true
  27 + self.error_fetching = msg
  28 + self.save!
25 29 end
26 30  
27 31 end
... ...
app/models/create_enterprise.rb
... ... @@ -36,14 +36,18 @@ class CreateEnterprise &lt; Task
36 36 validates_presence_of :reject_explanation, :if => (lambda { |record| record.status == Task::Status::CANCELLED } )
37 37 xss_terminate :only => [ :acronym, :address, :contact_person, :contact_phone, :economic_activity, :legal_form, :management_information, :name ], :on => 'validation'
38 38  
39   - def validate
  39 + validate :validator_correct_region
  40 + validate :not_used_identifier
40 41  
  42 + def validator_correct_region
41 43 if self.region && self.target
42 44 unless self.region.validators.include?(self.target) || self.target_type == "Environment"
43 45 self.errors.add(:target, _('{fn} is not a validator for the chosen region').fix_i18n)
44 46 end
45 47 end
  48 + end
46 49  
  50 + def not_used_identifier
47 51 if self.status != Task::Status::CANCELLED && self.identifier && Profile.exists?(:identifier => self.identifier)
48 52 self.errors.add(:identifier, _('{fn} is already being as identifier by another enterprise, organization or person.').fix_i18n)
49 53 end
... ... @@ -165,18 +169,18 @@ class CreateEnterprise &lt; Task
165 169 end
166 170  
167 171 def task_finished_message
168   - __('Your request for registering the enterprise "%{enterprise}" was approved. You can access %{environment} now and provide start providing all relevant information your new enterprise.') % { :enterprise => self.name, :environment => self.environment }
  172 + _('Your request for registering the enterprise "%{enterprise}" was approved. You can access %{environment} now and provide start providing all relevant information your new enterprise.') % { :enterprise => self.name, :environment => self.environment }
169 173 end
170 174  
171 175 def task_cancelled_message
172   - __("Your request for registering the enterprise %{enterprise} at %{environment} was NOT approved by the validator organization. The following explanation was given: \n\n%{explanation}") % { :enterprise => self.name, :environment => self.environment, :explanation => self.reject_explanation }
  176 + _("Your request for registering the enterprise %{enterprise} at %{environment} was NOT approved by the validator organization. The following explanation was given: \n\n%{explanation}") % { :enterprise => self.name, :environment => self.environment, :explanation => self.reject_explanation }
173 177 end
174 178  
175 179 def target_notification_message
176 180 msg = ""
177   - msg << __("Enterprise \"%{enterprise}\" just requested to enter %{environment}. You have to approve or reject it through the \"Pending Validations\" section in your control panel.\n") % { :enterprise => self.name, :environment => self.environment }
  181 + msg << _("Enterprise \"%{enterprise}\" just requested to enter %{environment}. You have to approve or reject it through the \"Pending Validations\" section in your control panel.\n") % { :enterprise => self.name, :environment => self.environment }
178 182 msg << "\n"
179   - msg << __("The data provided by the enterprise was the following:\n") << "\n"
  183 + msg << _("The data provided by the enterprise was the following:\n") << "\n"
180 184  
181 185  
182 186 msg << (_("Name: %s") % self.name) << "\n"
... ... @@ -186,12 +190,12 @@ class CreateEnterprise &lt; Task
186 190 msg << (_("Foundation Year: %d") % self.foundation_year) << "\n" unless self.foundation_year.blank?
187 191 msg << (_("Economic activity: %s") % self.economic_activity) << "\n"
188 192  
189   - msg << __("Information about enterprise's management:\n") << self.management_information.to_s << "\n"
  193 + msg << _("Information about enterprise's management:\n") << self.management_information.to_s << "\n"
190 194  
191 195 msg << (_("Contact phone: %s") % self.contact_phone) << "\n"
192 196 msg << (_("Contact person: %s") % self.contact_person) << "\n"
193 197  
194   - msg << __('CreateEnterprise|Identifier')
  198 + msg << _('CreateEnterprise|Identifier')
195 199  
196 200 msg
197 201 end
... ...
app/models/disabled_enterprise_message_block.rb
1 1 class DisabledEnterpriseMessageBlock < Block
2 2  
3 3 def self.description
4   - __('"Disabled enterprise" message')
  4 + _('"Disabled enterprise" message')
5 5 end
6 6  
7 7 def help
8   - __('Shows a message for disabled enterprises.')
  8 + _('Shows a message for disabled enterprises.')
9 9 end
10 10  
11 11 def default_title
... ... @@ -14,7 +14,7 @@ class DisabledEnterpriseMessageBlock &lt; Block
14 14  
15 15 def content(args={})
16 16 message = self.owner.environment.message_for_disabled_enterprise || ''
17   - lambda do
  17 + lambda do |_|
18 18 render :file => 'blocks/disabled_enterprise_message', :locals => {:message => message}
19 19 end
20 20 end
... ...
app/models/doc_item.rb
... ... @@ -31,7 +31,7 @@ class DocItem
31 31 search_path.unshift("/designs/themes/#{theme}#{translation}") # higher priority
32 32 search_path.push("/designs/themes/#{theme}#{image}") # lower priority
33 33 end
34   - search_path.find {|file| File.exist?("#{RAILS_ROOT}/public#{file}") }
  34 + search_path.find {|file| File.exist?(Rails.root.join('public', file[1..-1])) }
35 35 end
36 36  
37 37 end
... ...
app/models/doc_section.rb
1 1 class DocSection < DocItem
2 2  
3 3 def self.root_dir
4   - @root_dir ||= File.join(RAILS_ROOT, 'doc', 'noosfero')
  4 + @root_dir ||= Rails.root.join('doc', 'noosfero')
5 5 end
6 6  
7 7 def items
... ...
app/models/domain.rb
  1 +require 'noosfero/multi_tenancy'
  2 +
1 3 class Domain < ActiveRecord::Base
2 4  
  5 + attr_accessible :name, :owner
  6 +
3 7 # relationships
4 8 ###############
5 9  
... ... @@ -15,7 +19,9 @@ class Domain &lt; ActiveRecord::Base
15 19 # checks validations that could not be expressed using Rails' predefined
16 20 # validations. In particular:
17 21 # * <tt>name</tt> must not start with 'www.'
18   - def validate
  22 + validate :no_www
  23 +
  24 + def no_www
19 25 if self.name =~ /^www\./
20 26 self.errors.add(:name, _('{fn} must not start with www.').fix_i18n)
21 27 end
... ...
app/models/email_activation.rb
1 1 class EmailActivation < Task
2 2  
3 3 validates_presence_of :requestor_id, :target_id
  4 + validate :already_requested, :on => :create
4 5  
5 6 alias :environment :target
6 7 alias :person :requestor
7 8  
8   - def validate_on_create
  9 + def already_requested
9 10 if !self.requestor.nil? && self.requestor.user.email_activation_pending?
10   - self.errors.add_to_base(_('You have already requested activation of your mailbox.'))
  11 + self.errors.add(:base, _('You have already requested activation of your mailbox.'))
11 12 end
12 13 end
13 14  
... ... @@ -33,7 +34,7 @@ class EmailActivation &lt; Task
33 34  
34 35 # :nodoc:
35 36 def after_finish
36   - User::Mailer.deliver_activation_email_notify(person.user)
  37 + UserMailer.activation_email_notify(person.user).deliver
37 38 end
38 39  
39 40 def sends_email?
... ...
app/models/enterprise.rb
... ... @@ -17,12 +17,12 @@ class Enterprise &lt; Organization
17 17 has_and_belongs_to_many :fans, :class_name => 'Person', :join_table => 'favorite_enteprises_people'
18 18  
19 19 def product_categories
20   - products.includes(:product_category).map{|p| p.category_full_name}.compact
  20 + ProductCategory.by_enterprise(self)
21 21 end
22 22  
23 23 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code')
24 24  
25   - settings_items :organization_website, :historic_and_current_context, :activities_short_description, :zip_code, :city, :state, :country
  25 + settings_items :organization_website, :historic_and_current_context, :activities_short_description
26 26 settings_items :products_per_catalog_page, :type => :integer, :default => 6
27 27  
28 28 extend SetProfileRegionFromCityState::ClassMethods
... ... @@ -54,8 +54,9 @@ class Enterprise &lt; Organization
54 54 super + FIELDS
55 55 end
56 56  
57   - def validate
58   - super
  57 + validate :presence_of_required_fieds
  58 +
  59 + def presence_of_required_fieds
59 60 self.required_fields.each do |field|
60 61 if self.send(field).blank?
61 62 self.errors.add_on_blank(field)
... ... @@ -97,14 +98,18 @@ class Enterprise &lt; Organization
97 98 save
98 99 end
99 100  
  101 + def activation_task
  102 + self.tasks.where(:type => 'EnterpriseActivation').first
  103 + end
  104 +
100 105 def enable(owner)
101 106 return if enabled
102   - affiliate(owner, Profile::Roles.all_roles(environment.id))
103   - update_attribute(:enabled,true)
104   - if environment.replace_enterprise_template_when_enable
105   - apply_template(template)
106   - end
107   - save_without_validation!
  107 + # must be set first for the following to work
  108 + self.enabled = true
  109 + self.affiliate owner, Profile::Roles.all_roles(self.environment.id) if owner
  110 + self.apply_template template if self.environment.replace_enterprise_template_when_enable
  111 + self.activation_task.update_attribute :status, Task::Status::FINISHED rescue nil
  112 + self.save(:validate => false)
108 113 end
109 114  
110 115 def question
... ... @@ -168,7 +173,7 @@ class Enterprise &lt; Organization
168 173 alias_method_chain :template, :inactive_enterprise
169 174  
170 175 def control_panel_settings_button
171   - {:title => __('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
  176 + {:title => _('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
172 177 end
173 178  
174 179 settings_items :enable_contact_us, :type => :boolean, :default => true
... ... @@ -178,7 +183,7 @@ class Enterprise &lt; Organization
178 183 end
179 184  
180 185 def control_panel_settings_button
181   - {:title => __('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
  186 + {:title => _('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'}
182 187 end
183 188  
184 189 def create_product?
... ...
app/models/enterprise_activation.rb
1 1 class EnterpriseActivation < Task
2 2  
3   - class RequestorRequired < Exception; end
  3 + alias :person :requestor
  4 + alias :person= :requestor=
4 5  
5   - settings_items :enterprise_id, :integer
  6 + alias :enterprise :target
  7 + alias :enterprise= :target=
6 8  
7   - validates_presence_of :enterprise_id
8   -
9   - def enterprise
10   - Enterprise.find(enterprise_id)
11   - end
12   -
13   - def enterprise=(ent)
14   - self.enterprise_id = ent.id
15   - end
  9 + validates_presence_of :enterprise
16 10  
17 11 def perform
18   - raise EnterpriseActivation::RequestorRequired if requestor.nil?
19   - self.enterprise.enable(requestor)
  12 + self.enterprise.enable self.requestor
20 13 end
21 14  
22 15 def title
... ... @@ -28,15 +21,27 @@ class EnterpriseActivation &lt; Task
28 21 end
29 22  
30 23 def information
31   - {:message => _('%{requestor} wants to activate enterprise %{linked_subject}.')}
  24 + if self.requestor
  25 + {:message => _('%{requestor} wants to activate enterprise %{linked_subject}.')}
  26 + else
  27 + {:message => _('Pending activation of enterprise %{linked_subject}.')}
  28 + end
32 29 end
33 30  
34 31 def icon
35   - {:type => :profile_image, :profile => requestor, :url => requestor.url}
  32 + if self.requestor
  33 + {:type => :profile_image, :profile => self.requestor, :url => self.requestor.url}
  34 + else
  35 + {:type => :profile_image, :profile => self.enterprise, :url => self.enterprise.url}
  36 + end
36 37 end
37 38  
38 39 def target_notification_description
39   - _('%{requestor} wants to activate enterprise %{enterprise}.') % {:requestor => requestor.name, :enterprise => enterprise.name}
  40 + if self.requestor
  41 + _('%{requestor} wants to activate enterprise %{enterprise}.') % {:requestor => self.requestor.name, :enterprise => self.enterprise.name}
  42 + else
  43 + _('Pending activation of enterprise %{enterprise}.') % {:enterprise => self.enterprise.name}
  44 + end
40 45 end
41 46  
42 47 end
... ...
app/models/enterprise_homepage.rb
... ... @@ -5,7 +5,7 @@ class EnterpriseHomepage &lt; Article
5 5 end
6 6  
7 7 def self.short_description
8   - __('Enterprise homepage')
  8 + _('Enterprise homepage')
9 9 end
10 10  
11 11 def self.description
... ... @@ -18,7 +18,7 @@ class EnterpriseHomepage &lt; Article
18 18  
19 19 def to_html(options = {})
20 20 enterprise_homepage = self
21   - lambda do
  21 + proc do
22 22 extend EnterpriseHomepageHelper
23 23 extend CatalogHelper
24 24 catalog_load_index :page => 1, :show_categories => false
... ... @@ -26,6 +26,11 @@ class EnterpriseHomepage &lt; Article
26 26 end
27 27 end
28 28  
  29 + # disable cache because of products
  30 + def cache_key params = {}, the_profile = nil, language = 'en'
  31 + rand
  32 + end
  33 +
29 34 def can_display_hits?
30 35 false
31 36 end
... ...
app/models/enterprises_block.rb
1 1 class EnterprisesBlock < ProfileListBlock
2 2  
3 3 def default_title
4   - n__('{#} enterprise', '{#} enterprises', profile_count)
  4 + n_('{#} enterprise', '{#} enterprises', profile_count)
5 5 end
6 6  
7 7 def help
8   - __('This block displays the enterprises where this user works.')
  8 + _('This block displays the enterprises where this user works.')
9 9 end
10 10  
11 11 def self.description
12   - __('Enterprises')
  12 + _('Enterprises')
13 13 end
14 14  
15 15 def footer
16 16 owner = self.owner
17 17 case owner
18 18 when Profile
19   - lambda do
  19 + proc do
20 20 link_to s_('enterprises|View all'), :profile => owner.identifier, :controller => 'profile', :action => 'enterprises'
21 21 end
22 22 when Environment
23   - lambda do
  23 + proc do
24 24 link_to s_('enterprises|View all'), :controller => 'search', :action => 'assets', :asset => 'enterprises'
25 25 end
26 26 else
... ...
app/models/environment.rb
... ... @@ -3,6 +3,8 @@
3 3 # domains.
4 4 class Environment < ActiveRecord::Base
5 5  
  6 + attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound
  7 +
6 8 has_many :users
7 9  
8 10 self.partial_updates = false
... ... @@ -91,9 +93,9 @@ class Environment &lt; ActiveRecord::Base
91 93 def self.available_features
92 94 {
93 95 'disable_asset_articles' => _('Disable search for articles '),
94   - 'disable_asset_enterprises' => __('Disable search for enterprises'),
  96 + 'disable_asset_enterprises' => _('Disable search for enterprises'),
95 97 'disable_asset_people' => _('Disable search for people'),
96   - 'disable_asset_communities' => __('Disable search for communities'),
  98 + 'disable_asset_communities' => _('Disable search for communities'),
97 99 'disable_asset_products' => _('Disable search for products'),
98 100 'disable_asset_events' => _('Disable search for events'),
99 101 'disable_categories' => _('Disable categories'),
... ... @@ -104,11 +106,11 @@ class Environment &lt; ActiveRecord::Base
104 106 'disable_contact_person' => _('Disable contact for people'),
105 107 'disable_contact_community' => _('Disable contact for groups/communities'),
106 108  
107   - 'products_for_enterprises' => __('Enable products for enterprises'),
108   - 'enterprise_registration' => __('Enterprise registration'),
109   - 'enterprise_activation' => __('Enable activation of enterprises'),
110   - 'enterprises_are_disabled_when_created' => __('Enterprises are disabled when created'),
111   - 'enterprises_are_validated_when_created' => __('Enterprises are validated when created'),
  109 + 'products_for_enterprises' => _('Enable products for enterprises'),
  110 + 'enterprise_registration' => _('Enterprise registration'),
  111 + 'enterprise_activation' => _('Enable activation of enterprises'),
  112 + 'enterprises_are_disabled_when_created' => _('Enterprises are disabled when created'),
  113 + 'enterprises_are_validated_when_created' => _('Enterprises are validated when created'),
112 114  
113 115 'media_panel' => _('Media panel in WYSIWYG editor'),
114 116 'select_preferred_domain' => _('Select preferred domains per profile'),
... ... @@ -145,6 +147,18 @@ class Environment &lt; ActiveRecord::Base
145 147 end
146 148 validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true
147 149  
  150 + def self.signup_redirection_options
  151 + {
  152 + 'keep_on_same_page' => _('Stays on the same page the user was before signup.'),
  153 + 'site_homepage' => _('Redirects the user to the environment homepage.'),
  154 + 'user_profile_page' => _('Redirects the user to his profile page.'),
  155 + 'user_homepage' => _('Redirects the user to his homepage.'),
  156 + 'user_control_panel' => _('Redirects the user to his control panel.')
  157 + }
  158 + end
  159 + validates_inclusion_of :redirection_after_signup, :in => Environment.signup_redirection_options.keys, :allow_nil => true
  160 +
  161 +
148 162 # #################################################
149 163 # Relationships and applied behaviour
150 164 # #################################################
... ... @@ -161,6 +175,8 @@ class Environment &lt; ActiveRecord::Base
161 175  
162 176 # "left" area
163 177 env.boxes[1].blocks << LoginBlock.new
  178 + # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  179 + # the Noosfero core soon, see ActionItem3045
164 180 env.boxes[1].blocks << EnvironmentStatisticsBlock.new
165 181 env.boxes[1].blocks << RecentDocumentsBlock.new
166 182  
... ... @@ -185,6 +201,8 @@ class Environment &lt; ActiveRecord::Base
185 201  
186 202 has_many :product_categories, :conditions => { :type => 'ProductCategory'}
187 203 has_many :regions
  204 + has_many :states
  205 + has_many :cities
188 206  
189 207 has_many :roles, :dependent => :destroy
190 208  
... ... @@ -344,19 +362,22 @@ class Environment &lt; ActiveRecord::Base
344 362 features.delete_if{ |k, v| !self.enabled?(k) }
345 363 end
346 364  
  365 + DEFAULT_FEATURES = %w(
  366 + disable_asset_products
  367 + disable_gender_icon
  368 + products_for_enterprises
  369 + disable_select_city_for_contact
  370 + enterprise_registration
  371 + media_panel
  372 + organizations_are_moderated_by_default
  373 + show_balloon_with_profile_links_when_clicked
  374 + show_zoom_button_on_article_images
  375 + use_portal_community
  376 + )
  377 +
347 378 before_create :enable_default_features
348 379 def enable_default_features
349   - %w(
350   - disable_asset_products
351   - disable_gender_icon
352   - products_for_enterprises
353   - disable_select_city_for_contact
354   - enterprise_registration
355   - media_panel
356   - organizations_are_moderated_by_default
357   - show_balloon_with_profile_links_when_clicked
358   - use_portal_community
359   - ).each do |feature|
  380 + DEFAULT_FEATURES.each do |feature|
360 381 enable(feature, false)
361 382 end
362 383 end
... ... @@ -400,22 +421,6 @@ class Environment &lt; ActiveRecord::Base
400 421 self.settings[:organization_approval_method] = actual_value
401 422 end
402 423  
403   - def terminology
404   - if self.settings[:terminology]
405   - self.settings[:terminology].constantize.instance
406   - else
407   - Noosfero.terminology
408   - end
409   - end
410   -
411   - def terminology=(value)
412   - if value
413   - self.settings[:terminology] = value.class.name
414   - else
415   - self.settings[:terminology] = nil
416   - end
417   - end
418   -
419 424 def custom_person_fields
420 425 self.settings[:custom_person_fields].nil? ? {} : self.settings[:custom_person_fields]
421 426 end
... ... @@ -598,7 +603,7 @@ class Environment &lt; ActiveRecord::Base
598 603 # only one environment can be the default one
599 604 validates_uniqueness_of :is_default, :if => (lambda do |environment| environment.is_default? end), :message => N_('Only one Virtual Community can be the default one')
600 605  
601   - validates_format_of :contact_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |record| ! record.contact_email.blank? })
  606 + validates_format_of :contact_email, :noreply_email, :with => Noosfero::Constants::EMAIL_FORMAT, :allow_blank => true
602 607  
603 608 xss_terminate :only => [ :message_for_disabled_enterprise ], :with => 'white_list', :on => 'validation'
604 609  
... ... @@ -606,7 +611,10 @@ class Environment &lt; ActiveRecord::Base
606 611 validates_numericality_of :reports_lower_bound, :allow_nil => false, :only_integer => true, :greater_than_or_equal_to => 0
607 612  
608 613 include WhiteListFilter
609   - filter_iframes :message_for_disabled_enterprise, :whitelist => lambda { trusted_sites_for_iframe }
  614 + filter_iframes :message_for_disabled_enterprise
  615 + def iframe_whitelist
  616 + trusted_sites_for_iframe
  617 + end
610 618  
611 619 # #################################################
612 620 # Business logic in general
... ... @@ -635,6 +643,10 @@ class Environment &lt; ActiveRecord::Base
635 643 domain
636 644 end
637 645  
  646 + def admin_url
  647 + { :controller => 'admin_panel', :action => 'index' }
  648 + end
  649 +
638 650 def top_url
639 651 url = 'http://'
640 652 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
... ... @@ -656,9 +668,7 @@ class Environment &lt; ActiveRecord::Base
656 668 has_many :tags, :through => :articles
657 669  
658 670 def tag_counts
659   - options = Article.find_options_for_tag_counts.merge(:conditions => ['profiles.environment_id = ?', self.id])
660   - options[:joins] = options[:joins] + ' LEFT OUTER JOIN profiles on profiles.id = articles.profile_id'
661   - Tag.find(:all, options).inject({}) do |memo,tag|
  671 + articles.tag_counts.inject({}) do |memo,tag|
662 672 memo[tag.name] = tag.count
663 673 memo
664 674 end
... ... @@ -785,37 +795,74 @@ class Environment &lt; ActiveRecord::Base
785 795 end
786 796  
787 797 def notification_emails
788   - [contact_email.blank? ? nil : contact_email].compact + admins.map(&:email)
  798 + [noreply_email.blank? ? nil : noreply_email].compact + admins.map(&:email)
789 799 end
790 800  
791 801 after_create :create_templates
792 802  
793 803 def create_templates
794   - pre = self.name.to_slug + '_'
795   - ent_id = Enterprise.create!(:name => 'Enterprise template', :identifier => pre + 'enterprise_template', :environment => self, :visible => false, :is_template => true).id
796   - inactive_enterprise_tmpl = Enterprise.create!(:name => 'Inactive Enterprise template', :identifier => pre + 'inactive_enterprise_template', :environment => self, :visible => false, :is_template => true)
797   - com_id = Community.create!(:name => 'Community template', :identifier => pre + 'community_template', :environment => self, :visible => false, :is_template => true).id
  804 + prefix = self.name.to_slug + '_'
  805 +
  806 + enterprise_template = Enterprise.new(
  807 + :name => 'Enterprise template',
  808 + :identifier => prefix + 'enterprise_template'
  809 + )
  810 +
  811 + inactive_enterprise_template = Enterprise.new(
  812 + :name => 'Inactive Enterprise template',
  813 + :identifier => prefix + 'inactive_enterprise_template'
  814 + )
  815 +
  816 + community_template = Community.new(
  817 + :name => 'Community template',
  818 + :identifier => prefix + 'community_template'
  819 + )
  820 +
  821 + [
  822 + enterprise_template,
  823 + inactive_enterprise_template,
  824 + community_template
  825 + ].each do |profile|
  826 + profile.is_template = true
  827 + profile.visible = false
  828 + profile.environment = self
  829 + profile.save!
  830 + end
  831 +
798 832 pass = Digest::MD5.hexdigest rand.to_s
799   - user = User.create!(:login => (pre + 'person_template'), :email => (pre + 'template@template.noo'), :password => pass, :password_confirmation => pass, :environment => self).person
800   - user.update_attributes(:visible => false, :name => "Person template", :is_template => true)
801   - usr_id = user.id
802   - self.settings[:enterprise_template_id] = ent_id
803   - self.inactive_enterprise_template = inactive_enterprise_tmpl
804   - self.settings[:community_template_id] = com_id
805   - self.settings[:person_template_id] = usr_id
  833 + user = User.new(:login => (prefix + 'person_template'), :email => (prefix + 'template@template.noo'), :password => pass, :password_confirmation => pass)
  834 + user.environment = self
  835 + user.save!
  836 +
  837 + person_template = user.person
  838 + person_template.name = "Person template"
  839 + person_template.is_template = true
  840 + person_template.visible = false
  841 + person_template.save!
  842 +
  843 + self.enterprise_template = enterprise_template
  844 + self.inactive_enterprise_template = inactive_enterprise_template
  845 + self.community_template = community_template
  846 + self.person_template = person_template
806 847 self.save!
807 848 end
808 849  
809 850 after_create :create_default_licenses
810 851 def create_default_licenses
811   - License.create!(:name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode', :environment => self)
812   - License.create!(:name => 'CC (by-nd)', :url => 'http://creativecommons.org/licenses/by-nd/3.0/legalcode', :environment => self)
813   - License.create!(:name => 'CC (by-sa)', :url => 'http://creativecommons.org/licenses/by-sa/3.0/legalcode', :environment => self)
814   - License.create!(:name => 'CC (by-nc)', :url => 'http://creativecommons.org/licenses/by-nc/3.0/legalcode', :environment => self)
815   - License.create!(:name => 'CC (by-nc-nd)', :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode', :environment => self)
816   - License.create!(:name => 'CC (by-nc-sa)', :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode', :environment => self)
817   - License.create!(:name => 'Free Art', :url => 'http://artlibre.org/licence/lal/en', :environment => self)
818   - License.create!(:name => 'GNU FDL', :url => 'http://www.gnu.org/licenses/fdl-1.3.txt', :environment => self)
  852 + [
  853 + { :name => 'CC (by)', :url => 'http://creativecommons.org/licenses/by/3.0/legalcode'},
  854 + { :name => 'CC (by-nd)', :url => 'http://creativecommons.org/licenses/by-nd/3.0/legalcode'},
  855 + { :name => 'CC (by-sa)', :url => 'http://creativecommons.org/licenses/by-sa/3.0/legalcode'},
  856 + { :name => 'CC (by-nc)', :url => 'http://creativecommons.org/licenses/by-nc/3.0/legalcode'},
  857 + { :name => 'CC (by-nc-nd)', :url => 'http://creativecommons.org/licenses/by-nc-nd/3.0/legalcode'},
  858 + { :name => 'CC (by-nc-sa)', :url => 'http://creativecommons.org/licenses/by-nc-sa/3.0/legalcode'},
  859 + { :name => 'Free Art', :url => 'http://artlibre.org/licence/lal/en'},
  860 + { :name => 'GNU FDL', :url => 'http://www.gnu.org/licenses/fdl-1.3.txt'},
  861 + ].each do |data|
  862 + license = License.new(data)
  863 + license.environment = self
  864 + license.save!
  865 + end
819 866 end
820 867  
821 868 def highlighted_products_with_image(options = {})
... ...
app/models/environment_mailing.rb
... ... @@ -1,25 +0,0 @@
1   -class EnvironmentMailing < Mailing
2   -
3   - def recipients(offset=0, limit=100)
4   - source.people.all(:order => :id, :offset => offset, :limit => limit, :joins => "LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)", :conditions => { "m.person_id" => nil })
5   - end
6   -
7   - def each_recipient
8   - offset = 0
9   - limit = 100
10   - while !(people = recipients(offset, limit)).empty?
11   - people.each do |person|
12   - yield person
13   - end
14   - offset = offset + limit
15   - end
16   - end
17   -
18   - def signature_message
19   - _('Sent by %s.') % source.name
20   - end
21   -
22   - def url
23   - source.top_url
24   - end
25   -end
app/models/environment_statistics_block.rb
  1 +# TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
  2 +# the Noosfero core soon, see ActionItem3045
  3 +
1 4 class EnvironmentStatisticsBlock < Block
2 5  
3 6 def self.description
4   - _('Environment stastistics')
  7 + _('Environment stastistics (DEPRECATED)')
5 8 end
6 9  
7 10 def default_title
... ... @@ -20,9 +23,9 @@ class EnvironmentStatisticsBlock &lt; Block
20 23 info = []
21 24 info << (n_('One user', '%{num} users', users) % { :num => users })
22 25 unless owner.enabled?('disable_asset_enterprises')
23   - info << (n__('One enterprise', '%{num} enterprises', enterprises) % { :num => enterprises })
  26 + info << (n_('One enterprise', '%{num} enterprises', enterprises) % { :num => enterprises })
24 27 end
25   - info << (n__('One community', '%{num} communities', communities) % { :num => communities })
  28 + info << (n_('One community', '%{num} communities', communities) % { :num => communities })
26 29  
27 30 block_title(title) + content_tag('ul', info.map {|item| content_tag('li', item) }.join("\n"))
28 31 end
... ...
app/models/event.rb
  1 +require 'noosfero/translatable_content'
  2 +require 'builder'
  3 +
1 4 class Event < Article
2 5  
  6 + attr_accessible :start_date, :end_date, :link, :address
  7 +
3 8 def self.type_name
4 9 _('Event')
5 10 end
... ... @@ -29,30 +34,30 @@ class Event &lt; Article
29 34 end
30 35 end
31 36  
32   - named_scope :by_day, lambda { |date|
  37 + scope :by_day, lambda { |date|
33 38 { :conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}],
34 39 :order => 'start_date ASC'
35 40 }
36 41 }
37 42  
38   - named_scope :next_events_from_month, lambda { |date|
  43 + scope :next_events_from_month, lambda { |date|
39 44 date_temp = date.strftime("%Y-%m-%d")
40 45 { :conditions => ["start_date >= ?","#{date_temp}"],
41   - :limit => 10,
42 46 :order => 'start_date ASC'
43 47 }
44 48 }
45 49  
46   - named_scope :by_month, lambda { |date|
47   - date_temp = date.strftime("%Y-%m")
  50 + scope :by_month, lambda { |date|
48 51 { :conditions => ["EXTRACT(YEAR FROM start_date) = ? AND EXTRACT(MONTH FROM start_date) = ?",date.year,date.month],
49   - :limit => 10,
50 52 :order => 'start_date ASC'
51 53 }
52 54 }
53 55  
54 56 include WhiteListFilter
55   - filter_iframes :body, :link, :address, :whitelist => lambda { profile && profile.environment && profile.environment.trusted_sites_for_iframe }
  57 + filter_iframes :body, :link, :address
  58 + def iframe_whitelist
  59 + profile && profile.environment && profile.environment.trusted_sites_for_iframe
  60 + end
56 61  
57 62 def self.description
58 63 _('A calendar event.')
... ... @@ -66,7 +71,7 @@ class Event &lt; Article
66 71 'event'
67 72 end
68 73  
69   - named_scope :by_range, lambda { |range| {
  74 + scope :by_range, lambda { |range| {
70 75 :conditions => [
71 76 'start_date BETWEEN :start_day AND :end_day OR end_date BETWEEN :start_day AND :end_day',
72 77 { :start_day => range.first, :end_day => range.last }
... ... @@ -96,29 +101,27 @@ class Event &lt; Article
96 101 # FIXME this shouldn't be needed
97 102 include ActionView::Helpers::TagHelper
98 103 include ActionView::Helpers::UrlHelper
99   - include ActionController::UrlWriter
100 104 include DatesHelper
101 105  
102 106 def to_html(options = {})
103 107  
104 108 result = ''
105   - html = Builder::XmlMarkup.new(:target => result)
  109 + html = ::Builder::XmlMarkup.new(:target => result)
106 110  
107 111 html.div(:class => 'event-info' ) {
108   -
109 112 html.ul(:class => 'event-data' ) {
110 113 html.li(:class => 'event-dates' ) {
111 114 html.span _('When:')
112 115 html.text! show_period(start_date, end_date)
113   - }
  116 + } if start_date.present? || end_date.present?
114 117 html.li {
115 118 html.span _('URL:')
116 119 html.a(self.link || "", 'href' => self.link || "")
117   - }
  120 + } if self.link.present?
118 121 html.li {
119 122 html.span _('Address:')
120 123 html.text! self.address || ""
121   - }
  124 + } if self.address.present?
122 125 }
123 126  
124 127 # TODO: some good soul, please clean this ugly hack:
... ...
app/models/external_feed.rb
... ... @@ -5,11 +5,13 @@ class ExternalFeed &lt; ActiveRecord::Base
5 5 validates_presence_of :address, :if => lambda {|efeed| efeed.enabled}
6 6 validates_uniqueness_of :blog_id
7 7  
8   - named_scope :enabled, :conditions => { :enabled => true }
9   - named_scope :expired, lambda {
  8 + scope :enabled, :conditions => { :enabled => true }
  9 + scope :expired, lambda {
10 10 { :conditions => ['(fetched_at is NULL) OR (fetched_at < ?)', Time.now - FeedUpdater.update_interval] }
11 11 }
12 12  
  13 + attr_accessible :address, :enabled
  14 +
13 15 def add_item(title, link, date, content)
14 16 doc = Hpricot(content)
15 17 doc.search('*').each do |p|
... ... @@ -20,7 +22,14 @@ class ExternalFeed &lt; ActiveRecord::Base
20 22 end
21 23 content = doc.to_s
22 24  
23   - article = TinyMceArticle.new(:name => title, :profile => blog.profile, :body => content, :published_at => date, :source => link, :profile => blog.profile, :parent => blog)
  25 + article = TinyMceArticle.new
  26 + article.name = title
  27 + article.profile = blog.profile
  28 + article.body = content
  29 + article.published_at = date
  30 + article.source = link
  31 + article.profile = blog.profile
  32 + article.parent = blog
24 33 unless blog.children.exists?(:slug => article.slug)
25 34 article.save!
26 35 article.delay.create_activity
... ...
app/models/fans_block.rb
... ... @@ -5,7 +5,7 @@ class FansBlock &lt; ProfileListBlock
5 5 end
6 6  
7 7 def default_title
8   - n__('{#} fan', '{#} fans', profile_count)
  8 + n_('{#} fan', '{#} fans', profile_count)
9 9 end
10 10  
11 11 def help
... ... @@ -14,7 +14,7 @@ class FansBlock &lt; ProfileListBlock
14 14  
15 15 def footer
16 16 profile = self.owner
17   - lambda do
  17 + proc do
18 18 link_to _('View all'), :profile => profile.identifier, :controller =>
19 19 'profile', :action => 'fans'
20 20 end
... ...