Commit 6daf9ba27c9135578f8156e49dfa62f574702d89

Authored by Victor Costa
2 parents bb996411 c5265b67

Merge branch 'master' into rails3-custom_fields

Conflicts:
	app/helpers/application_helper.rb
	app/views/profile/_person_profile.html.erb
Showing 1380 changed files with 86898 additions and 157983 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 1380 files displayed.

.ackrc
1 1 --ignore-dir=log
2 2 --ignore-dir=tmp
3 3 --ignore-dir=pkg
  4 +--ignore-dir=public/javascripts/cache
  5 +--ignore-dir=public/stylesheets/cache
... ...
AUTHORS.md
... ... @@ -40,7 +40,9 @@ Alessandro Palmeira + João M. M. Silva <alessandro.palmeira@gmail.com>
40 40 Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
41 41 Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
42 42 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
  43 +analosnak <analosnak@gmail.com>
43 44 Ana Losnak <analosnak@gmail.com>
  45 +Andre Bernardes <andrebsguedes@gmail.com>
44 46 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
45 47 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
46 48 Antonio Terceiro <terceiro@colivre.coop.br>
... ... @@ -80,7 +82,6 @@ Carlos Morais + Diego Araújo &lt;diegoamc90@gmail.com&gt;
80 82 Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
81 83 Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
82 84 Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
83   -Daniela Feitosa <dani@dohko.(none)>
84 85 Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
85 86 Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
86 87 Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
... ... @@ -118,7 +119,6 @@ Diego Araújo + Renan Teruo &lt;diegoamc90@gmail.com&gt;
118 119 Diego Araujo + Rodrigo Souto + Rafael Manzo <rr.manzo@gmail.com>
119 120 Diego + Jefferson <diegoamc90@gmail.com>
120 121 Diego Martinez <diegoamc90@gmail.com>
121   -Diego Martinez <diego@diego-K55A.(none)>
122 122 Diego + Renan <renanteruoc@gmail.com>
123 123 Eduardo Tourinho Edington <eduardo.edington@serpro.gov.br>
124 124 Evandro Jr <evandrojr@gmail.com>
... ... @@ -132,6 +132,7 @@ Francisco Marcelo de Araújo Lima Júnior &lt;maljunior@gmail.com&gt;
132 132 Gabriela Navarro <navarro1703@gmail.com>
133 133 Grazieno Pellegrino <grazieno@gmail.com>
134 134 Gust <darksshades@hotmail.com>
  135 +Hebert Douglas <hebertdougl@gmail.com>
135 136 Hugo Melo <hugo@riseup.net>
136 137 Isaac Canan <isaac@intelletto.com.br>
137 138 Italo Valcy <italo@dcc.ufba.br>
... ... @@ -193,9 +194,11 @@ Luis David Aguilar Carlos &lt;ludwig9003@gmail.com&gt;
193 194 Luiz Fernando de Freitas Matos <luiz@luizff.matos@gmail.com>
194 195 Marcos Ramos <ms.ramos@outlook.com>
195 196 Martín Olivera <molivera@solar.org.ar>
  197 +Michal Čihař <michal@cihar.com>
196 198 Moises Machado <moises@colivre.coop.br>
197 199 Naíla Alves <naila@colivre.coop.br>
198 200 Nanda Lopes <nanda.listas+psl@gmail.com>
  201 +Parley Martins <parleypachecomartins@gmail.com>
199 202 Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>
200 203 Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>
201 204 Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>
... ... @@ -218,6 +221,7 @@ Rafael Reggiani Manzo + João M. M. da Silva &lt;rr.manzo@gmail.com&gt;
218 221 Rafael Reggiani Manzo <rr.manzo@gmail.com>
219 222 Raphaël Rousseau <raph@r4f.org>
220 223 Raquel Lira <raquel.lira@gmail.com>
  224 +Raquel <rcordioli@gmail.com>
221 225 Renan Teruo + Caio Salgado <renanteruoc@gmail.com>
222 226 Renan Teruoc + Diego Araujo <renanteruoc@gmail.com>
223 227 Renan Teruo + Diego Araujo <renanteruoc@gmail.com>
... ... @@ -225,11 +229,13 @@ Renan Teruo + Diego Araújo &lt;renanteruoc@gmail.com&gt;
225 229 Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
226 230 Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
227 231 Rodrigo Souto + Ana Losnak + Daniel Bucher + Caio Almeida + Leandro Nunes + Daniela Feitosa + Mariel Zasso <noosfero-br@listas.softwarelivre.org>
228   -Rodrigo Souto <diguliu@gmail.com>
229 232 Rodrigo Souto <rodrigo@colivre.coop.br>
230 233 Ronny Kursawe <kursawe.ronny@googlemail.com>
231 234 root <root@debian.sdr.serpro>
232 235 Samuel R. C. Vale <srcvale@holoscopio.com>
  236 +Tallys Martins <tallysmartins@gmail.com>
  237 +tallys <tallys@tallys.(none)>
  238 +Thiago Zoroastro <thiago.zoroastro@bol.com.br>
233 239 Valessio Brito <contato@valessiobrito.com.br>
234 240 Valessio Brito <contato@valessiobrito.info>
235 241 Valessio Brito <valessio@gmail.com>
... ...
DEVELOPMENT.md 0 → 100644
... ... @@ -0,0 +1,124 @@
  1 +# Noosfero Development Policy
  2 +
  3 +## Developer Roles
  4 +
  5 +* *Developers* are everyone that is contributing code to Noosfero.
  6 +* *Committers* are the people with direct commit access to the Noosfero source
  7 + code. They are responsible for reviewing contributions from other developers
  8 + and integrating them in the Noosfero code base. They are the members of the
  9 + [Noosfero group on Gitlab](https://gitlab.com/groups/noosfero/members).
  10 +* *Release managers* are the people that are managing the release of a new
  11 + Noosfero version and/or the maintainance work of an existing Noosfero stable
  12 + branch. See MAINTAINANCE.md for details on the maintaince policy.
  13 +
  14 +## Development process
  15 +
  16 +* Every new feature or non-trivial bugfix should be reviewed by at least one
  17 + committer. This must be the case even if the original author is a committer.
  18 +
  19 + * In the case the original author is a committer, he/she should feel free to
  20 + commit directly if after 1 week nobody has provided any kind of feedback.
  21 +
  22 + * Developers who are not committers should feel free to ping committers if
  23 + they do not get feedback on their contributions after 1 week.
  24 +
  25 + * On GitLab, one can just add a comment to the merge request; one can also
  26 + @-mention specific committers or other developers who have expertise on
  27 + the area of the contribution.
  28 +
  29 + * Committers should follow the activity of the project, and try to help
  30 + reviewing contributions from others as much as possible.
  31 +
  32 + * On GitLab one can get emails for all activity on a project by setting the
  33 + [notification settings](https://gitlab.com/profile/notifications) to
  34 + "watch".
  35 +
  36 + * Anyone can help by reviewing contributions. Committers are the only ones
  37 + who can give the final approval to a contribution, but everyone is welcome
  38 + to help with code review, testing, etc.
  39 +
  40 + * See note above about setting up notification on GitLab.
  41 +
  42 +* Committers should feel free to push trivial (or urgent) changes directly.
  43 + There are no strict rule on what makes a change trivial or urgent; committers
  44 + are expected to exercise good judgement on a case by case basis.
  45 +
  46 + * Usually changes to the database are not trivial.
  47 +
  48 +* In the case of unsolvable conflict between commiters regarding any change to
  49 + the code, the current release manager(s) will have the final say in the
  50 + matter.
  51 +
  52 +* Release managers are responsible for stablishing a release schedule, and
  53 + about deciding when and what to release.
  54 +
  55 + * Release managers should announce release schedules to the project mailing
  56 + lists in advance.
  57 +
  58 + * The release schedule may include a period of feature freeze, during which
  59 + no new features or any other changes that are not pre-approved by the
  60 + release manager must be committed to the repository.
  61 +
  62 + * Committers must respect the release schedule and feature freezes.
  63 +
  64 +## Maintainance process
  65 +
  66 +### Not all feature releases will be maintained as a stable release
  67 +
  68 +We will be choosing specific release series to be maintained as stable
  69 +releases.
  70 +
  71 +This means that a given release is not guaranteed to be maintained as a stable
  72 +release, but does *not* mean it won't be. Any committer (or anyone, really) can
  73 +decide to maintain a given release as stable and seek help from others to do
  74 +so.
  75 +
  76 +### No merges from stable branches to master
  77 +
  78 +*All* changes must be submitted against the master branch first, and when
  79 +applicable, backported to the desired stable releases. Exceptions to this rules
  80 +are bug fixes that only apply to a given stable branch and not to master.
  81 +
  82 +In the past we had non-trivial changes accepted into stable releases while
  83 +master was way ahead (e.g. during the rails3 migration period), that made the
  84 +merge back into master very painful. By eliminating the need to do these
  85 +merges, we save time for the people responsible for the release, and eliminate
  86 +the possibility of human errors or oversights causing changes to be accepted
  87 +into stable that will be a problem to merge back into master.
  88 +
  89 +By getting all fixes in master first, we improve the chances that a future
  90 +release will not present regressions against bugs that should already be fixed,
  91 +but the fixes got lost in a big, complicated merge (and those won't exist
  92 +anymore, at least not from stable branches to master).
  93 +
  94 +After a fix gets into master, backporting changes into a stable release branch
  95 +is the responsibility of whoever is maintaing that branch, and those interested
  96 +in it. The stable branch release manager(s) are entitled the final say on any
  97 +matters related to that branch.
  98 +
  99 +## Apendix A: how to become a committer
  100 +
  101 +Every developer that wants to be a committer should create [an issue on
  102 +Gitlab](https://gitlab.com/noosfero/noosfero/issues) requesting to be added as
  103 +a committer. This request must include information about the requestor's
  104 +previous contributions to the project.
  105 +
  106 +If 2 or more commiters consider second the request, the requestor is accepted
  107 +as new commiter and added to the Noosfero group.
  108 +
  109 +The existing committers are free to choose whatever criteria they want to
  110 +second the request, but they must be sure that the new committer is a
  111 +responsible developer and knows what she/he is doing. They must be aware that
  112 +seconding these requests means seconding the actions of the new committer: if
  113 +the new committer screw up, her/his seconds screwed up.
  114 +
  115 +## Apendix B: how to become a release manager
  116 +
  117 +A new release manager for the development version of Noosfero (i.e. the one
  118 +that includes new features, a.k.a. the master branch) is apointed by the
  119 +current release manager, and must be a committer first.
  120 +
  121 +Release managers for stable branches are self-appointed, i.e. whoever takes the
  122 +work takes the role. In case of a conflict (e.g. 2+ different people want to do
  123 +the work but can't agree on working together), the development release manager
  124 +decides.
... ...
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'
  2 +gem 'rails', '~> 3.2.19'
  3 +gem 'fast_gettext', '~> 0.6.8'
  4 +gem 'acts-as-taggable-on', '~> 3.0.2'
  5 +gem 'prototype-rails', '~> 3.2.1'
  6 +gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
  7 +gem 'rails_autolink', '~> 1.1.5'
  8 +gem 'pg', '~> 0.13.2'
  9 +gem 'rmagick', '~> 2.13.1'
  10 +gem 'RedCloth', '~> 4.2.9'
  11 +gem 'will_paginate', '~> 3.0.3'
  12 +gem 'ruby-feedparser', '~> 0.7'
  13 +gem 'daemons', '~> 1.1.5'
  14 +gem 'thin', '~> 1.3.1'
  15 +gem 'hpricot', '~> 0.8.6'
  16 +gem 'nokogiri', '~> 1.5.5'
17 17 gem 'rake', :require => false
18   -gem 'rest-client'
19   -gem 'exception_notification'
  18 +gem 'rest-client', '~> 1.6.7'
  19 +gem 'exception_notification', '~> 4.0.1'
  20 +gem 'gettext', '~> 2.2.1', :require => false, :group => :development
  21 +gem 'locale', '~> 2.0.5'
20 22  
21 23 # FIXME list here all actual dependencies (i.e. the ones in debian/control),
22 24 # with their GEM names (not the Debian package names)
23 25  
24 26 group :production do
25   - gem 'dalli'
  27 + gem 'dalli', '~> 2.7.0'
26 28 end
27 29  
28 30 group :test do
29   - gem 'rspec'
30   - gem 'rspec-rails'
31   - gem 'mocha', :require => false
  31 + gem 'rspec', '~> 2.10.0'
  32 + gem 'rspec-rails', '~> 2.10.1'
  33 + gem 'mocha', '~> 1.1.0', :require => false
32 34 end
33 35  
34 36 group :cucumber do
35   - gem 'cucumber-rails', :require => false
36   - gem 'capybara'
37   - gem 'cucumber'
38   - gem 'database_cleaner'
39   - gem 'selenium-webdriver'
  37 + gem 'cucumber-rails', '~> 1.0.6', :require => false
  38 + gem 'capybara', '~> 2.1.0'
  39 + gem 'cucumber', '~> 1.0.6'
  40 + gem 'database_cleaner', '~> 1.2.0'
  41 + gem 'selenium-webdriver', '~> 2.39.0'
40 42 end
41 43  
42   -# include plugin gemfiles
43   -Dir.glob(File.join('config', 'plugins', '*')).each do |plugin|
44   - plugin_gemfile = File.join(plugin, 'Gemfile')
45   - eval File.read(plugin_gemfile) if File.exists?(plugin_gemfile)
  44 +# include gemfiles from enabled plugins
  45 +# plugins in baseplugins/ are not included on purpose. They should not have any
  46 +# dependencies.
  47 +Dir.glob('config/plugins/*/Gemfile').each do |gemfile|
  48 + eval File.read(gemfile)
46 49 end
... ...
Gemfile.lock
... ... @@ -1,191 +0,0 @@
1   -PATH
2   - remote: vendor/prototype_legacy_helper
3   - specs:
4   - prototype_legacy_helper (0.0.0)
5   -
6   -GEM
7   - remote: https://rubygems.org/
8   - specs:
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)
42   - mime-types (>= 1.16)
43   - nokogiri (>= 1.3.3)
44   - rack (>= 1.0.0)
45   - rack-test (>= 0.5.4)
46   - xpath (~> 2.0)
47   - childprocess (0.3.3)
48   - ffi (~> 1.0.6)
49   - cucumber (1.0.6)
50   - builder (>= 2.1.2)
51   - diff-lcs (>= 1.1.2)
52   - gherkin (~> 2.4.18)
53   - json (>= 1.4.6)
54   - term-ansicolor (>= 1.0.6)
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)
62   - diff-lcs (1.1.3)
63   - erubis (2.7.0)
64   - eventmachine (0.12.10)
65   - exception_notification (4.0.1)
66   - actionmailer (>= 3.0.4)
67   - activesupport (>= 3.0.4)
68   - fast_gettext (0.6.8)
69   - ffi (1.0.11)
70   - gherkin (2.4.21)
71   - json (>= 1.4.6)
72   - hike (1.2.1)
73   - hpricot (0.8.6)
74   - i18n (0.6.0)
75   - journey (1.0.3)
76   - json (1.7.3)
77   - mail (2.4.4)
78   - i18n (>= 0.4.0)
79   - mime-types (~> 1.16)
80   - treetop (~> 1.4.8)
81   - metaclass (0.0.1)
82   - mime-types (1.19)
83   - mocha (0.11.3)
84   - metaclass (~> 0.0.1)
85   - multi_json (1.3.6)
86   - nokogiri (1.5.5)
87   - pg (0.13.2)
88   - polyglot (0.3.3)
89   - prototype-rails (3.2.1)
90   - rails (~> 3.2)
91   - rack (1.4.1)
92   - rack-cache (1.2)
93   - rack (>= 0.4)
94   - rack-ssl (1.3.2)
95   - rack
96   - rack-test (0.6.1)
97   - rack (>= 1.0)
98   - rails (3.2.6)
99   - actionmailer (= 3.2.6)
100   - actionpack (= 3.2.6)
101   - activerecord (= 3.2.6)
102   - activeresource (= 3.2.6)
103   - activesupport (= 3.2.6)
104   - bundler (~> 1.0)
105   - railties (= 3.2.6)
106   - rails_autolink (1.1.5)
107   - rails (> 3.1)
108   - railties (3.2.6)
109   - actionpack (= 3.2.6)
110   - activesupport (= 3.2.6)
111   - rack-ssl (~> 1.3.2)
112   - rake (>= 0.8.7)
113   - rdoc (~> 3.4)
114   - thor (>= 0.14.6, < 2.0)
115   - rake (0.9.2.2)
116   - rdoc (3.9.4)
117   - rest-client (1.6.7)
118   - mime-types (>= 1.16)
119   - rmagick (2.13.1)
120   - rspec (2.10.0)
121   - rspec-core (~> 2.10.0)
122   - rspec-expectations (~> 2.10.0)
123   - rspec-mocks (~> 2.10.0)
124   - rspec-core (2.10.1)
125   - rspec-expectations (2.10.0)
126   - diff-lcs (~> 1.1.3)
127   - rspec-mocks (2.10.1)
128   - rspec-rails (2.10.1)
129   - actionpack (>= 3.0)
130   - activesupport (>= 3.0)
131   - railties (>= 3.0)
132   - rspec (~> 2.10.0)
133   - ruby-feedparser (0.7)
134   - rubyzip (1.1.2)
135   - selenium-webdriver (2.39.0)
136   - childprocess (>= 0.2.5)
137   - multi_json (~> 1.0)
138   - rubyzip (~> 1.0)
139   - websocket (~> 1.0.4)
140   - sprockets (2.1.3)
141   - hike (~> 1.2)
142   - multi_json (~> 1.0)
143   - rack (~> 1.0)
144   - tilt (~> 1.1, != 1.3.0)
145   - term-ansicolor (1.0.7)
146   - thin (1.3.1)
147   - daemons (>= 1.0.9)
148   - eventmachine (>= 0.12.6)
149   - rack (>= 1.0.0)
150   - thor (0.15.3)
151   - tilt (1.3.3)
152   - treetop (1.4.10)
153   - polyglot
154   - polyglot (>= 0.3.1)
155   - tzinfo (0.3.33)
156   - websocket (1.0.7)
157   - will_paginate (3.0.3)
158   - xpath (2.0.0)
159   - nokogiri (~> 1.3)
160   -
161   -PLATFORMS
162   - ruby
163   -
164   -DEPENDENCIES
165   - RedCloth
166   - acts-as-taggable-on
167   - capybara
168   - cucumber
169   - cucumber-rails
170   - daemons
171   - dalli
172   - database_cleaner
173   - exception_notification
174   - fast_gettext
175   - hpricot
176   - mocha
177   - nokogiri
178   - pg
179   - prototype-rails
180   - prototype_legacy_helper (= 0.0.0)!
181   - rails
182   - rails_autolink
183   - rake
184   - rest-client
185   - rmagick
186   - rspec
187   - rspec-rails
188   - ruby-feedparser
189   - selenium-webdriver
190   - thin
191   - will_paginate
INSTALL.https.md
1   -Setup Noosfero to use HTTPS
2   -===========================
  1 +# Setup Noosfero to use HTTPS
3 2  
4 3 This document assumes that you have a fully and clean Noosfero
5 4 installation as explained at the `INSTALL.md` file.
6 5  
7   -SSL certificate
8   -+++++++++++++++
  6 +## Creating a self-signed SSL certificate
9 7  
10 8 You should get a valid SSL certificate, but if you want to test
11 9 your setup before, you could generate a self-signed certificate
... ... @@ -17,99 +15,106 @@ as below:
17 15 # openssl req -new -x509 -nodes -sha1 -days $[10*365] -key noosfero.key > noosfero.cert
18 16 # cat noosfero.key noosfero.cert > noosfero.pem
19 17  
  18 +## Web server configuration
  19 +
20 20 There are two ways of using SSL with Noosfero: 1) If you are not using
21 21 Varnish; and 2) If you are using Varnish.
22 22  
23   -1) If you are are not using Varnish
24   -+++++++++++++++++++++++++++++++++++
  23 +### 1) If you are are not using Varnish
25 24  
26 25 Simply do a redirect in apache to force all connections with SSL:
27 26  
28   - <VirtualHost *:8080>
29   - ServerName test.stoa.usp.br
30   -
31   - Redirect / https://example.com/
32   - </VirtualHost>
  27 +```
  28 +<VirtualHost *:8080>
  29 + ServerName test.stoa.usp.br
  30 + Redirect / https://example.com/
  31 +</VirtualHost>
  32 +```
33 33  
34 34 And set a vhost to receive then:
35 35  
36   - <VirtualHost *:443>
37   - ServerName example.com
38   -
39   - SSLEngine On
40   - SSLCertificateFile /etc/ssl/certs/cert.pem
41   - SSLCertificateKeyFile /etc/ssl/private/cert.key
42   -
43   - Include /etc/noosfero/apache/virtualhost.conf
44   - </VirtualHost>
  36 +```
  37 +<VirtualHost *:443>
  38 + ServerName example.com
  39 + SSLEngine On
  40 + SSLCertificateFile /etc/ssl/certs/cert.pem
  41 + SSLCertificateKeyFile /etc/ssl/private/cert.key
  42 + Include /etc/noosfero/apache/virtualhost.conf
  43 +</VirtualHost>
  44 +```
45 45  
46 46 Be aware that if you had configured varnish, the requests won't reach
47 47 it with this configuration.
48 48  
49   -2) If you are using Varnish
50   -+++++++++++++++++++++++++++
51   -
52   -Varnish isn't able to communicate with the SSL protocol, so we will
53   -need some one who do this and Pound[1] can do the job. In order to
54   -install it in Debian based systems:
  49 +### 2) If you are using Varnish
55 50  
56   - $ sudo apt-get install pound
  51 +Varnish isn't able to communicate with the SSL protocol, so we will need some
  52 +one else who do this and [Pound](http://www.apsis.ch/pound) can do the job. In
  53 +order to install it in Debian based systems:
57 54  
58   -Set Varnish to listen in other port than 80:
  55 +```
  56 +$ sudo apt-get install pound
  57 +```
59 58  
60   -/etc/defaults/varnish
61   ----------------------
  59 +Set Varnish to listen in other port than 80 in `/etc/defaults/varnish`:
62 60  
63   - DAEMON_OPTS="-a localhost:6081 \
64   - -T localhost:6082 \
65   - -f /etc/varnish/default.vcl \
66   - -S /etc/varnish/secret \
67   - -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"
  61 +```
  62 +DAEMON_OPTS="-a localhost:6081 \
  63 + -T localhost:6082 \
  64 + -f /etc/varnish/default.vcl \
  65 + -S /etc/varnish/secret \
  66 + -s file,/var/lib/varnish/$INSTANCE/varnish_storage.bin,1G"
  67 +```
68 68  
69 69 Configure Pound:
70 70  
71   - # cp /usr/share/noosfero/etc/pound.cfg /etc/pound/
72   -
73   -Edit /etc/pound.cfg and set the IP and domain of your server.
  71 +```
  72 +# cp /usr/share/noosfero/etc/pound.cfg /etc/pound/
  73 +```
74 74  
75   -Configure Pound to start at system initialization:
  75 +Edit `/etc/pound.cfg` and set the IP and domain of your server.
76 76  
77   -/etc/default/pound
  77 +Configure Pound to start at system initialization. At `/etc/default/pound`:
78 78 ------------------
79 79  
80   - startup=1
  80 +```
  81 +startup=1
  82 +```
81 83  
82   -Set Apache to only listen to localhost:
  84 +Set Apache to only listen to localhost, at `/etc/apache2/ports.conf`:
83 85  
84   -/etc/apache2/ports.conf
85   ------------------------
86   -
87   - Listen 127.0.0.1:8080
  86 +```
  87 +Listen 127.0.0.1:8080
  88 +```
88 89  
89 90 Restart the services:
90 91  
91   - $ sudo service apache2 restart
92   - $ sudo service varnish restart
  92 +```
  93 +$ sudo service apache2 restart
  94 +$ sudo service varnish restart
  95 +```
93 96  
94 97 Start pound:
95 98  
96   - $ sudo service pound start
97   -
98   -[1] http://www.apsis.ch/pound
  99 +```
  100 +$ sudo service pound start
  101 +```
99 102  
100   -Noosfero XMPP chat
101   -++++++++++++++++++
  103 +## Noosfero XMPP chat
102 104  
103 105 If you want to use chat over HTTPS, then you should add the domain
104   -and IP of your server in the /etc/hosts file, example:
  106 +and IP of your server in the /etc/hosts file, example
105 107  
106   -/etc/hosts
107   -----------
  108 +`/etc/hosts:`
108 109  
109   - 192.168.1.86 mydomain.example.com
  110 +```
  111 +192.168.1.86 mydomain.example.com
  112 +```
110 113  
111   -Also, it's recomended that you remove lines above from the file
  114 +Also, it's recomended that you remove the lines below from the file
112 115 `/etc/apache2/sites-enabled/noosfero`:
113 116  
114   - RewriteEngine On
115   - Include /usr/share/noosfero/util/chat/apache/xmpp.conf
  117 +```
  118 +RewriteEngine On
  119 +Include /usr/share/noosfero/util/chat/apache/xmpp.conf
  120 +```
... ...
INSTALL.locales.md 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +Using custom locales
  2 +====================
  3 +
  4 +Personalized translations go into the `config/custom_locales/` directory.
  5 +Custom locales can be identified by the rails environment, schema name in a
  6 +multitenancy setup or domain name until the first dot (e.g env1.coop.br for the
  7 +example below).
  8 +
  9 +Currently, the only filename prefix for the localization file which is
  10 +processed is "environment". For instance, a POT file would be called
  11 +"environment.pot".
  12 +
  13 +The structure of an environment named env1 with custom translations for both
  14 +Portuguese and Spanish and an environment named env2 with custom Russian
  15 +translation would be:
  16 +
  17 + config/
  18 + custom_locales/
  19 + env1/
  20 + environment.pot
  21 + pt/
  22 + environment.po
  23 + es/
  24 + environment.po
  25 + env2/
  26 + environment.pot
  27 + ru/
  28 + environment.po
  29 +
... ...
INSTALL.md
... ... @@ -186,8 +186,8 @@ Apache instalation
186 186  
187 187 # apt-get install apache2
188 188  
189   -Apache configuration
190   ---------------------
  189 +Configuration - noosfero at /
  190 +-----------------------------
191 191  
192 192 First you have to enable the following some apache modules:
193 193  
... ... @@ -257,6 +257,62 @@ Now restart your apache server (as root):
257 257  
258 258 # invoke-rc.d apache2 restart
259 259  
  260 +Configuration - noosfero at a /subdirectory
  261 +-------------------------------------------
  262 +
  263 +This section describes how to configure noosfero at a subdirectory, what is
  264 +specially useful when you want Noosfero to share a domain name with other
  265 +applications. For example you can host noosfero at yourdomain.com/social, a
  266 +webmail application at yourdomain.com/webmail, and have a static HTML website
  267 +at yourdomain.com/.
  268 +
  269 +**NOTE:** Some plugins might not work well with this setting. Before deploying
  270 +this setting, make sure you test that everything you need works properly with
  271 +it.
  272 +
  273 +The configuration is similar to the main configuration instructions, except for
  274 +the following points. In the description below, replace '/subdirectory' with
  275 +the actual subdirectory you want.
  276 +
  277 +1) add a `prefix: /subdirectory` line to your thin configuration file (thin.yml).
  278 +
  279 +1.1) remember to restart the noosfero application server whenever you make
  280 +changes to that configuration file.
  281 +
  282 + # service noosfero restart
  283 +
  284 +2) add a line saying `export RAILS_RELATIVE_URL_ROOT=/subdirectory` to
  285 +/etc/default/noosfero (you can create it with just this line if it does not
  286 +exist already).
  287 +
  288 +3) You should add the following apache configuration to an existing virtual
  289 +host (plus the `<Proxy balancer://noosfero>` section as displayed above):
  290 +
  291 +```
  292 +Alias /subdirectory /path/to/noosfero/public
  293 +<Directory "/path/to/noosfero/public">
  294 + Options FollowSymLinks
  295 + AllowOverride None
  296 + Order Allow,Deny
  297 + Allow from all
  298 +
  299 + Include /path/to/noosfero/etc/noosfero/apache/cache.conf
  300 +
  301 + RewriteEngine On
  302 + RewriteBase /subdirectory
  303 + # Rewrite index to check for static index.html
  304 + RewriteRule ^$ index.html [QSA]
  305 + # Rewrite to check for Rails cached page
  306 + RewriteRule ^([^.]+)$ $1.html [QSA]
  307 + RewriteCond %{REQUEST_FILENAME} !-f
  308 + RewriteRule ^(.*)$ http://localhost:3000%{REQUEST_URI} [P,QSA,L]
  309 +</Directory>
  310 +```
  311 +
  312 +3.1) remember to reload the apache server whenever any apache configuration
  313 +file changes.
  314 +
  315 + # sudo service apache2 reload
260 316  
261 317 Enabling exception notifications
262 318 ================================
... ...
Rakefile
... ... @@ -6,3 +6,13 @@
6 6 require File.expand_path('../config/application', __FILE__)
7 7  
8 8 Noosfero::Application.load_tasks
  9 +
  10 +[
  11 + "baseplugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  12 + "config/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  13 + "config/plugins/*/vendor/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  14 +].map do |pattern|
  15 + Dir.glob(pattern).sort
  16 +end.flatten.each do |taskfile|
  17 + load taskfile
  18 +end
... ...
Vagrantfile
... ... @@ -3,7 +3,7 @@
3 3  
4 4 VAGRANTFILE_API_VERSION = "2"
5 5 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
6   - config.vm.box = "debian-wheezy"
  6 + config.vm.box = ENV.fetch('VAGRANT_BOX', "debian-wheezy")
7 7 config.vm.network :forwarded_port, host: 3000, guest: 3000
8 8 config.vm.provision :shell do |shell|
9 9 shell.inline = 'su vagrant -c /vagrant/script/vagrant'
... ...
app/controllers/admin/admin_panel_controller.rb
... ... @@ -71,4 +71,22 @@ class AdminPanelController &lt; AdminController
71 71 end
72 72 end
73 73 end
  74 +
  75 + def manage_organizations_status
  76 + scope = environment.organizations
  77 + @filter = params[:filter] || 'any'
  78 + @title = "Organization profiles"
  79 + @title = @title+" - "+@filter if @filter != 'any'
  80 +
  81 + if @filter == 'enabled'
  82 + scope = scope.visible
  83 + elsif @filter == 'disabled'
  84 + scope = scope.disabled
  85 + end
  86 +
  87 + scope = scope.order('name ASC')
  88 +
  89 + @q = params[:q]
  90 + @collection = find_by_contents(:organizations, scope, @q, {:per_page => 10, :page => params[:npage]})[:results]
  91 + end
74 92 end
... ...
app/controllers/admin/plugin_admin_controller.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class PluginAdminController < AdminController
  2 +
  3 + protect 'edit_environment_features', :environment
  4 +
  5 +end
... ...
app/controllers/admin/templates_controller.rb
... ... @@ -40,8 +40,67 @@ class TemplatesController &lt; AdminController
40 40 end
41 41 end
42 42  
  43 + def set_community_as_default
  44 + begin
  45 + community = environment.communities.find(params[:template_id])
  46 + rescue ActiveRecord::RecordNotFound
  47 + message = _('Community not found. The template could no be changed.')
  48 + community = nil
  49 + end
  50 +
  51 + message = _('%s defined as default') % community.name if set_as_default(community)
  52 + session[:notice] = message
  53 +
  54 + redirect_to :action => 'index'
  55 + end
  56 +
  57 + def set_person_as_default
  58 + begin
  59 + person = environment.people.find(params[:template_id])
  60 + rescue ActiveRecord::RecordNotFound
  61 + message = _('Person not found. The template could no be changed.')
  62 + person = nil
  63 + end
  64 +
  65 + message = _('%s defined as default') % person.name if set_as_default(person)
  66 + session[:notice] = message
  67 +
  68 + redirect_to :action => 'index'
  69 + end
  70 +
  71 + def set_enterprise_as_default
  72 + begin
  73 + enterprise = environment.enterprises.find(params[:template_id])
  74 + rescue ActiveRecord::RecordNotFound
  75 + message = _('Enterprise not found. The template could no be changed.')
  76 + enterprise = nil
  77 + end
  78 +
  79 + message = _('%s defined as default') % enterprise.name if set_as_default(enterprise)
  80 + session[:notice] = message
  81 +
  82 + redirect_to :action => 'index'
  83 + end
  84 +
43 85 private
44 86  
  87 + def set_as_default(obj)
  88 + return nil if obj.nil?
  89 + case obj.class.name
  90 + when 'Community' then
  91 + environment.community_default_template = obj
  92 + environment.save!
  93 + when 'Person' then
  94 + environment.person_default_template = obj
  95 + environment.save!
  96 + when 'Enterprise' then
  97 + environment.enterprise_default_template = obj
  98 + environment.save!
  99 + else
  100 + nil
  101 + end
  102 + end
  103 +
45 104 def create_organization_template(klass)
46 105 identifier = params[:name].to_slug
47 106 template = klass.new(:name => params[:name], :identifier => identifier, :is_template => true)
... ...
app/controllers/application_controller.rb
... ... @@ -40,7 +40,7 @@ class ApplicationController &lt; ActionController::Base
40 40  
41 41 theme_layout = theme_option(:layout)
42 42 if theme_layout
43   - theme_view_file('layouts/'+theme_layout) || theme_layout
  43 + (theme_view_file('layouts/'+theme_layout) || theme_layout).to_s
44 44 else
45 45 'application'
46 46 end
... ... @@ -127,6 +127,9 @@ class ApplicationController &lt; ActionController::Base
127 127  
128 128 # TODO: move this logic somewhere else (Domain class?)
129 129 def detect_stuff_by_domain
  130 + # Sets text domain based on request host for custom internationalization
  131 + FastGettext.text_domain = Domain.custom_locale(request.host)
  132 +
130 133 @domain = Domain.find_by_name(request.host)
131 134 if @domain.nil?
132 135 @environment = Environment.default
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -174,6 +174,8 @@ class CmsController &lt; MyProfileController
174 174  
175 175 post_only :set_home_page
176 176 def set_home_page
  177 + return render_access_denied unless user.can_change_homepage?
  178 +
177 179 article = params[:id].nil? ? nil : profile.articles.find(params[:id])
178 180 profile.update_attribute(:home_page, article)
179 181  
... ... @@ -212,6 +214,7 @@ class CmsController &lt; MyProfileController
212 214 if @errors.any?
213 215 render :action => 'upload_files', :parent_id => @parent_id
214 216 else
  217 + session[:notice] = _('File(s) successfully uploaded')
215 218 if @back_to
216 219 redirect_to @back_to
217 220 elsif @parent
... ... @@ -227,7 +230,7 @@ class CmsController &lt; MyProfileController
227 230 @article = profile.articles.find(params[:id])
228 231 if request.post?
229 232 @article.destroy
230   - session[:notice] = _("\"#{@article.name}\" was removed.")
  233 + session[:notice] = _("\"%s\" was removed." % @article.name)
231 234 referer = Rails.application.routes.recognize_path URI.parse(request.referer).path rescue nil
232 235 if referer and referer[:controller] == 'cms' and referer[:action] != 'edit'
233 236 redirect_to referer
... ...
app/controllers/my_profile/friends_controller.rb 100644 → 100755
... ... @@ -20,7 +20,7 @@ class FriendsController &lt; MyProfileController
20 20  
21 21 class << self
22 22 def per_page
23   - 10
  23 + 12
24 24 end
25 25 end
26 26 def per_page
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -3,7 +3,16 @@ class ProfileDesignController &lt; BoxOrganizerController
3 3 needs_profile
4 4  
5 5 protect 'edit_profile_design', :profile
6   -
  6 +
  7 + before_filter :protect_fixed_block, :only => [:save, :move_block]
  8 +
  9 + def protect_fixed_block
  10 + block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
  11 + if block.fixed && !current_person.is_admin?
  12 + render_access_denied
  13 + end
  14 + end
  15 +
7 16 def available_blocks
8 17 blocks = [ ArticleBlock, TagsBlock, RecentDocumentsBlock, ProfileInfoBlock, LinkListBlock, MyNetworkBlock, FeedReaderBlock, ProfileImageBlock, LocationBlock, SlideshowBlock, ProfileSearchBlock, HighlightsBlock ]
9 18  
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -19,14 +19,16 @@ class ProfileEditorController &lt; MyProfileController
19 19 params[:profile_data][:custom_fields] ||= {}
20 20 end
21 21 Profile.transaction do
22   - Image.transaction do
23   - if @profile_data.update_attributes(params[:profile_data])
24   - redirect_to :action => 'index', :profile => profile.identifier
25   - else
26   - profile.identifier = params[:profile] if profile.identifier.blank?
  22 + Image.transaction do
  23 + begin
  24 + @plugins.dispatch(:profile_editor_transaction_extras)
  25 + @profile_data.update_attributes!(params[:profile_data])
  26 + redirect_to :action => 'index', :profile => profile.identifier
  27 + rescue Exception => ex
  28 + profile.identifier = params[:profile] if profile.identifier.blank?
  29 + end
27 30 end
28 31 end
29   - end
30 32 end
31 33 end
32 34  
... ... @@ -75,10 +77,51 @@ class ProfileEditorController &lt; MyProfileController
75 77 if request.post?
76 78 if @profile.destroy
77 79 session[:notice] = _('The profile was deleted.')
78   - redirect_to :controller => 'home'
  80 + if(params[:return_to])
  81 + redirect_to params[:return_to]
  82 + else
  83 + redirect_to :controller => 'home'
  84 + end
79 85 else
80 86 session[:notice] = _('Could not delete profile')
81 87 end
82 88 end
83 89 end
  90 +
  91 + def deactivate_profile
  92 + if environment.admins.include?(current_person)
  93 + profile = environment.profiles.find(params[:id])
  94 + if profile.disable
  95 + profile.save
  96 + session[:notice] = _("The profile '#{profile.name}' was deactivated.")
  97 + else
  98 + session[:notice] = _('Could not deactivate profile.')
  99 + end
  100 + end
  101 +
  102 + redirect_to_previous_location
  103 + end
  104 +
  105 + def activate_profile
  106 + if environment.admins.include?(current_person)
  107 + profile = environment.profiles.find(params[:id])
  108 +
  109 + if profile.enable
  110 + session[:notice] = _("The profile '#{profile.name}' was activated.")
  111 + else
  112 + session[:notice] = _('Could not activate the profile.')
  113 + end
  114 + end
  115 +
  116 + redirect_to_previous_location
  117 + end
  118 +
  119 + protected
  120 +
  121 + def redirect_to_previous_location
  122 + back = request.referer
  123 + back = "/" if back.nil?
  124 +
  125 + redirect_to back
  126 + end
84 127 end
... ...
app/controllers/my_profile/profile_members_controller.rb
... ... @@ -20,7 +20,7 @@ class ProfileMembersController &lt; MyProfileController
20 20 redirect_to :action => :last_admin
21 21 elsif @person.define_roles(@roles, profile)
22 22 session[:notice] = _('Roles successfuly updated')
23   - redirect_to :controller => 'profile_editor'
  23 + redirect_to :action => 'index'
24 24 else
25 25 session[:notice] = _('Couldn\'t change the roles')
26 26 redirect_to :action => 'index'
... ...
app/controllers/public/account_controller.rb
... ... @@ -104,6 +104,7 @@ class AccountController &lt; ApplicationController
104 104 @user.return_to = session[:return_to]
105 105 @person = Person.new(params[:profile_data])
106 106 @person.environment = @user.environment
  107 +
107 108 if request.post?
108 109 if may_be_a_bot
109 110 set_signup_start_time_for_now
... ... @@ -122,6 +123,14 @@ class AccountController &lt; ApplicationController
122 123 invitation.update_attributes!({:friend => @user.person})
123 124 invitation.finish
124 125 end
  126 +
  127 + unless params[:file].nil?
  128 + image = Image::new :uploaded_data=> params[:file][:image]
  129 +
  130 + @user.person.image = image
  131 + @user.person.save
  132 + end
  133 +
125 134 if @user.activated?
126 135 self.current_user = @user
127 136 check_join_in_community(@user)
... ... @@ -191,7 +200,7 @@ class AccountController &lt; ApplicationController
191 200 else
192 201 @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]]
193 202 end
194   - rescue ActiveRecord::RecordInvald
  203 + rescue ActiveRecord::RecordInvalid
195 204 @change_password.errors[:base] << _('Could not perform password recovery for the user.')
196 205 end
197 206 end
... ...
app/controllers/public/chat_controller.rb
... ... @@ -19,9 +19,13 @@ 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))
23   - render :text => data, :layout => false, :content_type => mimetype
24   - expires_in 24.hours
  22 + if filename =~ /^(https?:)?\/\//
  23 + redirect_to filename
  24 + else
  25 + data = File.read(File.join(Rails.root, 'public', filename))
  26 + render :text => data, :layout => false, :content_type => mimetype
  27 + expires_in 24.hours
  28 + end
25 29 end
26 30  
27 31 def index
... ...
app/controllers/public/contact_controller.rb
1 1 class ContactController < PublicController
2 2  
3   - before_filter :login_required
4   -
5 3 needs_profile
6 4  
7 5 def new
8   - @contact
  6 + @contact = build_contact
9 7 if request.post? && params[:confirm] == 'true'
10   - @contact = user.build_contact(profile, params[:contact])
11 8 @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil
12 9 @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil
13 10 if @contact.deliver
... ... @@ -16,8 +13,17 @@ class ContactController &lt; PublicController
16 13 else
17 14 session[:notice] = _('Contact not sent')
18 15 end
  16 + end
  17 + end
  18 +
  19 + protected
  20 +
  21 + def build_contact
  22 + params[:contact] ||= {}
  23 + if logged_in?
  24 + user.build_contact profile, params[:contact]
19 25 else
20   - @contact = user.build_contact(profile)
  26 + Contact.new params[:contact].merge(dest: profile)
21 27 end
22 28 end
23 29  
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -126,7 +126,7 @@ class ContentViewerController &lt; ApplicationController
126 126 elsif !@page.display_to?(user)
127 127 if !profile.public?
128 128 private_profile_partial_parameters
129   - render :template => 'profile/_private_profile', :status => 403
  129 + render :template => 'profile/_private_profile', :status => 403, :formats => [:html]
130 130 allowed = false
131 131 else #if !profile.visible?
132 132 render_access_denied
... ... @@ -216,8 +216,6 @@ class ContentViewerController &lt; ApplicationController
216 216 if @page.has_posts?
217 217 posts = get_posts(params[:year], params[:month])
218 218  
219   - posts = posts.includes(:parent, {:profile => [:domains, :environment]}, :author)
220   -
221 219 #FIXME Need to run this before the pagination because this version of
222 220 # will_paginate returns a will_paginate collection instead of a
223 221 # relation.
... ...
app/controllers/public/profile_controller.rb
... ... @@ -17,7 +17,11 @@ class ProfileController &lt; PublicController
17 17 end
18 18 @tags = profile.article_tags
19 19 unless profile.display_info_to?(user)
20   - profile.visible? ? private_profile : invisible_profile
  20 + if profile.visible?
  21 + private_profile
  22 + else
  23 + invisible_profile
  24 + end
21 25 end
22 26 end
23 27  
... ... @@ -61,13 +65,13 @@ class ProfileController &lt; PublicController
61 65  
62 66 def friends
63 67 if is_cache_expired?(profile.friends_cache_key(params))
64   - @friends = profile.friends.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage])
  68 + @friends = profile.friends.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.friends.count)
65 69 end
66 70 end
67 71  
68 72 def members
69 73 if is_cache_expired?(profile.members_cache_key(params))
70   - @members = profile.members_by_name.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage])
  74 + @members = profile.members_by_name.includes(relations_to_include).paginate(:per_page => members_per_page, :page => params[:npage], :total_entries => profile.members.count)
71 75 end
72 76 end
73 77  
... ... @@ -315,7 +319,7 @@ class ProfileController &lt; PublicController
315 319 abuse_report = AbuseReport.new(params[:abuse_report])
316 320 if !params[:content_type].blank?
317 321 article = params[:content_type].constantize.find(params[:content_id])
318   - abuse_report.content = instance_eval(&article.reported_version)
  322 + abuse_report.content = article_reported_version(article)
319 323 end
320 324  
321 325 user.register_report(abuse_report, profile)
... ... @@ -394,6 +398,7 @@ class ProfileController &lt; PublicController
394 398  
395 399 def private_profile
396 400 private_profile_partial_parameters
  401 + render :action => 'index', :status => 403
397 402 end
398 403  
399 404 def invisible_profile
... ...
app/controllers/public/search_controller.rb
... ... @@ -90,10 +90,14 @@ class SearchController &lt; PublicController
90 90 end
91 91  
92 92 def events
93   - year = (params[:year] ? params[:year].to_i : Date.today.year)
94   - month = (params[:month] ? params[:month].to_i : Date.today.month)
95   - day = (params[:day] ? params[:day].to_i : Date.today.day)
96   - @date = build_date(year, month, day)
  93 + if params[:year].blank? && params[:year].blank? && params[:day].blank?
  94 + @date = Date.today
  95 + else
  96 + year = (params[:year] ? params[:year].to_i : Date.today.year)
  97 + month = (params[:month] ? params[:month].to_i : Date.today.month)
  98 + day = (params[:day] ? params[:day].to_i : 1)
  99 + @date = build_date(year, month, day)
  100 + end
97 101 date_range = (@date - 1.month).at_beginning_of_month..(@date + 1.month).at_end_of_month
98 102  
99 103 @events = []
... ...
app/helpers/application_helper.rb
... ... @@ -304,7 +304,7 @@ module ApplicationHelper
304 304 def partial_for_class(klass, prefix=nil, suffix=nil)
305 305 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
306 306 name = klass.name.underscore
307   - controller.view_paths.reverse_each do |view_path|
  307 + controller.view_paths.each do |view_path|
308 308 partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix)
309 309 return partial if partial
310 310 end
... ... @@ -433,19 +433,19 @@ module ApplicationHelper
433 433 end
434 434  
435 435 def theme_site_title
436   - theme_include('site_title')
  436 + @theme_site_title ||= theme_include 'site_title'
437 437 end
438 438  
439 439 def theme_header
440   - theme_include('header')
  440 + @theme_header ||= theme_include 'header'
441 441 end
442 442  
443 443 def theme_footer
444   - theme_include('footer')
  444 + @theme_footer ||= theme_include 'footer'
445 445 end
446 446  
447 447 def theme_extra_navigation
448   - theme_include('navigation')
  448 + @theme_extra_navigation ||= theme_include 'navigation'
449 449 end
450 450  
451 451 def is_testing_theme
... ... @@ -482,7 +482,12 @@ module ApplicationHelper
482 482 '/images/icons-app/enterprise-'+ size.to_s() +'.png'
483 483 end
484 484 else
485   - '/images/icons-app/person-'+ size.to_s() +'.png'
  485 + pixels = Image.attachment_options[:thumbnails][size].split('x').first
  486 + gravatar_profile_image_url(
  487 + profile.email,
  488 + :size => pixels,
  489 + :d => gravatar_default
  490 + )
486 491 end
487 492 filename = default_or_themed_icon(icon)
488 493 end
... ... @@ -602,7 +607,7 @@ module ApplicationHelper
602 607 end
603 608  
604 609 def gravatar_default
605   - (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar']
  610 + (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar'] || 'mm'
606 611 end
607 612  
608 613 attr_reader :environment
... ... @@ -669,13 +674,14 @@ module ApplicationHelper
669 674 html.join "\n"
670 675 end
671 676  
  677 + def theme_javascript_src
  678 + script = File.join theme_path, 'theme.js'
  679 + script if File.exists? File.join(Rails.root, 'public', script)
  680 + end
  681 +
672 682 def theme_javascript_ng
673   - script = File.join(theme_path, 'theme.js')
674   - if File.exists?(File.join(Rails.root, 'public', script))
675   - javascript_include_tag script
676   - else
677   - nil
678   - end
  683 + script = theme_javascript_src
  684 + javascript_include_tag script if script
679 685 end
680 686  
681 687 def file_field_or_thumbnail(label, image, i)
... ... @@ -856,8 +862,9 @@ module ApplicationHelper
856 862 end
857 863  
858 864 def base_url
859   - environment.top_url
  865 + environment.top_url(request.scheme)
860 866 end
  867 + alias :top_url :base_url
861 868  
862 869 def helper_for_article(article)
863 870 article_helper = ActionView::Base.new
... ... @@ -902,13 +909,15 @@ module ApplicationHelper
902 909 end
903 910  
904 911 def page_title
905   - (@page ? @page.title + ' - ' : '') +
906   - (@topic ? @topic.title + ' - ' : '') +
907   - (@section ? @section.title + ' - ' : '') +
908   - (@toc ? _('Online Manual') + ' - ' : '') +
909   - (controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') +
910   - (profile ? profile.short_name : environment.name) +
911   - (@category ? " - #{@category.full_name}" : '')
  912 + CGI.escapeHTML(
  913 + (@page ? @page.title + ' - ' : '') +
  914 + (@topic ? @topic.title + ' - ' : '') +
  915 + (@section ? @section.title + ' - ' : '') +
  916 + (@toc ? _('Online Manual') + ' - ' : '') +
  917 + (controller.controller_name == 'chat' ? _('Chat') + ' - ' : '') +
  918 + (profile ? profile.short_name : environment.name) +
  919 + (@category ? " - #{@category.full_name}" : '')
  920 + )
912 921 end
913 922  
914 923 # DEPRECATED. Do not use this.
... ... @@ -937,9 +946,9 @@ module ApplicationHelper
937 946 # from Article model for an ArticleBlock.
938 947 def reference_to_article(text, article, anchor=nil)
939 948 if article.profile.domains.empty?
940   - href = "/#{article.url[:profile]}/"
  949 + href = "#{Noosfero.root}/#{article.url[:profile]}/"
941 950 else
942   - href = "http://#{article.profile.domains.first.name}/"
  951 + href = "http://#{article.profile.domains.first.name}#{Noosfero.root}/"
943 952 end
944 953 href += article.url[:page].join('/')
945 954 href += '#' + anchor if anchor
... ... @@ -1280,11 +1289,13 @@ module ApplicationHelper
1280 1289 end
1281 1290  
1282 1291 def delete_article_message(article)
1283   - if article.folder?
1284   - _("Are you sure that you want to remove the folder \"#{article.name}\"? Note that all the items inside it will also be removed!")
1285   - else
1286   - _("Are you sure that you want to remove the item \"#{article.name}\"?")
1287   - end
  1292 + CGI.escapeHTML(
  1293 + if article.folder?
  1294 + _("Are you sure that you want to remove the folder \"%s\"? Note that all the items inside it will also be removed!") % article.name
  1295 + else
  1296 + _("Are you sure that you want to remove the item \"%s\"?") % article.name
  1297 + end
  1298 + )
1288 1299 end
1289 1300  
1290 1301 def expirable_link_to(expired, content, url, options = {})
... ... @@ -1301,7 +1312,7 @@ module ApplicationHelper
1301 1312 end
1302 1313  
1303 1314 def template_options(kind, field_name)
1304   - templates = environment.send(kind).templates.order('name')
  1315 + templates = environment.send(kind).templates
1305 1316 return '' if templates.count == 0
1306 1317 if templates.count == 1
1307 1318 if templates.first.custom_fields == {}
... ... @@ -1315,10 +1326,16 @@ module ApplicationHelper
1315 1326 content_tag('div', custom_fields)
1316 1327 end
1317 1328 else
1318   - options = options_for_select(templates.collect{ |template| [template.name, template.id]})
1319   - content_tag('div',
1320   - content_tag('div', content_tag('label', _('Profile organization'), :class => 'formlabel') + (select_tag 'profile_data[template_id]', options, :onchange => 'show_fields_for_template(this);')),
1321   - :id => 'template-options')
  1329 + radios = templates.map do |template|
  1330 + content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template)))
  1331 + end.join("\n")
  1332 +
  1333 + content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') +
  1334 + content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') +
  1335 + content_tag('ul', radios, :style => 'list-style: none; padding-left: 20px; margin-top: 0.5em;'),
  1336 + :id => 'template-options',
  1337 + :style => 'margin-top: 1em'
  1338 + )
1322 1339 end
1323 1340 end
1324 1341  
... ... @@ -1375,7 +1392,7 @@ module ApplicationHelper
1375 1392 # are old things that do not support it we are keeping this hot spot.
1376 1393 html = @plugins.pipeline(:parse_content, html, source).first
1377 1394 end
1378   - html
  1395 + html && html.html_safe
1379 1396 end
1380 1397  
1381 1398 def convert_macro(html, source)
... ...
app/helpers/article_helper.rb
... ... @@ -3,6 +3,12 @@ module ArticleHelper
3 3 include PrototypeHelper
4 4 include TokenHelper
5 5  
  6 + def article_reported_version(article)
  7 + search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions')
  8 + partial_path = File.join('shared', 'reported_versions', 'profile', partial_for_class_in_view_path(article.class, search_path))
  9 + render_to_string(:partial => partial_path, :locals => {:article => article})
  10 + end
  11 +
6 12 def custom_options_for_article(article, tokenized_children)
7 13 @article = article
8 14  
... ... @@ -71,12 +77,59 @@ module ArticleHelper
71 77 content_tag('div',
72 78 radio_button(:article, :published, false) +
73 79 content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private")
74   - ) +
75   - (article.profile.community? ? content_tag('div',
76   - content_tag('label', _('Fill in the search field to add the exception users to see this content'), :id => "text-input-search-exception-users") +
77   - token_input_field_tag(:q, 'search-article-privacy-exceptions', {:action => 'search_article_privacy_exceptions'},
78   - {:focus => false, :hint_text => _('Type in a search term for a user'), :pre_populate => tokenized_children})) :
79   - ''))
  80 + ) +
  81 + privacity_exceptions(article, tokenized_children)
  82 + )
  83 + end
  84 +
  85 + def privacity_exceptions(article, tokenized_children)
  86 + content_tag('div',
  87 + content_tag('div',
  88 + (
  89 + if article.profile
  90 + add_option_to_followers(article, tokenized_children)
  91 + else
  92 + ''
  93 + end
  94 + )
  95 + ),
  96 + :style => "margin-left:10px"
  97 + )
  98 + end
  99 +
  100 + def add_option_to_followers(article, tokenized_children)
  101 + label_message = article.profile.organization? ? _('For all community members') : _('For all your friends')
  102 +
  103 + check_box(
  104 + :article,
  105 + :show_to_followers,
  106 + {:class => "custom_privacy_option"}
  107 + ) +
  108 + content_tag(
  109 + 'label',
  110 + label_message,
  111 + :for => 'article_show_to_followers',
  112 + :id => 'label_show_to_followers'
  113 + ) +
  114 + (article.profile.community? ?
  115 + content_tag(
  116 + 'div',
  117 + content_tag(
  118 + 'label',
  119 + _('Fill in the search field to add the exception users to see this content'),
  120 + :id => "text-input-search-exception-users"
  121 + ) +
  122 + token_input_field_tag(
  123 + :q,
  124 + 'search-article-privacy-exceptions',
  125 + {:action => 'search_article_privacy_exceptions'},
  126 + {
  127 + :focus => false,
  128 + :hint_text => _('Type in a search term for a user'),
  129 + :pre_populate => tokenized_children
  130 + }
  131 + )
  132 + ) : '')
80 133 end
81 134  
82 135 def prepare_to_token_input(array)
... ...
app/helpers/boxes_helper.rb
... ... @@ -170,49 +170,54 @@ module BoxesHelper
170 170 else
171 171 "before-block-#{block.id}"
172 172 end
173   -
174   - content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover')
  173 + if block.nil? or modifiable?(block)
  174 + content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover')
  175 + else
  176 + ""
  177 + end
175 178 end
176 179  
177 180 # makes the given block draggable so it can be moved away.
178 181 def block_handle(block)
179   - draggable_element("block-#{block.id}", :revert => true)
  182 + modifiable?(block) ? draggable_element("block-#{block.id}", :revert => true) : ""
180 183 end
181 184  
182 185 def block_edit_buttons(block)
183 186 buttons = []
184 187 nowhere = 'javascript: return false;'
185 188  
186   - if block.first?
187   - buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere)
188   - else
189   - buttons << icon_button('up', _('Move block up'), { :action => 'move_block_up', :id => block.id }, { :method => 'post' })
190   - end
  189 + if modifiable?(block)
  190 + if block.first?
  191 + buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere)
  192 + else
  193 + buttons << icon_button('up', _('Move block up'), { :action => 'move_block_up', :id => block.id }, { :method => 'post' })
  194 + end
191 195  
192   - if block.last?
193   - buttons << icon_button('down-disabled', _("Can't move down anymore."), nowhere)
194   - else
195   - buttons << icon_button(:down, _('Move block down'), { :action => 'move_block_down' ,:id => block.id }, { :method => 'post'})
196   - end
  196 + if block.last?
  197 + buttons << icon_button('down-disabled', _("Can't move down anymore."), nowhere)
  198 + else
  199 + buttons << icon_button(:down, _('Move block down'), { :action => 'move_block_down' ,:id => block.id }, { :method => 'post'})
  200 + end
197 201  
198   - holder = block.owner
199   - # move to opposite side
200   - # FIXME too much hardcoded stuff
201   - if holder.layout_template == 'default'
202   - if block.box.position == 2 # area 2, left side => move to right side
203   - buttons << icon_button('right', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[2].id.to_s, :id => block.id }, :method => 'post' )
204   - elsif block.box.position == 3 # area 3, right side => move to left side
205   - buttons << icon_button('left', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[1].id.to_s, :id => block.id }, :method => 'post' )
  202 + holder = block.owner
  203 + # move to opposite side
  204 + # FIXME too much hardcoded stuff
  205 + if holder.layout_template == 'default'
  206 + if block.box.position == 2 # area 2, left side => move to right side
  207 + buttons << icon_button('right', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[2].id.to_s, :id => block.id }, :method => 'post' )
  208 + elsif block.box.position == 3 # area 3, right side => move to left side
  209 + buttons << icon_button('left', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[1].id.to_s, :id => block.id }, :method => 'post' )
  210 + end
206 211 end
207   - end
208 212  
209   - if block.editable?
210   - buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
211   - end
  213 + if block.editable?
  214 + buttons << colorbox_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  215 + end
212 216  
213   - if !block.main?
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_block', :id => block.id }, { :method => 'post' })
  217 + if !block.main?
  218 + buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})
  219 + buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })
  220 + end
216 221 end
217 222  
218 223 if block.respond_to?(:help)
... ... @@ -248,5 +253,7 @@ module BoxesHelper
248 253 classes
249 254 end
250 255  
251   -
  256 + def modifiable?(block)
  257 + return !block.fixed || environment.admins.include?(user)
  258 + end
252 259 end
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -10,7 +10,7 @@ module ContentViewerHelper
10 10 end
11 11  
12 12 def number_of_comments(article)
13   - display_number_of_comments(article.comments_count - article.spam_comments_count)
  13 + display_number_of_comments(article.comments_count - article.spam_comments_count.to_i)
14 14 end
15 15  
16 16 def article_title(article, args = {})
... ... @@ -45,7 +45,7 @@ module ContentViewerHelper
45 45 { article.environment.locales[translation.language] => { :href => url_for(translation.url) } }
46 46 end
47 47 content_tag(:div, link_to(_('Translations'), '#',
48   - :onmouseover => "toggleSubmenu(this, '#{_('Translations')}', #{links.to_json}); return false",
  48 + :onmouseover => "toggleSubmenu(this, '#{_('Translations')}', #{CGI::escape_html(links.to_json)}); return false",
49 49 :class => 'article-translations-menu simplemenu-trigger up'),
50 50 :class => 'article-translations')
51 51 end
... ...
app/helpers/layout_helper.rb
... ... @@ -2,12 +2,31 @@ module LayoutHelper
2 2  
3 3 def body_classes
4 4 # Identify the current controller and action for the CSS:
  5 + (logged_in? ? " logged-in" : "") +
5 6 " controller-#{controller.controller_name}" +
6 7 " action-#{controller.controller_name}-#{controller.action_name}" +
7 8 " template-#{@layout_template || if profile.blank? then 'default' else profile.layout_template end}" +
8 9 (!profile.nil? && profile.is_on_homepage?(request.path,@page) ? " profile-homepage" : "")
9 10 end
10 11  
  12 + def html_tag_classes
  13 + [
  14 + body_classes, (
  15 + profile.blank? ? nil : [
  16 + 'profile-type-is-' + profile.class.name.downcase,
  17 + 'profile-name-is-' + profile.identifier,
  18 + ]
  19 + ), 'theme-' + current_theme,
  20 + @plugins.dispatch(:html_tag_classes).map do |content|
  21 + if content.respond_to?(:call)
  22 + instance_exec(&content)
  23 + else
  24 + content.html_safe
  25 + end
  26 + end
  27 + ].flatten.compact.join(' ')
  28 + end
  29 +
11 30 def noosfero_javascript
12 31 plugins_javascripts = @plugins.map { |plugin| [plugin.js_files].flatten.map { |js| plugin.class.public_path(js) } }.flatten
13 32  
... ... @@ -17,6 +36,8 @@ module LayoutHelper
17 36 unless plugins_javascripts.empty?
18 37 output += javascript_include_tag plugins_javascripts, :cache => "cache/plugins-#{Digest::MD5.hexdigest plugins_javascripts.to_s}"
19 38 end
  39 + output += theme_javascript_ng.to_s
  40 +
20 41 output
21 42 end
22 43  
... ... @@ -84,6 +105,10 @@ module LayoutHelper
84 105 theme_path + '/style.css'
85 106 end
86 107  
  108 + def layout_template
  109 + if profile then profile.layout_template else environment.layout_template end
  110 + end
  111 +
87 112 def addthis_javascript
88 113 if NOOSFERO_CONF['addthis_enabled']
89 114 '<script src="https://s7.addthis.com/js/152/addthis_widget.js"></script>'
... ... @@ -91,7 +116,7 @@ module LayoutHelper
91 116 end
92 117  
93 118 def meta_description_tag(article=nil)
94   - article ? truncate(strip_tags(article.body.to_s), :length => 200) : environment.name
  119 + article ? CGI.escapeHTML(truncate(strip_tags(article.body.to_s), :length => 200)) : environment.name
95 120 end
96 121 end
97 122  
... ...
app/helpers/person_notifier_helper.rb
... ... @@ -1,15 +0,0 @@
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_helper.rb
1 1 module ProfileHelper
2 2  
3   - def display_field(title, profile, field, force = false)
  3 + COMMON_CATEGORIES = ActiveSupport::OrderedHash.new
  4 + COMMON_CATEGORIES[:content] = [:blogs, :image_galleries, :events, :article_tags]
  5 + COMMON_CATEGORIES[:interests] = [:interests]
  6 + COMMON_CATEGORIES[:general] = nil
  7 +
  8 + PERSON_CATEGORIES = ActiveSupport::OrderedHash.new
  9 + PERSON_CATEGORIES[:basic_information] = [:nickname, :sex, :birth_date, :location, :privacy_setting, :created_at]
  10 + PERSON_CATEGORIES[:contact] = [:contact_phone, :cell_phone, :comercial_phone, :contact_information, :email, :personal_website, :jabber_id]
  11 + PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality]
  12 + PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity]
  13 + PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study]
  14 + PERSON_CATEGORIES[:network] = [:friends, :communities, :enterprises]
  15 + PERSON_CATEGORIES.merge!(COMMON_CATEGORIES)
  16 +
  17 + ORGANIZATION_CATEGORIES = ActiveSupport::OrderedHash.new
  18 + ORGANIZATION_CATEGORIES[:basic_information] = [:display_name, :created_at, :foundation_year, :type, :language, :members_count, :location, :address_reference, :historic_and_current_context, :admins]
  19 + ORGANIZATION_CATEGORIES[:contact] = [:contact_person, :contact_phone, :contact_email, :organization_website, :jabber_id]
  20 + ORGANIZATION_CATEGORIES[:economic] = [:business_name, :acronym, :economic_activity, :legal_form, :products, :activities_short_description, :management_information]
  21 + ORGANIZATION_CATEGORIES.merge!(COMMON_CATEGORIES)
  22 +
  23 + CATEGORY_MAP = ActiveSupport::OrderedHash.new
  24 + CATEGORY_MAP[:person] = PERSON_CATEGORIES
  25 + CATEGORY_MAP[:organization] = ORGANIZATION_CATEGORIES
  26 +
  27 + FORCE = {
  28 + :person => [:privacy_setting],
  29 + :organization => [:privacy_setting, :location],
  30 + }
  31 +
  32 + MULTIPLE = {
  33 + :person => [:blogs, :image_galleries, :interests],
  34 + :organization => [:blogs, :image_galleries, :interests],
  35 + }
  36 +
  37 + CUSTOM_LABELS = {
  38 + :zip_code => _('ZIP code'),
  39 + :email => _('e-Mail'),
  40 + :jabber_id => _('Jabber'),
  41 + :birth_date => _('Date of birth'),
  42 + :created_at => _('Profile created at'),
  43 + :members_count => _('Members'),
  44 + :privacy_setting => _('Privacy setting'),
  45 + :article_tags => _('Tags')
  46 + }
  47 +
  48 + EXCEPTION = {
  49 + :person => [:image, :preferred_domain, :description, :tag_list],
  50 + :organization => [:image, :preferred_domain, :description, :tag_list, :address, :zip_code, :city, :state, :country, :district]
  51 + }
  52 +
  53 + def general_fields
  54 + categorized_fields = CATEGORY_MAP[kind].values.flatten
  55 + profile.class.fields.map(&:to_sym) - categorized_fields - EXCEPTION[kind]
  56 + end
  57 +
  58 + def kind
  59 + if profile.kind_of?(Person)
  60 + :person
  61 + else
  62 + :organization
  63 + end
  64 + end
  65 +
  66 + def title(field, entry = nil)
  67 + return self.send("#{field}_custom_title", entry) if MULTIPLE[kind].include?(field) && entry.present?
  68 + CUSTOM_LABELS[field.to_sym] || _(field.to_s.humanize)
  69 + end
  70 +
  71 + def display_field(field)
  72 + force = FORCE[kind].include?(field)
  73 + multiple = MULTIPLE[kind].include?(field)
4 74 unless force || profile.may_display_field_to?(field, user)
5 75 return ''
6 76 end
7   - value = profile.send(field)
8   - if !value.blank?
9   - if block_given?
10   - value = yield(value)
11   - end
12   - content_tag('tr', content_tag('td', title, :class => 'field-name') + content_tag('td', value))
  77 + value = begin profile.send(field) rescue nil end
  78 + return '' if value.blank?
  79 + if value.kind_of?(Hash)
  80 + content = self.send("treat_#{field}", value)
  81 + content_tag('tr', content_tag('td', title(field), :class => 'field-name') + content_tag('td', content))
13 82 else
14   - ''
  83 + entries = multiple ? value : [] << value
  84 + entries.map do |entry|
  85 + content = self.send("treat_#{field}", entry)
  86 + unless content.blank?
  87 + content_tag('tr', content_tag('td', title(field, entry), :class => 'field-name') + content_tag('td', content))
  88 + end
  89 + end.join("\n")
15 90 end
16 91 end
17 92  
18   - def display_contact(profile)
19   - fields = []
20   - fields << display_field(_('Address:'), profile, :address).html_safe
21   - fields << display_field(_('ZIP code:'), profile, :zip_code).html_safe
22   - fields << display_field(_('Contact phone:'), profile, :contact_phone).html_safe
23   - fields << display_field(_('e-Mail:'), profile, :email) { |email| link_to_email(email) }.html_safe
24   - fields << display_field(_('Personal website:'), profile, :personal_website).html_safe
25   - fields << display_field(_('Jabber:'), profile, :jabber_id).html_safe
26   - if fields.reject!(&:blank?).empty?
27   - ''
28   - else
29   - content_tag('tr', content_tag('th', _('Contact'), { :colspan => 2 })) + fields.join.html_safe
  93 + def treat_email(email)
  94 + link_to_email(email)
  95 + end
  96 +
  97 + def treat_organization_website(url)
  98 + link_to(url, url)
  99 + end
  100 +
  101 + def treat_sex(gender)
  102 + { 'male' => _('Male'), 'female' => _('Female') }[gender]
  103 + end
  104 +
  105 + def treat_date(date)
  106 + show_date(date.to_date)
  107 + end
  108 + alias :treat_birth_date :treat_date
  109 + alias :treat_created_at :treat_date
  110 +
  111 + def treat_friends(friends)
  112 + link_to friends.count, :controller => 'profile', :action => 'friends'
  113 + end
  114 +
  115 + def treat_communities(communities)
  116 + link_to communities.count, :controller => "profile", :action => 'communities'
  117 + end
  118 +
  119 + def treat_enterprises(enterprises)
  120 + if environment.disabled?('disable_asset_enterprises')
  121 + link_to enterprises.count, :controller => "profile", :action => 'enterprises'
  122 + end
  123 + end
  124 +
  125 + def treat_members_count(count)
  126 + link_to count, :controller => 'profile', :action => 'members'
  127 + end
  128 +
  129 + def treat_products(products)
  130 + if profile.kind_of?(Enterprise) && profile.environment.enabled?('products_for_enterprises')
  131 + link_to _('Products/Services'), :controller => 'catalog', :action => 'index'
30 132 end
31 133 end
32 134  
33   - def display_work_info(profile)
34   - organization = display_field(_('Organization:'), profile, :organization)
35   - organization_site = display_field(_('Organization website:'), profile, :organization_website) { |url| link_to(url, url) }
36   - if organization.blank? && organization_site.blank?
37   - ''
  135 + def treat_admins(admins)
  136 + profile.admins.map { |admin| link_to(admin.short_name, admin.url)}.join(', ')
  137 + end
  138 +
  139 + def treat_blogs(blog)
  140 + link_to(n_('One post', '%{num} posts', blog.posts.published.count) % { :num => blog.posts.published.count }, blog.url)
  141 + end
  142 +
  143 + def treat_image_galleries(gallery)
  144 + link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url)
  145 + end
  146 +
  147 + def treat_events(events)
  148 + link_to events.published.count, :controller => 'events', :action => 'events'
  149 + end
  150 +
  151 + def treat_article_tags(tags)
  152 + tag_cloud @tags, :id, { :action => 'tags' }, :max_size => 18, :min_size => 10
  153 + end
  154 +
  155 + def treat_interests(interest)
  156 + link_to interest.name, :controller => 'search', :action => 'category_index', :category_path => interest.explode_path
  157 + end
  158 +
  159 + def article_custom_title(article)
  160 + article.name
  161 + end
  162 + alias :blogs_custom_title :article_custom_title
  163 + alias :image_galleries_custom_title :article_custom_title
  164 +
  165 + def interests_custom_title(interest)
  166 + ''
  167 + end
  168 +
  169 + def method_missing(method, *args, &block)
  170 + if method.to_s =~ /^treat_(.+)$/
  171 + args[0]
  172 + elsif method.to_s =~ /^display_(.+)$/ && CATEGORY_MAP[kind].has_key?($1.to_sym)
  173 + category = $1.to_sym
  174 + fields = category == :general ? general_fields : CATEGORY_MAP[kind][category]
  175 + contents = []
  176 +
  177 + fields.each do |field|
  178 + contents << display_field(field).html_safe
  179 + end
  180 +
  181 + contents = contents.delete_if(&:blank?)
  182 +
  183 + unless contents.empty?
  184 + content_tag('tr', content_tag('th', title(category), { :colspan => 2 })) + contents.join.html_safe
  185 + else
  186 + ''
  187 + end
38 188 else
39   - content_tag('tr', content_tag('th', _('Work'), { :colspan => 2 })) + organization + organization_site
  189 + super
40 190 end
41 191 end
42 192  
... ...
app/helpers/role_helper.rb
1 1 module RoleHelper
  2 +
  3 + def role_available_permissions(role)
  4 + role.kind == "Environment" ? ['Environment', 'Profile'] : [role.kind]
  5 + end
  6 +
2 7 end
... ...
app/helpers/search_helper.rb
... ... @@ -21,6 +21,12 @@ module SearchHelper
21 21 'more_comments' => _('More comments')
22 22 }
23 23  
  24 + COMMON_PROFILE_LIST_BLOCK = [
  25 + :enterprises,
  26 + :people,
  27 + :communities
  28 + ]
  29 +
24 30 # FIXME remove it after search_controler refactored
25 31 include EventsHelper
26 32  
... ... @@ -94,7 +100,7 @@ module SearchHelper
94 100 compact_link = display?(asset, :compact) ? (display == 'compact' ? _('Compact') : link_to(_('Compact'), params.merge(:display => 'compact'))) : nil
95 101 map_link = display?(asset, :map) ? (display == 'map' ? _('Map') : link_to(_('Map'), params.merge(:display => 'map'))) : nil
96 102 full_link = display?(asset, :full) ? (display == 'full' ? _('Full') : link_to(_('Full'), params.merge(:display => 'full'))) : nil
97   - content_tag('div',
  103 + content_tag('div',
98 104 content_tag('strong', _('Display')) + ': ' + [compact_link, map_link, full_link].compact.join(' | ').html_safe,
99 105 :class => 'search-customize-options'
100 106 )
... ...
app/helpers/sweeper_helper.rb
... ... @@ -56,12 +56,12 @@ module SweeperHelper
56 56 if profile
57 57 profile.blocks.each {|block|
58 58 conditions = block.class.expire_on
59   - blocks_to_expire << block unless (conditions[:profile] & causes).empty?
  59 + blocks_to_expire << block unless (conditions[:profile] & causes).blank?
60 60 }
61 61 end
62 62 environment.blocks.each {|block|
63 63 conditions = block.class.expire_on
64   - blocks_to_expire << block unless (conditions[:environment] & causes).empty?
  64 + blocks_to_expire << block unless (conditions[:environment] & causes).blank?
65 65 }
66 66  
67 67 blocks_to_expire.uniq!
... ...
app/helpers/tinymce_helper.rb 0 → 100644
... ... @@ -0,0 +1,51 @@
  1 +module TinymceHelper
  2 + include MacrosHelper
  3 +
  4 + def tinymce_js
  5 + output = ''
  6 + output += javascript_include_tag 'tinymce/js/tinymce/tinymce.min.js'
  7 + output += javascript_include_tag 'tinymce/js/tinymce/jquery.tinymce.min.js'
  8 + output += javascript_include_tag 'tinymce.js'
  9 + output += include_macro_js_files.to_s
  10 + output
  11 + end
  12 +
  13 + def tinymce_init_js options = {}
  14 + options.merge! :document_base_url => top_url,
  15 + :content_css => "/stylesheets/tinymce.css,#{macro_css_files}",
  16 + :plugins => %w[compat3x advlist autolink lists link image charmap print preview hr anchor pagebreak
  17 + searchreplace wordcount visualblocks visualchars code fullscreen
  18 + insertdatetime media nonbreaking save table contextmenu directionality
  19 + emoticons template paste textcolor colorpicker textpattern],
  20 + :language => tinymce_language
  21 +
  22 + options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
  23 + if options[:mode] == 'simple'
  24 + options[:menubar] = false
  25 + else
  26 + options[:menubar] = 'edit insert view tools'
  27 + options[:toolbar2] = 'print preview code media | table'
  28 +
  29 + options[:toolbar2] += ' | macros'
  30 + macros_with_buttons.each do |macro|
  31 + options[:toolbar2] += " #{macro.identifier}"
  32 + end
  33 + end
  34 +
  35 + options[:macros_setup] = macros_with_buttons.map do |macro|
  36 + <<-EOS
  37 + ed.addButton('#{macro.identifier}', {
  38 + title: #{macro_title(macro).to_json},
  39 + onclick: #{generate_macro_config_dialog macro},
  40 + image : '#{macro.configuration[:icon_path]}'
  41 + });
  42 + EOS
  43 + end
  44 +
  45 + #cleanup non tinymce options
  46 + options = options.except :mode
  47 +
  48 + "noosfero.tinymce.init(#{options.to_json})"
  49 + end
  50 +
  51 +end
... ...
app/models/article.rb
... ... @@ -2,7 +2,14 @@ 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, :external_link, :image_builder
  5 + attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent,
  6 + :allow_members_to_edit, :translation_of_id, :language,
  7 + :license_id, :parent_id, :display_posts_in_current_language,
  8 + :category_ids, :posts_per_page, :moderate_comments,
  9 + :accept_comments, :feed, :published, :source,
  10 + :highlighted, :notify_comments, :display_hits, :slug,
  11 + :external_feed_builder, :display_versions, :external_link,
  12 + :image_builder, :show_to_followers
6 13  
7 14 acts_as_having_image
8 15  
... ... @@ -157,14 +164,17 @@ class Article &lt; ActiveRecord::Base
157 164 self.profile
158 165 end
159 166  
160   - def self.human_attribute_name(attrib, options = {})
  167 + def self.human_attribute_name_with_customization(attrib, options={})
161 168 case attrib.to_sym
162 169 when :name
163 170 _('Title')
164 171 else
165   - _(self.superclass.human_attribute_name(attrib))
  172 + _(self.human_attribute_name_without_customization(attrib))
166 173 end
167 174 end
  175 + class << self
  176 + alias_method_chain :human_attribute_name, :customization
  177 + end
168 178  
169 179 def css_class_list
170 180 [self.class.name.to_css_class]
... ... @@ -282,13 +292,6 @@ class Article &lt; ActiveRecord::Base
282 292 end
283 293 end
284 294  
285   - def reported_version(options = {})
286   - article = self
287   - search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions')
288   - partial_path = File.join('shared', 'reported_versions', partial_for_class_in_view_path(article.class, search_path))
289   - lambda { render_to_string(:partial => partial_path, :locals => {:article => article}) }
290   - end
291   -
292 295 # returns the data of the article. Must be overriden in each subclass to
293 296 # provide the correct content for the article.
294 297 def data
... ... @@ -337,7 +340,7 @@ class Article &lt; ActiveRecord::Base
337 340 def belongs_to_blog?
338 341 self.parent and self.parent.blog?
339 342 end
340   -
  343 +
341 344 def belongs_to_forum?
342 345 self.parent and self.parent.forum?
343 346 end
... ... @@ -449,6 +452,7 @@ class Article &lt; ActiveRecord::Base
449 452 if self.parent && !self.parent.published?
450 453 return false
451 454 end
  455 +
452 456 true
453 457 else
454 458 false
... ... @@ -480,14 +484,17 @@ class Article &lt; ActiveRecord::Base
480 484 {:conditions => [" articles.published = ? OR
481 485 articles.last_changed_by_id = ? OR
482 486 articles.profile_id = ? OR
483   - ?",
484   - true, user.id, user.id, user.has_permission?(:view_private_content, profile)] }
  487 + ? OR articles.show_to_followers = ? AND ?",
  488 + true, user.id, user.id, user.has_permission?(:view_private_content, profile),
  489 + true, user.follows?(profile)]}
485 490 end
486 491  
  492 +
487 493 def display_unpublished_article_to?(user)
488 494 user == author || allow_view_private_content?(user) || user == profile ||
489 495 user.is_admin?(profile.environment) || user.is_admin?(profile) ||
490   - article_privacy_exceptions.include?(user)
  496 + article_privacy_exceptions.include?(user) ||
  497 + (self.show_to_followers && user.follows?(profile))
491 498 end
492 499  
493 500 def display_to?(user = nil)
... ...
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
  3 + attr_accessible :title, :display, :limit, :box_id, :posts_per_page, :visualization_format, :language, :display_user, :box, :fixed
4 4  
5 5 # to be able to generate HTML
6 6 include ActionView::Helpers::UrlHelper
... ... @@ -64,7 +64,7 @@ class Block &lt; ActiveRecord::Base
64 64 end
65 65  
66 66 def display_to_user?(user)
67   - display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged')
  67 + display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && user.follows?(owner))
68 68 end
69 69  
70 70 def display_always(context)
... ... @@ -75,7 +75,7 @@ class Block &lt; ActiveRecord::Base
75 75 if context[:article]
76 76 return context[:article] == owner.home_page
77 77 else
78   - return context[:request_path] == '/'
  78 + return home_page_path?(context[:request_path])
79 79 end
80 80 end
81 81  
... ... @@ -83,7 +83,7 @@ class Block &lt; ActiveRecord::Base
83 83 if context[:article]
84 84 return context[:article] != owner.home_page
85 85 else
86   - return context[:request_path] != '/' + (owner.kind_of?(Profile) ? owner.identifier : '')
  86 + return !home_page_path?(context[:request_path])
87 87 end
88 88 end
89 89  
... ... @@ -110,11 +110,14 @@ class Block &lt; ActiveRecord::Base
110 110 # * <tt>'all'</tt>: the block is always displayed
111 111 settings_items :language, :type => :string, :default => 'all'
112 112  
  113 + # The block can be configured to be fixed. Only can be edited by environment admins
  114 + settings_items :fixed, :type => :boolean, :default => false
  115 +
113 116 # returns the description of the block, used when the user sees a list of
114 117 # blocks to choose one to include in the design.
115 118 #
116 119 # Must be redefined in subclasses to match the description of each block
117   - # type.
  120 + # type.
118 121 def self.description
119 122 '(dummy)'
120 123 end
... ... @@ -124,13 +127,13 @@ class Block &lt; ActiveRecord::Base
124 127 # This method can return several types of objects:
125 128 #
126 129 # * <tt>String</tt>: if the string starts with <tt>http://</tt> or <tt>https://</tt>, then it is assumed to be address of an IFRAME. Otherwise it's is used as regular HTML.
127   - # * <tt>Hash</tt>: the hash is used to build an URL that is used as the address for a IFRAME.
  130 + # * <tt>Hash</tt>: the hash is used to build an URL that is used as the address for a IFRAME.
128 131 # * <tt>Proc</tt>: the Proc is evaluated in the scope of BoxesHelper. The
129 132 # block can then use <tt>render</tt>, <tt>link_to</tt>, etc.
130 133 #
131 134 # The method can also return <tt>nil</tt>, which means "no content".
132 135 #
133   - # See BoxesHelper#extract_block_content for implementation details.
  136 + # See BoxesHelper#extract_block_content for implementation details.
134 137 def content(args={})
135 138 "This is block number %d" % self.id
136 139 end
... ... @@ -192,7 +195,7 @@ class Block &lt; ActiveRecord::Base
192 195  
193 196 # Override in your subclasses.
194 197 # Define which events and context should cause the block cache to expire
195   - # Possible events are: :article, :profile, :friendship, :category
  198 + # Possible events are: :article, :profile, :friendship, :category, :role_assignment
196 199 # Possible contexts are: :profile, :environment
197 200 def self.expire_on
198 201 {
... ... @@ -221,6 +224,7 @@ class Block &lt; ActiveRecord::Base
221 224 'all' => _('All users'),
222 225 'logged' => _('Logged'),
223 226 'not_logged' => _('Not logged'),
  227 + 'followers' => owner.class != Environment && owner.organization? ? _('Members') : _('Friends')
224 228 }
225 229 end
226 230  
... ... @@ -234,4 +238,26 @@ class Block &lt; ActiveRecord::Base
234 238 duplicated_block
235 239 end
236 240  
  241 + def copy_from(block)
  242 + self.settings = block.settings
  243 + self.position = block.position
  244 + end
  245 +
  246 + private
  247 +
  248 + def home_page_path
  249 + home_page_url = Noosfero.root('/')
  250 +
  251 + if owner.kind_of?(Profile)
  252 + home_page_url += "profile/" if owner.home_page.nil?
  253 + home_page_url += owner.identifier
  254 + end
  255 +
  256 + return home_page_url
  257 + end
  258 +
  259 + def home_page_path? path
  260 + return path == home_page_path || path == (home_page_path + '/')
  261 + end
  262 +
237 263 end
... ...
app/models/blog.rb
... ... @@ -53,7 +53,7 @@ class Blog &lt; Folder
53 53 def prepare_external_feed
54 54 unless self.external_feed_data.nil?
55 55 if self.external_feed(true) && self.external_feed.id == self.external_feed_data[:id].to_i
56   - self.external_feed.attributes = self.external_feed_data
  56 + self.external_feed.attributes = self.external_feed_data.except(:id)
57 57 else
58 58 self.build_external_feed(self.external_feed_data, :without_protection => true)
59 59 end
... ...
app/models/change_password.rb
... ... @@ -2,16 +2,19 @@ class ChangePassword &lt; Task
2 2  
3 3 attr_accessor :password, :password_confirmation
4 4  
5   - def self.human_attribute_name(attrib, options = {})
  5 + def self.human_attribute_name_with_customization(attrib, options={})
6 6 case attrib.to_sym
7 7 when :password
8 8 _('Password')
9 9 when :password_confirmation
10 10 _('Password Confirmation')
11 11 else
12   - _(self.superclass.human_attribute_name(attrib))
  12 + _(self.human_attribute_name_without_customization(attrib))
13 13 end
14 14 end
  15 + class << self
  16 + alias_method_chain :human_attribute_name, :customization
  17 + end
15 18  
16 19 validates_presence_of :requestor
17 20  
... ...
app/models/community.rb
... ... @@ -50,16 +50,6 @@ class Community &lt; Organization
50 50 super + FIELDS
51 51 end
52 52  
53   - validate :presence_of_required_fieds
54   -
55   - def presence_of_required_fieds
56   - self.required_fields.each do |field|
57   - if self.send(field).blank?
58   - self.errors.add_on_blank(field)
59   - end
60   - end
61   - end
62   -
63 53 def active_fields
64 54 environment ? environment.active_community_fields : []
65 55 end
... ... @@ -78,7 +68,7 @@ class Community &lt; Organization
78 68 end
79 69  
80 70 def default_template
81   - environment.community_template
  71 + environment.community_default_template
82 72 end
83 73  
84 74 def news(limit = 30, highlight = false)
... ...
app/models/domain.rb
... ... @@ -92,4 +92,11 @@ class Domain &lt; ActiveRecord::Base
92 92 @hosting = {}
93 93 end
94 94  
  95 + # Detects a domain's custom text domain chain if available based on a domain
  96 + # served on multitenancy configuration or a registered domain.
  97 + def self.custom_locale(domainname)
  98 + domain = Noosfero::MultiTenancy.mapping[domainname] || domainname[/(.*?)\./,1]
  99 + FastGettext.translation_repositories.keys.include?(domain) ? domain : FastGettext.default_text_domain
  100 + end
  101 +
95 102 end
... ...
app/models/enterprise.rb
... ... @@ -59,16 +59,6 @@ class Enterprise &lt; Organization
59 59 super + FIELDS
60 60 end
61 61  
62   - validate :presence_of_required_fieds
63   -
64   - def presence_of_required_fieds
65   - self.required_fields.each do |field|
66   - if self.send(field).blank?
67   - self.errors.add_on_blank(field)
68   - end
69   - end
70   - end
71   -
72 62 def active_fields
73 63 environment ? environment.active_enterprise_fields : []
74 64 end
... ... @@ -107,7 +97,12 @@ class Enterprise &lt; Organization
107 97 self.tasks.where(:type => 'EnterpriseActivation').first
108 98 end
109 99  
110   - def enable(owner)
  100 + def enable(owner = nil)
  101 + if owner.nil?
  102 + self.visible = true
  103 + return self.save
  104 + end
  105 +
111 106 return if enabled
112 107 # must be set first for the following to work
113 108 self.enabled = true
... ... @@ -169,7 +164,7 @@ class Enterprise &lt; Organization
169 164 end
170 165  
171 166 def default_template
172   - environment.enterprise_template
  167 + environment.enterprise_default_template
173 168 end
174 169  
175 170 def template_with_inactive_enterprise
... ...
app/models/environment.rb
... ... @@ -283,6 +283,7 @@ class Environment &lt; ActiveRecord::Base
283 283 www.flickr.com
284 284 www.gmodules.com
285 285 www.youtube.com
  286 + openstreetmap.org
286 287 ] + ('a' .. 'z').map{|i| "#{i}.yimg.com"}
287 288  
288 289 settings_items :enabled_plugins, :type => Array, :default => Noosfero::Plugin.available_plugin_names
... ... @@ -656,10 +657,11 @@ class Environment &lt; ActiveRecord::Base
656 657 { :controller => 'admin_panel', :action => 'index' }
657 658 end
658 659  
659   - def top_url
660   - url = 'http://'
  660 + def top_url(scheme = 'http')
  661 + url = scheme + '://'
661 662 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
662 663 url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port)
  664 + url << Noosfero.root('')
663 665 url
664 666 end
665 667  
... ... @@ -727,31 +729,50 @@ class Environment &lt; ActiveRecord::Base
727 729 ]
728 730 end
729 731  
730   - def community_template
  732 + def is_default_template?(template)
  733 + is_default = template == community_default_template
  734 + is_default = is_default || template == person_default_template
  735 + is_default = is_default || template == enterprise_default_template
  736 + is_default
  737 + end
  738 +
  739 + def community_templates
  740 + self.communities.templates
  741 + end
  742 +
  743 + def community_default_template
731 744 template = Community.find_by_id settings[:community_template_id]
732   - template if template && template.is_template
  745 + template if template && template.is_template?
  746 + end
  747 +
  748 + def community_default_template=(value)
  749 + settings[:community_template_id] = value.kind_of?(Community) ? value.id : value
733 750 end
734 751  
735   - def community_template=(value)
736   - settings[:community_template_id] = value.id
  752 + def person_templates
  753 + self.people.templates
737 754 end
738 755  
739   - def person_template
  756 + def person_default_template
740 757 template = Person.find_by_id settings[:person_template_id]
741   - template if template && template.is_template
  758 + template if template && template.is_template?
  759 + end
  760 +
  761 + def person_default_template=(value)
  762 + settings[:person_template_id] = value.kind_of?(Person) ? value.id : value
742 763 end
743 764  
744   - def person_template=(value)
745   - settings[:person_template_id] = value.id
  765 + def enterprise_templates
  766 + self.enterprises.templates
746 767 end
747 768  
748   - def enterprise_template
  769 + def enterprise_default_template
749 770 template = Enterprise.find_by_id settings[:enterprise_template_id]
750   - template if template && template.is_template
  771 + template if template && template.is_template?
751 772 end
752 773  
753   - def enterprise_template=(value)
754   - settings[:enterprise_template_id] = value.id
  774 + def enterprise_default_template=(value)
  775 + settings[:enterprise_template_id] = value.kind_of?(Enterprise) ? value.id : value
755 776 end
756 777  
757 778 def inactive_enterprise_template
... ... @@ -804,7 +825,7 @@ class Environment &lt; ActiveRecord::Base
804 825 end
805 826  
806 827 def notification_emails
807   - [noreply_email.blank? ? nil : noreply_email].compact + admins.map(&:email)
  828 + [contact_email].select(&:present?) + admins.map(&:email)
808 829 end
809 830  
810 831 after_create :create_templates
... ... @@ -849,10 +870,10 @@ class Environment &lt; ActiveRecord::Base
849 870 person_template.visible = false
850 871 person_template.save!
851 872  
852   - self.enterprise_template = enterprise_template
  873 + self.enterprise_default_template = enterprise_template
853 874 self.inactive_enterprise_template = inactive_enterprise_template
854   - self.community_template = community_template
855   - self.person_template = person_template
  875 + self.community_default_template = community_template
  876 + self.person_default_template = person_template
856 877 self.save!
857 878 end
858 879  
... ... @@ -916,6 +937,10 @@ class Environment &lt; ActiveRecord::Base
916 937 locales_list
917 938 end
918 939  
  940 + def has_license?
  941 + self.licenses.any?
  942 + end
  943 +
919 944 private
920 945  
921 946 def default_language_available
... ...
app/models/event.rb
... ... @@ -19,7 +19,7 @@ class Event &lt; Article
19 19 maybe_add_http(self.setting[:link])
20 20 end
21 21  
22   - xss_terminate :only => [ :body, :link, :address ], :with => 'white_list', :on => 'validation'
  22 + xss_terminate :only => [ :name, :body, :link, :address ], :with => 'white_list', :on => 'validation'
23 23  
24 24 def initialize(*args)
25 25 super(*args)
... ...
app/models/external_feed.rb
... ... @@ -10,9 +10,10 @@ class ExternalFeed &lt; ActiveRecord::Base
10 10 { :conditions => ['(fetched_at is NULL) OR (fetched_at < ?)', Time.now - FeedUpdater.update_interval] }
11 11 }
12 12  
13   - attr_accessible :address, :enabled
  13 + attr_accessible :address, :enabled, :only_once
14 14  
15 15 def add_item(title, link, date, content)
  16 + return if content.blank?
16 17 doc = Hpricot(content)
17 18 doc.search('*').each do |p|
18 19 if p.instance_of? Hpricot::Elem
... ... @@ -30,6 +31,7 @@ class ExternalFeed &lt; ActiveRecord::Base
30 31 article.source = link
31 32 article.profile = blog.profile
32 33 article.parent = blog
  34 + article.author_name = self.feed_title
33 35 unless blog.children.exists?(:slug => article.slug)
34 36 article.save!
35 37 article.delay.create_activity
... ...
app/models/feed_reader_block.rb
... ... @@ -85,8 +85,4 @@ class FeedReaderBlock &lt; Block
85 85 block_title(title) + formatted_feed_content
86 86 end
87 87  
88   - def editable?
89   - true
90   - end
91   -
92 88 end
... ...
app/models/folder.rb
... ... @@ -12,7 +12,7 @@ class Folder &lt; Article
12 12  
13 13 acts_as_having_settings :field => :setting
14 14  
15   - xss_terminate :only => [ :body ], :with => 'white_list', :on => 'validation'
  15 + xss_terminate :only => [ :name, :body ], :with => 'white_list', :on => 'validation'
16 16  
17 17 include WhiteListFilter
18 18 filter_iframes :body
... ...
app/models/invitation.rb
... ... @@ -65,18 +65,16 @@ class Invitation &lt; Task
65 65  
66 66 task_args = if user.nil?
67 67 {:person => person, :friend_name => friend_name, :friend_email => friend_email, :message => message}
68   - elsif !user.person.is_a_friend?(person)
  68 + else
69 69 {:person => person, :target => user.person}
70 70 end
71 71  
72   - if !task_args.nil?
73   - if profile.person?
74   - InviteFriend.create(task_args)
75   - elsif profile.community?
76   - InviteMember.create(task_args.merge(:community_id => profile.id))
77   - else
78   - raise NotImplementedError, 'Don\'t know how to invite people to a %s' % profile.class.to_s
79   - end
  72 + if profile.person?
  73 + InviteFriend.create(task_args) if user.nil? || !user.person.is_a_friend?(person)
  74 + elsif profile.community?
  75 + InviteMember.create(task_args.merge(:community_id => profile.id)) if user.nil? || !user.person.is_member_of?(profile)
  76 + else
  77 + raise NotImplementedError, 'Don\'t know how to invite people to a %s' % profile.class.to_s
80 78 end
81 79 end
82 80 end
... ...
app/models/link_list_block.rb
... ... @@ -78,16 +78,17 @@ class LinkListBlock &lt; Block
78 78 address
79 79 end
80 80 if add !~ /^[a-z]+:\/\// && add !~ /^\//
81   - 'http://' + add
  81 + '//' + add
82 82 else
  83 + if root = Noosfero.root
  84 + if !add.starts_with?(root)
  85 + add = root + add
  86 + end
  87 + end
83 88 add
84 89 end
85 90 end
86 91  
87   - def editable?
88   - true
89   - end
90   -
91 92 def icons_options
92 93 ICONS.map do |i|
93 94 "<span title=\"#{i[1]}\" class=\"icon-#{i[0]}\" onclick=\"changeIcon(this, '#{i[0]}')\"></span>".html_safe
... ... @@ -100,4 +101,5 @@ class LinkListBlock &lt; Block
100 101 sanitizer = HTML::WhiteListSanitizer.new
101 102 sanitizer.sanitize(text)
102 103 end
  104 +
103 105 end
... ...
app/models/main_block.rb
... ... @@ -16,10 +16,6 @@ class MainBlock &lt; Block
16 16 true
17 17 end
18 18  
19   - def editable?
20   - true
21   - end
22   -
23 19 def cacheable?
24 20 false
25 21 end
... ...
app/models/organization.rb
... ... @@ -30,6 +30,16 @@ class Organization &lt; Profile
30 30  
31 31 scope :more_popular, :order => 'members_count DESC'
32 32  
  33 + validate :presence_of_required_fieds, :unless => :is_template
  34 +
  35 + def presence_of_required_fieds
  36 + self.required_fields.each do |field|
  37 + if self.send(field).blank?
  38 + self.errors.add_on_blank(field)
  39 + end
  40 + end
  41 + end
  42 +
33 43 def validation_methodology
34 44 self.validation_info ? self.validation_info.validation_methodology : nil
35 45 end
... ... @@ -135,7 +145,11 @@ class Organization &lt; Profile
135 145 end
136 146  
137 147 def notification_emails
138   - [contact_email.blank? ? nil : contact_email].compact + admins.map(&:email)
  148 + emails = [contact_email].select(&:present?) + admins.map(&:email)
  149 + if emails.empty?
  150 + emails << environment.contact_email
  151 + end
  152 + emails
139 153 end
140 154  
141 155 def already_request_membership?(person)
... ...
app/models/person.rb
... ... @@ -21,6 +21,12 @@ class Person &lt; Profile
21 21 { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => [conditions] }
22 22 }
23 23  
  24 + scope :by_role, lambda { |roles|
  25 + roles = [roles] unless roles.kind_of?(Array)
  26 + { :select => 'DISTINCT profiles.*', :joins => :role_assignments, :conditions => ['role_assignments.role_id IN (?)',
  27 +roles] }
  28 + }
  29 +
24 30 def has_permission_with_plugins?(permission, profile)
25 31 permissions = [has_permission_without_plugins?(permission, profile)]
26 32 permissions += plugins.map do |plugin|
... ... @@ -74,6 +80,10 @@ class Person &lt; Profile
74 80  
75 81 belongs_to :user, :dependent => :delete
76 82  
  83 + def can_change_homepage?
  84 + !environment.enabled?('cant_change_homepage') || is_admin?
  85 + end
  86 +
77 87 def can_control_scrap?(scrap)
78 88 begin
79 89 !self.scraps(scrap).nil?
... ... @@ -161,7 +171,7 @@ class Person &lt; Profile
161 171 FIELDS
162 172 end
163 173  
164   - validate :presence_of_required_fields
  174 + validate :presence_of_required_fields, :unless => :is_template
165 175  
166 176 def presence_of_required_fields
167 177 self.required_fields.each do |field|
... ... @@ -300,7 +310,7 @@ class Person &lt; Profile
300 310 end
301 311  
302 312 def default_template
303   - environment.person_template
  313 + environment.person_default_template
304 314 end
305 315  
306 316 def apply_type_specific_template(template)
... ...
app/models/person_notifier.rb
... ... @@ -67,7 +67,7 @@ class PersonNotifier
67 67  
68 68 class Mailer < ActionMailer::Base
69 69  
70   - add_template_helper(PersonNotifierHelper)
  70 + add_template_helper(ApplicationHelper)
71 71  
72 72 def session
73 73 {:theme => nil}
... ...
app/models/product.rb
... ... @@ -11,7 +11,7 @@ class Product &lt; ActiveRecord::Base
11 11  
12 12 SEARCH_DISPLAYS = %w[map full]
13 13  
14   - attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs
  14 + attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs, :qualifiers_list
15 15  
16 16 def self.default_search_display
17 17 'full'
... ...
app/models/profile.rb
... ... @@ -125,7 +125,7 @@ class Profile &lt; ActiveRecord::Base
125 125 end
126 126  
127 127 def members_by_name
128   - members.order(:name)
  128 + members.order('profiles.name')
129 129 end
130 130  
131 131 class << self
... ... @@ -136,8 +136,8 @@ class Profile &lt; ActiveRecord::Base
136 136 alias_method_chain :count, :distinct
137 137 end
138 138  
139   - def members_by_role(role)
140   - Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id])
  139 + def members_by_role(roles)
  140 + Person.members_of(self).by_role(roles)
141 141 end
142 142  
143 143 acts_as_having_boxes
... ... @@ -149,7 +149,9 @@ class Profile &lt; ActiveRecord::Base
149 149 end
150 150  
151 151 scope :visible, :conditions => { :visible => true }
  152 + scope :disabled, :conditions => { :visible => false }
152 153 scope :public, :conditions => { :visible => true, :public_profile => true }
  154 + scope :enabled, :conditions => { :enabled => true }
153 155  
154 156 # Subclasses must override this method
155 157 scope :more_popular
... ... @@ -374,16 +376,17 @@ class Profile &lt; ActiveRecord::Base
374 376 end
375 377  
376 378 def copy_blocks_from(profile)
  379 + template_boxes = profile.boxes.select{|box| box.position}
377 380 self.boxes.destroy_all
378   - profile.boxes.each do |box|
379   - new_box = Box.new
  381 + self.boxes = template_boxes.size.times.map { Box.new }
  382 +
  383 + template_boxes.each_with_index do |box, i|
  384 + new_box = self.boxes[i]
380 385 new_box.position = box.position
381   - self.boxes << new_box
382 386 box.blocks.each do |block|
383 387 new_block = block.class.new(:title => block[:title])
384   - new_block.settings = block.settings
385   - new_block.position = block.position
386   - self.boxes[-1].blocks << new_block
  388 + new_block.copy_from(block)
  389 + new_box.blocks << new_block
387 390 end
388 391 end
389 392 end
... ... @@ -418,7 +421,7 @@ class Profile &lt; ActiveRecord::Base
418 421 end
419 422  
420 423 xss_terminate :only => [ :name, :nickname, :address, :contact_phone, :description ], :on => 'validation'
421   - xss_terminate :only => [ :custom_footer, :custom_header ], :with => 'white_list', :on => 'validation'
  424 + xss_terminate :only => [ :custom_footer, :custom_header ], :with => 'white_list'
422 425  
423 426 include WhiteListFilter
424 427 filter_iframes :custom_header, :custom_footer
... ... @@ -802,7 +805,7 @@ private :generate_url, :url_options
802 805 end
803 806  
804 807 include Noosfero::Plugin::HotSpot
805   -
  808 +
806 809 def folder_types
807 810 types = Article.folder_types
808 811 plugins.dispatch(:content_types).each {|type|
... ... @@ -926,6 +929,13 @@ private :generate_url, :url_options
926 929 end
927 930  
928 931 def disable
  932 + self.visible = false
  933 + self.save
  934 + end
  935 +
  936 + def enable
  937 + self.visible = true
  938 + self.save
929 939 end
930 940  
931 941 def control_panel_settings_button
... ...
app/models/profile_image_block.rb
... ... @@ -23,10 +23,6 @@ class ProfileImageBlock &lt; Block
23 23 end
24 24 end
25 25  
26   - def editable?
27   - true
28   - end
29   -
30 26 def cacheable?
31 27 false
32 28 end
... ...
app/models/profile_info_block.rb
... ... @@ -15,10 +15,6 @@ class ProfileInfoBlock &lt; Block
15 15 end
16 16 end
17 17  
18   - def editable?
19   - false
20   - end
21   -
22 18 def cacheable?
23 19 false
24 20 end
... ...
app/models/profile_search_block.rb
... ... @@ -11,8 +11,4 @@ class ProfileSearchBlock &lt; Block
11 11 end
12 12 end
13 13  
14   - def editable?
15   - true
16   - end
17   -
18 14 end
... ...
app/models/task.rb
... ... @@ -285,8 +285,9 @@ class Task &lt; ActiveRecord::Base
285 285 # If
286 286 def send_notification(action)
287 287 if sends_email?
288   - if self.requestor
289   - TaskMailer.generic_message("task_#{action}", self)
  288 + if self.requestor && !self.requestor.notification_emails.empty?
  289 + message = TaskMailer.generic_message("task_#{action}", self)
  290 + message.deliver if message
290 291 end
291 292 end
292 293 end
... ...
app/models/user.rb
... ... @@ -16,15 +16,18 @@ class User &lt; ActiveRecord::Base
16 16 end
17 17  
18 18 # FIXME ugly workaround
19   - def self.human_attribute_name(attrib, options={})
  19 + def self.human_attribute_name_with_customization(attrib, options={})
20 20 case attrib.to_sym
21 21 when :login
22 22 return [_('Username'), _('Email')].join(' / ')
23 23 when :email
24 24 return _('e-Mail')
25   - else _(self.superclass.human_attribute_name(attrib))
  25 + else _(self.human_attribute_name_without_customization(attrib))
26 26 end
27 27 end
  28 + class << self
  29 + alias_method_chain :human_attribute_name, :customization
  30 + end
28 31  
29 32 before_create do |user|
30 33 if user.environment.nil?
... ... @@ -198,6 +201,10 @@ class User &lt; ActiveRecord::Base
198 201 Digest::MD5.hexdigest(password)
199 202 end
200 203  
  204 + add_encryption_method :salted_md5 do |password, salt|
  205 + Digest::MD5.hexdigest(password+salt)
  206 + end
  207 +
201 208 add_encryption_method :clear do |password, salt|
202 209 password
203 210 end
... ... @@ -347,6 +354,7 @@ class User &lt; ActiveRecord::Base
347 354 end
348 355  
349 356 def delay_activation_check
  357 + return if person.is_template?
350 358 Delayed::Job.enqueue(UserActivationJob.new(self.id), {:priority => 0, :run_at => 72.hours.from_now})
351 359 end
352 360 end
... ...
app/sweepers/role_assignment_sweeper.rb
... ... @@ -13,20 +13,22 @@ class RoleAssignmentSweeper &lt; ActiveRecord::Observer
13 13 protected
14 14  
15 15 def expire_caches(role_assignment)
16   - expire_cache(role_assignment.accessor)
17   - expire_cache(role_assignment.resource) if role_assignment.resource.respond_to?(:cache_keys)
  16 + expire_cache(role_assignment.accessor) if role_assignment.accessor.kind_of?(Profile)
  17 + expire_cache(role_assignment.resource) if role_assignment.resource.kind_of?(Profile)
18 18 end
19 19  
20 20 def expire_cache(profile)
21 21 per_page = Noosfero::Constants::PROFILE_PER_PAGE
22   - profile.cache_keys(:per_page => per_page).each { |ck|
23   - expire_timeout_fragment(ck)
24   - }
  22 +
  23 + profile.cache_keys(:per_page => per_page).each { |ck| expire_timeout_fragment(ck) }
  24 + expire_timeout_fragment(profile.members_cache_key(:per_page => per_page))
25 25  
26 26 profile.blocks_to_expire_cache.each { |block|
27 27 blocks = profile.blocks.select{|b| b.kind_of?(block)}
28 28 BlockSweeper.expire_blocks(blocks)
29 29 }
  30 +
  31 + expire_blocks_cache(profile, [:role_assignment])
30 32 end
31 33  
32 34 end
... ...
app/views/admin_panel/index.html.erb
... ... @@ -20,6 +20,7 @@
20 20 <tr><td><%= link_to _('Users'), :controller => 'users' %></td></tr>
21 21 <tr><td><%= link_to _('Profile templates'), :controller => 'templates' %></td></tr>
22 22 <tr><td><%= link_to _('Fields'), :controller => 'features', :action => 'manage_fields' %></td></tr>
  23 + <tr><td><%= link_to _('Manage organizations status'), :action => 'manage_organizations_status' %></td></tr>
23 24 </table>
24 25  
25 26  
... ...
app/views/admin_panel/manage_organizations_status.html.erb 0 → 100644
... ... @@ -0,0 +1,69 @@
  1 +<h1><%= _('Manage organizations') %></h1>
  2 +
  3 +<%= form_tag( { :action => 'manage_organizations_status' }, :method => 'get', :class => 'users-search' ) do %>
  4 +
  5 + <div class="search-field">
  6 + <span class="formfield">
  7 + <%= text_field_tag 'q', @q, :title => _("Find profiles"), :style=>"width:85%" %>
  8 + </span>
  9 +
  10 + <%= submit_button(:search, _('Search')) %>
  11 + </div>
  12 +
  13 + <div class="environment-users-results-header">
  14 + <div id='environment-users-filter-title'><%= @title %></div>
  15 +
  16 + <div id="environment-users-filter-filter">
  17 + <strong><%= _("Filter by: ") %></strong>
  18 +
  19 + <select id="profile_filter_select">
  20 + <%= options_for_select([['Any', 'any'],["Disabled profiles", "disabled"], ["Enabled profiles", "enabled"]], @filter) %>
  21 + </select>
  22 + </div>
  23 + <div style="clear: both"></div>
  24 + </div>
  25 +
  26 + <table>
  27 + <colgroup>
  28 + <col width="80%">
  29 + <col width="20%">
  30 + </colgroup>
  31 +
  32 + <tr>
  33 + <th><%= _('Member') %></th>
  34 + <th><%= _('Actions') %></th>
  35 + </tr>
  36 +
  37 + <% @collection.each do |p| %>
  38 + <tr title="<%= p.name %>">
  39 + <td><%= link_to_profile p.short_name, p.identifier, :title => p.name %> </td>
  40 +
  41 + <td class='actions'>
  42 + <div class="members-buttons-cell">
  43 + <% if p.visible %>
  44 + <%= button_without_text :'deactivate-user', _('Deactivate'), {:controller => "profile_editor", :action => 'deactivate_profile', :profile => p.identifier, :id => p.id}, :confirm => _("Do you want to deactivate this profile ?") %>
  45 + <% else %>
  46 + <%= button_without_text :'activate-user', _('Activate'), {:controller => "profile_editor", :action => 'activate_profile', :profile => p.identifier, :id => p.id}, :confirm => _("Do you want to activate this profile ?") %>
  47 + <% end %>
  48 + <%= button_without_text :'delete', _('Remove'), {:controller => "profile_editor", :action => 'destroy_profile', :profile => p.identifier, :id => p.id, :return_to => "/admin/admin_panel/manage_organizations_status"}, :method => :post, :confirm => _("Do you want to deactivate this profile ?") %>
  49 + </div>
  50 + </td>
  51 + </tr>
  52 + <% end %>
  53 + </table>
  54 +
  55 +<% end %>
  56 +
  57 +<%= pagination_links @collection, {:param_name => 'npage', :page_links => true} %>
  58 +
  59 +<% button_bar do %>
  60 + <%= button :back, _('Back'), :controller => 'admin_panel' %>
  61 +<% end %>
  62 +
  63 +<script type="text/javascript">
  64 + jQuery(document).ready(function(){
  65 + jQuery("#profile_filter_select").change(function(){
  66 + document.location.href = '/admin/admin_panel/manage_organizations_status?filter='+this.value;
  67 + });
  68 + });
  69 +</script>
0 70 \ No newline at end of file
... ...
app/views/box_organizer/edit.html.erb
... ... @@ -5,6 +5,12 @@
5 5  
6 6 <%= labelled_form_field(_('Custom title for this block: '), text_field(:block, :title, :maxlength => 20)) %>
7 7  
  8 + <% if environment.admins.include?(user) %>
  9 + <div class="fixed_block">
  10 + <%= labelled_check_box(_("Fixed"), "block[fixed]", value = "1", checked = @block.fixed) %>
  11 + </div>
  12 + <% end %>
  13 +
8 14 <%= render :partial => partial_for_class(@block.class) %>
9 15  
10 16 <div class="display">
... ...
app/views/catalog/index.html.erb
... ... @@ -14,8 +14,8 @@
14 14  
15 15 <ul id="product-list">
16 16 <% @products.each do |product| %>
17   - <% extra_content = @plugins.dispatch(:catalog_item_extras, product).collect { |content| instance_eval(&content) } %>
18   - <% extra_content_list = @plugins.dispatch(:catalog_list_item_extras, product).collect { |content| instance_eval(&content) } %>
  17 + <% extra_content = @plugins.dispatch(:catalog_item_extras, product).collect { |content| instance_exec(&content) } %>
  18 + <% extra_content_list = @plugins.dispatch(:catalog_list_item_extras, product).collect { |content| instance_exec(&content) } %>
19 19  
20 20 <% status = [] %>
21 21 <% status << 'not-available' if !product.available %>
... ...
app/views/cms/_general_fields.html.erb
1 1 <%= select_profile_folder(_('Parent folder:'), 'article[parent_id]', profile, @article.parent_id) %>
2   -<%= labelled_form_field(_('License'), select(:article, :license_id, options_for_select_with_title([[_('None'), nil]] + profile.environment.licenses.map {|license| [license.name, license.id]}, @article.license ? @article.license.id : nil))) %>
  2 +<% if profile.environment.has_license? %>
  3 + <%= labelled_form_field(_('License'), select(:article, :license_id, options_for_select_with_title([[_('None'), nil]] + profile.environment.licenses.map {|license| [license.name, license.id]}, @article.license ? @article.license.id : nil))) %>
  4 +<% end %>
... ...
app/views/cms/upload_files.html.erb
... ... @@ -20,5 +20,10 @@
20 20 <h5><%= _('Uploading files to %s') % content_tag('code', @target) %></h5>
21 21  
22 22 <%= form_for('uploaded_file', :url => { :action => 'upload_files' }, :html => {:multipart => true}) do |f| %>
  23 +
  24 + <%= @plugins.dispatch(:upload_files_extra_fields, params[:parent_id]).collect { |content| instance_exec(&content) }.join("") %>
  25 +
23 26 <%= render :partial => 'upload_file_form', :locals => { :size => '45'} %>
24   -<% end %>
  27 +
  28 +<% end %>
  29 +
... ...
app/views/cms/view.html.erb
... ... @@ -2,7 +2,7 @@
2 2 <%= _('Content management') %>
3 3 </h1>
4 4  
5   -<% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %>
  5 +<% if user.can_change_homepage? && !remove_content_button(:home) %>
6 6 <div class="cms-homepage">
7 7 <%= _('Profile homepage:') %>
8 8 <% if profile.home_page %>
... ... @@ -69,7 +69,7 @@
69 69 <%= expirable_button article, :edit, _('Edit'), {:action => 'edit', :id => article.id} if !remove_content_button(:edit) %>
70 70 <%= button_without_text :eyes, _('Public view'), article.view_url %>
71 71 <%= display_spread_button(profile, article) unless article.folder? || remove_content_button(:spread)%>
72   - <% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %>
  72 + <% if user.can_change_homepage? && !remove_content_button(:home) %>
73 73 <% if profile.home_page != article %>
74 74 <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
75 75 <% else %>
... ...
app/views/contact/new.html.erb
... ... @@ -13,11 +13,16 @@
13 13  
14 14 <%= required_fields_message %>
15 15  
16   - <% location_fields = select_city(true) %>
  16 + <% unless logged_in? %>
  17 + <%= required f.text_field(:name) %>
  18 + <%= required f.text_field(:email) %>
  19 + <% end %>
17 20  
  21 + <% location_fields = select_city(true) %>
18 22 <% unless environment.enabled?('disable_select_city_for_contact') || location_fields.blank? %>
19 23 <%= labelled_form_field _('City and state'), location_fields %>
20 24 <% end %>
  25 +
21 26 <%= required f.text_field(:subject) %>
22 27  
23 28 <%= render :file => 'shared/tiny_mce' %>
... ... @@ -25,5 +30,9 @@
25 30  
26 31 <%= labelled_form_field check_box(:contact, :receive_a_copy) + _('I want to receive a copy of the message in my e-mail.'), '' %>
27 32  
28   - <%= submit_button(:send, _('Send'), :onclick => "$('confirm').value = 'true'") %>
  33 + <% unless logged_in? %>
  34 + <%= recaptcha_tags :ajax => true, :display => {:theme => 'clean'} %>
  35 + <% end %>
  36 +
  37 + <%= submit_button(:send, _('Send'), :onclick => "jQuery('#confirm').val('true')") %>
29 38 <% end %>
... ...
app/views/content_viewer/view_page.html.erb
... ... @@ -70,37 +70,36 @@
70 70  
71 71 <%= @plugins.dispatch(:article_extra_contents, @page).collect { |content| instance_exec(&content) }.join("") %>
72 72  
73   -<div class="comments" id="comments_list">
74   -
75   - <% if @page.accept_comments? || @comments_count > 0 %>
  73 +<% if @page.accept_comments? || @comments_count > 0 %>
  74 + <div class="comments" id="comments_list">
76 75 <h3 <%= 'class="no-comments-yet"' if @comments_count == 0 %>>
77 76 <%= display_number_of_comments(@comments_count) %>
78 77 </h3>
79   - <% end %>
80 78  
81   - <% if @comments.present? && @comments.count > 1 %>
82   - <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form', :id => 'top-post-comment-button', :onclick => "jQuery('#page-comment-form .display-comment-form').first().click();") if @page.accept_comments? %>
  79 + <% if @comments.present? && @comments.count > 1 %>
  80 + <%= link_to(_('Post a comment'), '#', :class => 'display-comment-form', :id => 'top-post-comment-button', :onclick => "jQuery('#page-comment-form .display-comment-form').first().click();") if @page.accept_comments? %>
  81 +
  82 + <%= hidden_field_tag("page_url", url_for(:controller=>'content_viewer', :action=>'view_page', :profile=>profile.identifier, :page => @page.explode_path)) %>
  83 + <%= javascript_include_tag "comment_order.js" %>
  84 + <div class="comment-order">
  85 + <%= form_tag({:controller=>'content_viewer' , :action=>'view_page'}, {:method=>'get', :id=>"form_order"}) do %>
  86 + <%= select_tag 'comment_order', options_for_select({_('Oldest first')=>'oldest', _('Newest first')=>'newest'}, @comment_order) %>
  87 + <% end %>
  88 + </div>
  89 + <% end %>
83 90  
84   - <%= hidden_field_tag("page_url", url_for(:controller=>'content_viewer', :action=>'view_page', :profile=>profile.identifier, :page => @page.explode_path)) %>
85   - <%= javascript_include_tag "comment_order.js" %>
86   - <div class="comment-order">
87   - <%= form_tag({:controller=>'content_viewer' , :action=>'view_page'}, {:method=>'get', :id=>"form_order"}) do %>
88   - <%= select_tag 'comment_order', options_for_select({_('Oldest first')=>'oldest', _('Newest first')=>'newest'}, @comment_order) %>
  91 + <ul class="article-comments-list">
  92 + <% if @comments.present? %>
  93 + <%= render :partial => 'comment/comment', :collection => @comments %>
  94 + <%= pagination_links @comments, :param_name => 'comment_page' %>
89 95 <% end %>
90   - </div>
91   - <% end %>
  96 + </ul>
92 97  
93   - <ul class="article-comments-list">
94   - <% if @comments.present? %>
95   - <%= render :partial => 'comment/comment', :collection => @comments %>
96   - <%= pagination_links @comments, :param_name => 'comment_page' %>
  98 + <% if @page.accept_comments? %>
  99 + <div id='page-comment-form' class='page-comment-form'><%= render :partial => 'comment/comment_form', :locals =>{:url => {:controller => :comment, :action => :create}, :display_link => true, :cancel_triggers_hide => true}%></div>
97 100 <% end %>
98   - </ul>
99   -
100   - <% if @page.accept_comments? %>
101   - <div id='page-comment-form' class='page-comment-form'><%= render :partial => 'comment/comment_form', :locals =>{:url => {:controller => :comment, :action => :create}, :display_link => true, :cancel_triggers_hide => true}%></div>
102   - <% end %>
103   -</div><!-- end class="comments" -->
  101 + </div><!-- end class="comments" -->
  102 +<% end %>
104 103  
105 104 </div><!-- end id="article" -->
106 105 <%= add_zoom_to_article_images %>
... ...
app/views/enterprise_registration/basic_information.html.erb
... ... @@ -20,7 +20,7 @@
20 20  
21 21 <%= labelled_form_for :create_enterprise do |f| %>
22 22 <%= required f.text_field 'name', :onchange => "updateUrlField(this, 'create_enterprise_identifier')", :size => 40 %>
23   - <%= required labelled_form_field(_('Address'), content_tag('code', environment.top_url + "/" + text_field(:create_enterprise, 'identifier', :size => 26))) %>
  23 + <%= required labelled_form_field(_('Address'), content_tag('code', top_url + "/" + text_field(:create_enterprise, 'identifier', :size => 26))) %>
24 24 <%= render :partial => 'shared/organization_custom_fields', :locals => { :f => f, :object_name => :create_enterprise, :profile => @create_enterprise } %>
25 25 <%= required labelled_form_field(_('Region'), f.select('region_id', @regions)) if @validation == :region %>
26 26  
... ...
app/views/events/_month.html.erb
... ... @@ -13,8 +13,8 @@
13 13 date.day,
14 14 :url => {:action => 'events_by_day', :year => date.year, :month => date.month, :day => date.day, :category_id => @category_id},
15 15 :update => 'events-of-the-day',
16   - :loading => '$("events-of-the-day").addClassName("loading")',
17   - :complete => '$("events-of-the-day").removeClassName("loading")'
  16 + :loading => "$('events-of-the-day').addClassName('loading')",
  17 + :complete => "$('events-of-the-day').removeClassName('loading')"
18 18 ) :
19 19 date.day
20 20 %>
... ...
app/views/events/events.html.erb
... ... @@ -3,7 +3,7 @@
3 3 <div id='agenda-toolbar'>
4 4 <%= button :back, _('Back to %s') % profile.name, profile.url %>
5 5 <% if user && user.has_permission?('post_content', profile) %>
6   - <%= button :new, _('New event'), myprofile_url(:controller => 'cms', :action => 'new', :type => 'Event') %>
  6 + <%= button :new, _('New event'), myprofile_path(:controller => 'cms', :action => 'new', :type => 'Event') %>
7 7 <% end %>
8 8 </div>
9 9  
... ...
app/views/file_presenter/_generic.html.erb
1 1 <span class="download-link">
2 2 <span>Download</span>
3   - <strong><%= link_to generic.filename, generic.public_filename %></strong>
  3 + <strong><%= link_to generic.filename, [Noosfero.root, generic.public_filename].join %></strong>
4 4 </span>
5 5  
6 6 <div class="uploaded-file-description <%= 'empty' if generic.abstract.blank? %>">
... ...
app/views/file_presenter/_image.html.erb
... ... @@ -28,7 +28,7 @@
28 28  
29 29 <%# image_tag(article.public_filename(:display), :class => article.css_class_name, :style => 'max-width: 100%') %>
30 30  
31   -<img src="<%=image.public_filename(:display)%>" class="<%=image.css_class_name%>">
  31 +<img src="<%= [Noosfero.root, image.public_filename(:display)].join %>" class="<%=image.css_class_name%>">
32 32  
33 33 <div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>">
34 34 <%= image.abstract %>
... ...
app/views/home/index.html.erb
... ... @@ -61,9 +61,6 @@
61 61 <%= submit_button(:search, _('Search')) %>
62 62 </div>
63 63  
64   - <div>
65   - <%= lightbox_link_to _('More options'), :controller => 'search', :action => 'popup' %>
66   - </div>
67 64 <% end %>
68 65 </div>
69 66 <% end %>
... ...
app/views/layouts/_content.html.erb 0 → 100644
... ... @@ -0,0 +1,4 @@
  1 +<div id="content-inner">
  2 + <%= insert_boxes(yield) %>
  3 + <br style='clear: both'/>
  4 +</div><!-- end id="content-inner" -->
... ...
app/views/layouts/application-ng.html.erb
1 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2   -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= html_language %>" lang="<%= html_language %>">
  2 +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= html_language %>" lang="<%= html_language %>" class="<%= h html_tag_classes %>">
3 3 <head>
4 4 <title><%= h page_title %></title>
5 5 <%= yield(:feeds) %>
... ... @@ -12,20 +12,8 @@
12 12 <meta name="twitter:title" content="<%= h page_title %>">
13 13 <meta name="twitter:description" content="<%= meta_description_tag(@page) %>">
14 14  
15   - <!-- Open Graph -->
16   - <meta property="og:type" content="<%= @page ? 'article' : 'website' %>">
17   - <meta property="og:url" content="<%= @page ? url_for(@page.url) : @environment.top_url %>">
18   - <meta property="og:title" content="<%= h page_title %>">
19   - <meta property="og:site_name" content="<%= profile ? profile.name : @environment.name %>">
20   - <meta property="og:description" content="<%= @page ? truncate(strip_tags(@page.body.to_s), :length => 200) : @environment.name %>">
21   -
22   - <% if @page %>
23   - <meta property="article:published_time" content="<%= show_date(@page.published_at) %>">
24   - <% @page.body_images_paths.each do |img| %>
25   - <meta name="twitter:image" content="<%= img.to_s %>">
26   - <meta property="og:image" content="<%= img.to_s %>">
27   - <% end %>
28   - <% end %>
  15 + <!-- site root -->
  16 + <meta property="noosfero:root" content="<%= Noosfero.root %>"/>
29 17  
30 18 <link rel="shortcut icon" href="<%= image_path(theme_favicon) %>" type="image/x-icon" />
31 19 <%= noosfero_javascript %>
... ... @@ -69,10 +57,7 @@
69 57 <div id="navigation-end"></div>
70 58 </div><!-- end id="navigation" -->
71 59 <div id="content">
72   - <div id="content-inner">
73   - <%= insert_boxes(yield) %>
74   - <br style='clear: both'/>
75   - </div><!-- end id="content-inner" -->
  60 + <%= render 'layouts/content' %>
76 61 </div><!-- end id="content" -->
77 62 </div><!-- end id="wrap-2" -->
78 63 </div><!-- end id="wrap-1" -->
... ... @@ -81,7 +66,6 @@
81 66 <%= theme_footer %>
82 67 </div><!-- end id="theme-footer" -->
83 68 <%= noosfero_layout_features %>
84   - <%= theme_javascript_ng %>
85 69 <%= addthis_javascript %>
86 70 <%=
87 71 @plugins.dispatch(:body_ending).map do |content|
... ...
app/views/layouts/application.html.erb
1 1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2   -<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= html_language %>" lang="<%= html_language %>">
  2 +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%= html_language %>" lang="<%= html_language %>" class="<%= h html_tag_classes %>">
3 3 <head>
4 4 <title><%= h page_title %></title>
5 5 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
... ... @@ -68,7 +68,7 @@
68 68  
69 69 <div id="navigation_bar">
70 70 <%= link_to "<span>"+ @environment.name() +"</span>",
71   - @environment.top_url,
  71 + top_url,
72 72 :id=>"menu_link_to_envhome",
73 73 :title=>@environment.name %>
74 74 <% unless environment.enabled?(:disable_categories) %>
... ...
app/views/manage_products/_edit_description.html.erb
1 1 <%= render :file => 'shared/tiny_mce', :locals => {:mode => 'simple'} %>
2 2 <%= remote_form_for(@product,
3 3 :loading => "small_loading('product-description-form')",
4   - :before => ("tinyMCE.triggerSave()" unless Rails.env == 'test'),
5 4 :update => 'product-description',
6 5 :url => {:controller => 'manage_products', :action => 'edit', :id => @product, :field => 'description'},
7 6 :html => {:id => 'product-description-form', :method => 'post'}) do |f| %>
... ...
app/views/manage_products/_edit_info.html.erb
... ... @@ -47,7 +47,7 @@
47 47 <%= button_to_function(
48 48 :add,
49 49 _('Add new qualifier'),
50   - "new_qualifier_row('#product-qualifiers-list', '#{escape_javascript(select_qualifiers(@product))}', '#{escape_javascript(remove_qualifier_button)}')"
  50 + "new_qualifier_row('#product-qualifiers-list', '#{escape_javascript(CGI::escape_html(select_qualifiers(@product)))}', '#{escape_javascript(CGI::escape_html(remove_qualifier_button))}')"
51 51 ) %>
52 52 <%= hidden_field_tag "product[qualifiers_list][nil]" %>
53 53 <% end %>
... ...
app/views/manage_products/show.html.erb
... ... @@ -13,7 +13,7 @@
13 13 <%= render :partial => 'manage_products/display_image' %>
14 14 </div>
15 15 <div id='product-extra-content'>
16   - <% extra_content = @plugins.dispatch(:product_info_extras, @product).collect { |content| instance_eval(&content) } %>
  16 + <% extra_content = @plugins.dispatch(:product_info_extras, @product).collect { |content| instance_exec(&content) } %>
17 17 <%= extra_content.join("\n") %>
18 18 </div>
19 19 <div id='product-info'>
... ...
app/views/profile/_common.html.erb
1 1 <% unless @action %>
2 2 <% cache_timeout(profile.cache_key + '-profile-general-info', 4.hours) do %>
3   - <tr>
4   - <th colspan='2'>
5   - <%= _('Content') %>
6   - </th>
7   - </tr>
8   -
9   - <% profile.blogs.each do |blog| %>
10   - <tr>
11   - <td><%= blog.name + ':' %></td>
12   - <td>
13   - <%= link_to(n_('One post', '%{num} posts', blog.posts.published.count) % { :num => blog.posts.published.count }, blog.url) %>
14   - </td>
15   - </tr>
16   - <% end %>
17   - <% profile.image_galleries.each do |gallery| %>
18   - <tr>
19   - <td><%= gallery.name + ':' %></td>
20   - <td>
21   - <%= link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) %>
22   - </td>
23   - </tr>
24   - <% end %>
25   -
26   - <tr>
27   - <td><%= _('Events:') %></td>
28   - <td>
29   - <%= link_to profile.events.published.count, :controller => 'events', :action => 'events' %>
30   - </td>
31   - </tr>
32   - <tr>
33   - <td>
34   - <%= _('Tags:') %>
35   - </td>
36   - <td>
37   - <%= tag_cloud @tags, :id, { :action => 'tags' }, :max_size => 18, :min_size => 10%>
38   - </td>
39   - </tr>
  3 + <%= display_content %>
40 4  
41 5 <% if !environment.enabled?('disable_categories') && !profile.interests.empty? %>
42   - <tr>
43   - <th colspan='2'><%= _('Interests') %></th>
44   - </tr>
45   - <% profile.interests.each do |item| %>
46   - <tr>
47   - <td></td>
48   - <td><%= link_to item.name, :controller => 'search', :action => 'category_index', :category_path => item.explode_path %></td>
49   - </tr>
50   - <% end %>
  6 + <%= display_interests %>
51 7 <% end %>
  8 +
  9 + <%= display_general %>
52 10 <% end %>
53 11 <% end %>
... ...
app/views/profile/_organization_profile.html.erb
1 1 <table>
2   - <tr>
3   - <th colspan='2'><%= _('Basic information')%></th>
4   - </tr>
5   -
6   - <tr>
7   - <td class='field-name'><%= _('Members') %></td>
8   - <td>
9   - <%= link_to profile.members_count, :controller => 'profile', :action => 'members' %>
10   - </td>
11   - </tr>
12   -
13   - <%= display_field(_('Type:'), profile, :privacy_setting, true) %>
14   -
15   - <%= display_field(_('Location:'), profile, :location, true) %>
16   -
17   - <tr>
18   - <td class='field-name'><%= _('Profile created at:') %></td>
19   - <td><%= show_date(profile.created_at) %></td>
20   - </tr>
21   -
22   - <% if profile.kind_of?(Enterprise) && profile.environment.enabled?('products_for_enterprises') %>
23   - <tr>
24   - <td></td>
25   - <td>
26   - <%= link_to _('Products/Services'), :controller => 'catalog', :action => 'index' %>
27   - </td>
28   - </tr>
29   - <% end %>
30   -
31   - <tr>
32   - <td class='field-name'><%= _('Administrators:') %></td>
33   - <td>
34   - <%= profile.admins.map { |admin| link_to(admin.short_name, admin.url)}.join(', ') %>
35   - </td>
36   - </tr>
37   -
  2 + <%= display_basic_information %>
  3 + <%= display_contact %>
  4 + <%= display_economic %>
38 5 <%= render :partial => 'common' %>
39 6 </table>
... ...
app/views/profile/_person_profile.html.erb
1 1 <table>
2   - <tr>
3   - <th colspan='2'><%= _('Basic information')%></th>
4   - </tr>
5   - <%= display_field(_('Sex:'), profile, :sex) { |gender| { 'male' => _('Male'), 'female' => _('Female') }[gender] } %>
6   - <%= display_field(_('Date of birth:'), profile, :birth_date) { |date| show_date(date) }%>
7   - <%= display_field _('Location:'), profile, :location %>
8   -
9   - <%= display_field(_('Type:'), profile, :privacy_setting, true) %>
10   -
11   - <tr>
12   - <td class='field-name'><%= _('Profile created at:') %></td>
13   - <td><%= show_date(profile.created_at) %></td>
14   - </tr>
15   -
16   - <%= display_contact profile %>
  2 + <%= display_basic_information %>
  3 + <%= display_contact %>
  4 + <%= display_location %>
17 5  
18 6 <% cache_timeout(profile.relationships_cache_key, 4.hours) do %>
19   - <%= display_work_info profile %>
20   -
21   - <%= display_custom_fields(profile) %>
22   -
23   - <tr>
24   - <th colspan='2'><%= _('Network')%></th>
25   - </tr>
26   - <tr>
27   - <td><%= _('Friends') + ':' %></td>
28   - <td><%= link_to profile.friends.count, { :controller => 'profile', :action => 'friends' } %></td>
29   - </tr>
30   - <tr>
31   - <td><%= _('Communities') + ':' %></td>
32   - <td><%= link_to profile.communities.count, :controller => "profile", :action => 'communities' %></td>
33   - </tr>
34   - <% if environment.disabled?('disable_asset_enterprises') %>
35   - <tr id="person-profile-network-enterprises">
36   - <td><%= _('Enterprises') + ':' %></td>
37   - <td><%= link_to profile.enterprises.count, :controller => "profile", :action => 'enterprises' %></td>
38   - </tr>
39   - <% end %>
  7 + <%= display_work %>
  8 + <%= display_study %>
  9 + <%= display_network %>
  10 + <%= display_custom_fields(profile) %>
40 11  
41 12 <%= render :partial => 'common' %>
42   -
43 13 <% end %>
44 14 </table>
  15 +
... ...
app/views/profile/_profile_comment_form.html.erb
... ... @@ -10,8 +10,8 @@
10 10 :rows => 1,
11 11 :class => 'submit-with-keypress',
12 12 :title => _('Leave your comment'),
13   - :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
14   - :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  13 + :onfocus => ("if(this.value==this.title){this.value='';this.style.color='#000'};this.style.backgroundImage='url(" + profile_icon(current_person, :icon, false) + ")'" if logged_in?),
  14 + :onblur => ("if(this.value==''){this.value=this.title;this.style.color='#ccc'};this.style.backgroundImage='none'" if logged_in?),
15 15 :value => _('Leave your comment'),
16 16 :style => 'color: #ccc' %>
17 17 <%= hidden_field_tag :source_id, activity.id, :id => "activity_id_#{activity.id}" %>
... ...
app/views/profile/_profile_scrap_reply_form.html.erb
... ... @@ -9,8 +9,8 @@
9 9 :rows => 1,
10 10 :class => 'submit-with-keypress',
11 11 :title => _('Leave your comment'),
12   - :onfocus => ('if(this.value==this.title){this.value="";this.style.color="#000"};this.style.backgroundImage="url(' + profile_icon(current_person, :icon, false) + ')"' if logged_in?),
13   - :onblur => ('if(this.value==""){this.value=this.title;this.style.color="#ccc"};this.style.backgroundImage="none"' if logged_in?),
  12 + :onfocus => ("if(this.value==this.title){this.value='';this.style.color='#000'};this.style.backgroundImage='url(" + profile_icon(current_person, :icon, false) + ")'" if logged_in?),
  13 + :onblur => ("if(this.value==''){this.value=this.title;this.style.color='#ccc'};this.style.backgroundImage='none'" if logged_in?),
14 14 :value => _('Leave your comment') %>
15 15 <%= hidden_field_tag 'scrap[scrap_id]', scrap.id %>
16 16 <%= hidden_field_tag 'receiver_id', scrap.sender.id %>
... ...
app/views/profile_editor/_person_form.html.erb
... ... @@ -25,6 +25,11 @@
25 25 <%= optional_field(@person, 'address', labelled_form_field(_('Address (street and number)'), text_field(:profile_data, :address, :rel => _('Address')))) %>
26 26 <%= optional_field(@person, 'address_reference', labelled_form_field(_('Address reference'), text_field(:profile_data, :address_reference, :rel => _('Address reference')))) %>
27 27 <%= optional_field(@person, 'district', labelled_form_field(_('District'), text_field(:profile_data, :district, :rel => _('District')))) %>
  28 +<%= optional_field(@person, 'image', labelled_form_field(_('Image'), file_field(:file, :image, :rel => _('Image')))) %>
  29 +
  30 +<% @plugins.dispatch(:extra_optional_fields).each do |field| %>
  31 + <%= optional_field(@person, field[:name], labelled_form_field(field[:label], text_field(field[:object_name], field[:method], :rel => field[:label], :value => field[:value]))) %>
  32 +<% end %>
28 33  
29 34 <% optional_field(@person, 'schooling') do %>
30 35 <div class="formfieldline">
... ...
app/views/profile_editor/edit.html.erb
1 1 <h1><%= _('Profile settings for %s') % profile.name %></h1>
2 2  
  3 +<%= javascript_include_tag 'deactivate_profile' %>
3 4 <%= error_messages_for :profile_data %>
4 5  
5 6 <%= labelled_form_for :profile_data, :html => { :id => 'profile-data', :multipart => true } do |f| %>
... ... @@ -67,6 +68,15 @@
67 68 <% if user && user.has_permission?('destroy_profile', profile) %>
68 69 <% button_bar(:id => 'delete-profile') do %>
69 70 <%= button(:remove, _('Delete profile'), {:action => :destroy_profile}) %>
  71 +
  72 + <% if environment.admins.include?(current_person) %>
  73 +
  74 + <% if profile.visible? %>
  75 + <%= button(:remove, _('Deactivate profile'), {:action => :deactivate_profile, :id=>profile.id}, :id=>'deactivate_profile_button', :data => {:confirm=>_("Are you sure you want to deactivate this profile?")}) %>
  76 + <% else %>
  77 + <%= button(:add, _('Activate profile'), {:action => :activate_profile, :id=>profile.id}, :data => {:confirm=>_("Are you sure you want to deactivate this profile?")}) %>
  78 + <% end %>
  79 + <% end %>
70 80 <% end %>
71 81 <% end %>
72 82 -<% end %>
  83 +<% end %>
73 84 \ No newline at end of file
... ...
app/views/role/_form.html.erb
... ... @@ -6,10 +6,14 @@
6 6  
7 7 <%= required f.text_field(:name) %>
8 8  
9   - <p><%= _('Permissions:') %><p>
10   - <% permissions.keys.each do |p| %>
11   - <%= check_box_tag("role[permissions][]", p, role.has_permission?(p), { :id => p }) %>
12   - <%= content_tag(:label, permission_name(p), { :for => p }) %><br/>
  9 + <% permissions.each do |key| %>
  10 + <div class="permissions <%= key.downcase %>">
  11 + <h4><%= _('%s Permissions:' % key) %></h4>
  12 + <% ActiveRecord::Base::PERMISSIONS[key].keys.each do |p| %>
  13 + <%= check_box_tag("role[permissions][]", p, role.has_permission?(p), { :id => p }) %>
  14 + <%= content_tag(:label, permission_name(p), { :for => p }) %><br/>
  15 + <% end %>
  16 + </div>
13 17 <% end %>
14 18  
15 19 <% button_bar do %>
... ...
app/views/role/edit.html.erb
1 1 <h2> <%= _("Editing #{@role.name}") %> </h2>
2 2  
3   -<%= render :partial => 'form', :locals => { :mode => :edit, :role => @role, :permissions => ActiveRecord::Base::PERMISSIONS[@role.kind] } %>
  3 +<%= render :partial => 'form', :locals => { :mode => :edit, :role => @role, :permissions => role_available_permissions(@role) } %>
... ...
app/views/role/new.html.erb
1 1 <h2> <%= _("Create a new role") %> </h2>
2 2  
3   -<%= render :partial => 'form', :locals => { :mode => :create, :role => @role, :permissions => ActiveRecord::Base::PERMISSIONS[@role.kind] } %>
  3 +<%= render :partial => 'form', :locals => { :mode => :create, :role => @role, :permissions => role_available_permissions(@role) } %>
... ...
app/views/search/_display_results.html.erb
... ... @@ -14,7 +14,7 @@
14 14  
15 15 <% display = display_filter(name, params[:display]) %>
16 16  
17   - <div class="search-results-innerbox search-results-type-<%= name.to_s.singularize %> <%= 'common-profile-list-block' if [:enterprises, :people, :communities].include?(name) %>">
  17 + <div class="search-results-innerbox search-results-type-<%= name.to_s.singularize %> <%= 'common-profile-list-block' if SearchHelper::COMMON_PROFILE_LIST_BLOCK.include?(name) %>">
18 18 <ul>
19 19 <% search[:results].each do |hit| %>
20 20 <% partial = partial_for_class(hit.class, display) %>
... ...
app/views/shared/reported_versions/_article.html.erb
... ... @@ -1,10 +0,0 @@
1   -<ul>
2   - <li><%= (content_tag('strong', _('Title') + ': ') + article.title) if article.title %> </li>
3   - <li><%= (content_tag('strong', _('Type') + ': ') + article.class.short_description) %> </li>
4   - <li>
5   - <%= (content_tag('strong', _('Original content') + ': ') + link_to(article.name, article.url)) %> <br />
6   - <%= content_tag('small', _('This link might be unavailable if the content is removed')) %>
7   - </li>
8   -</ul>
9   -
10   -<%= article_to_html(article) %>
app/views/shared/reported_versions/_comment.html.erb
... ... @@ -1,10 +0,0 @@
1   -<ul>
2   - <li><%= (content_tag('strong', _('Title') + ': ') + comment.title) if comment.title %> </li>
3   - <li><%= content_tag('strong', _('Type') + ': ') + _('Comment') %> </li>
4   - <li>
5   - <%= (content_tag('strong', _('Original content') + ': ') + link_to(comment.title || url_for(comment.url), comment.url)) %> <br />
6   - <%= content_tag('small', _('This link might be unavailable if the content is removed')) %>
7   - </li>
8   -</ul>
9   -
10   -<p><%= article_to_html(comment) %></p>
app/views/shared/reported_versions/_folder.html.erb
... ... @@ -1 +0,0 @@
1   -<%= _('Reported folder') + ': ' + link_to(article.name, article.url) %>
app/views/shared/reported_versions/profile/_article.html.erb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<ul>
  2 + <li><%= (content_tag('strong', _('Title') + ': ') + article.title) if article.title %> </li>
  3 + <li><%= (content_tag('strong', _('Type') + ': ') + article.class.short_description) %> </li>
  4 + <li>
  5 + <%= (content_tag('strong', _('Original content') + ': ') + link_to(article.name, article.url)) %> <br />
  6 + <%= content_tag('small', _('This link might be unavailable if the content is removed')) %>
  7 + </li>
  8 +</ul>
  9 +
  10 +<%= article_to_html(article) %>
... ...
app/views/shared/reported_versions/profile/_comment.html.erb 0 → 100644
... ... @@ -0,0 +1,10 @@
  1 +<ul>
  2 + <li><%= (content_tag('strong', _('Title') + ': ') + comment.title) if comment.title %> </li>
  3 + <li><%= content_tag('strong', _('Type') + ': ') + _('Comment') %> </li>
  4 + <li>
  5 + <%= (content_tag('strong', _('Original content') + ': ') + link_to(comment.title || url_for(comment.url), comment.url)) %> <br />
  6 + <%= content_tag('small', _('This link might be unavailable if the content is removed')) %>
  7 + </li>
  8 +</ul>
  9 +
  10 +<p><%= article_to_html(comment) %></p>
... ...
app/views/shared/reported_versions/profile/_folder.html.erb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= _('Reported folder') + ': ' + link_to(article.name, article.url) %>
... ...