Commit 1ac6167675cfca3ac4a14c16f9364506d3a3bfca

Authored by Victor Costa
2 parents 3b3be02b 7e1172c4

Merge branch 'master' into AI3074-community_dashboard

Showing 1288 changed files with 98103 additions and 144085 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 1288 files displayed.

.ackrc 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +--ignore-dir=log
  2 +--ignore-dir=tmp
  3 +--ignore-dir=pkg
  4 +--ignore-dir=public/javascripts/cache
  5 +--ignore-dir=public/stylesheets/cache
@@ -1,240 +0,0 @@ @@ -1,240 +0,0 @@
1 -If you are not listed here, but should be, please write to the noosfero mailing  
2 -list: http://listas.softwarelivre.org/cgi-bin/mailman/listinfo/noosfero-dev  
3 -(this list requires subscription to post, but since you are an author of  
4 -noosfero, that's not a problem).  
5 -  
6 -Developers  
7 -==========  
8 -  
9 -Alan Freihof Tygel <alantygel@gmail.com>  
10 -alcampelo <alcampelo@alcampelo.(none)>  
11 -Alessandro Palmeira <alessandro.palmeira@gmail.com>  
12 -Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>  
13 -Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>  
14 -Alessandro Palmeira + Caio Salgado <caio.csalgado@gmail.com>  
15 -Alessandro Palmeira + Caio Salgado + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>  
16 -Alessandro Palmeira + Carlos Morais <alessandro.palmeira@gmail.com>  
17 -Alessandro Palmeira + Daniel Alves <alessandro.palmeira@gmail.com>  
18 -Alessandro Palmeira + Daniel Alves + Diego Araújo <diegoamc90@gmail.com>  
19 -Alessandro Palmeira + Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>  
20 -Alessandro Palmeira + Diego Araujo <alessandro.palmeira@gmail.com>  
21 -Alessandro Palmeira + Diego Araújo <alessandro.palmeira@gmail.com>  
22 -Alessandro Palmeira + Diego Araujo + Daniela Feitosa <alessandro.palmeira@gmail.com>  
23 -Alessandro Palmeira + Diego Araujo <diegoamc90@gmail.com>  
24 -Alessandro Palmeira + Diego Araújo <diegoamc90@gmail.com>  
25 -Alessandro Palmeira + Diego Araujo + Eduardo Morais <alessandro.palmeira@gmail.com>  
26 -Alessandro Palmeira + Diego Araújo + João M. M. da Silva <alessandro.palmeira@gmail.com>  
27 -Alessandro Palmeira + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>  
28 -Alessandro Palmeira + Diego Araujo + João M. M. da Silva + Paulo Meirelles <alessandro.palmeira@gmail.com>  
29 -Alessandro Palmeira + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>  
30 -Alessandro Palmeira + Diego Araújo + Pedro Leal + João M. M. da Silva <diegoamc90@gmail.com>  
31 -Alessandro Palmeira + Diego Araujo + Rafael Manzo <alessandro.palmeira@gmail.com>  
32 -Alessandro Palmeira + Eduardo Morais <alessandro.palmeira@gmail.com>  
33 -Alessandro Palmeira + Guilherme Rojas <alessandro.palmeira@gmail.com>  
34 -Alessandro Palmeira + Jefferson Fernandes <alessandro.palmeira@gmail.com>  
35 -Alessandro Palmeira + João M. M. da Silva <alessandro.palmeira@gmail.com>  
36 -Alessandro Palmeira + Joao M. M. da Silva + Diego Araujo <alessandro.palmeira@gmail.com>  
37 -Alessandro Palmeira + João M. M. da Silva + Renan Teruo <alessandro.palmeira@gmail.com>  
38 -Alessandro Palmeira + João M. M. Silva <alessandro.palmeira@gmail.com>  
39 -Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>  
40 -Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>  
41 -Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>  
42 -Ana Losnak <analosnak@gmail.com>  
43 -Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>  
44 -Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>  
45 -Antonio Terceiro <terceiro@colivre.coop.br>  
46 -Arthur Del Esposte <arthurmde@yahoo.com.br>  
47 -Aurelio A. Heckert <aurelio@colivre.coop.br>  
48 -Braulio Bhavamitra <brauliobo@gmail.com>  
49 -Bráulio Bhavamitra <brauliobo@gmail.com>  
50 -Braulio Bhavamitra <braulio@eita.org.br>  
51 -Caio <caio.csalgado@gmail.com>  
52 -Caio + Diego + Pedro + João <caio.csalgado@gmail.com>  
53 -Caio Formiga <caio.formiga@gmail.com>  
54 -Caio, Pedro <caio.csalgado@gmail.com>  
55 -Caio Salgado + Alessandro Palmeira <caio.csalgado@gmail.com>  
56 -Caio Salgado <caio.csalgado@gmail.com>  
57 -Caio Salgado + Carlos Morais + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>  
58 -Caio Salgado + Diego Araujo <caio.csalgado@gmail.com>  
59 -Caio Salgado + Diego Araújo <caio.csalgado@gmail.com>  
60 -Caio Salgado + Diego Araújo <diegoamc90@gmail.com>  
61 -Caio Salgado + Diego Araújo + Jefferson Fernandes <caio.csalgado@gmail.com>  
62 -Caio Salgado + Diego Araújo + João M. M. da Silva <caio.csalgado@gmail.com>  
63 -Caio Salgado + Diego Araújo + Pedro Leal <caio.csalgado@gmail.com>  
64 -Caio Salgado + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>  
65 -Caio Salgado + Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>  
66 -Caio Salgado + Jefferson Fernandes <caio.csalgado@gmail.com>  
67 -Caio Salgado + Jefferson Fernandes <jeffs.fernandes@gmail.com>  
68 -Caio Salgado + Rafael Manzo <caio.csalgado@gmail.com>  
69 -Caio Salgado + Renan Teruo <caio.csalgado@gmail.com>  
70 -Caio Salgado + Renan Teruo <caio.salgado@gmail.com>  
71 -Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com>  
72 -Caio Salgado + Renan Teruo <renanteruoc@gmail.com>  
73 -Caio SBA <caio@colivre.coop.br>  
74 -Carlos Andre de Souza <carlos.andre.souza@msn.com>  
75 -Carlos Morais <carlos88morais@gmail.com>  
76 -Carlos Morais + Diego Araújo <diegoamc90@gmail.com>  
77 -Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>  
78 -Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>  
79 -Carlos Morais + Pedro Leal <carlos88morais@gmail.com>  
80 -Daniel Alves + Diego Araújo <danpaulalves@gmail.com>  
81 -Daniel Alves + Diego Araújo <diegoamc90@gmail.com>  
82 -Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>  
83 -Daniel Alves + Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>  
84 -Daniel Alves + Diego Araújo + Guilherme Rojas <guilhermehrojas@gmail.com>  
85 -Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>  
86 -Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>  
87 -Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>  
88 -Daniel Bucher <daniel.bucher88@gmail.com>  
89 -Daniel Cunha <daniel@colivre.coop.br>  
90 -David Carlos <ddavidcarlos1392@gmail.com>  
91 -diegoamc <diegoamc90@gmail.com>  
92 -Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>  
93 -Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>  
94 -Diego Araújo + Alessandro Palmeira + Rafael Manzo <rr.manzo@gmail.com>  
95 -Diego Araujo + Caio Salgado <diegoamc90@gmail.com>  
96 -Diego Araújo + Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>  
97 -Diego Araújo <diegoamc90@gmail.com>  
98 -Diego Araújo + Eduardo Morais + Paulo Meirelles <diegoamc90@gmail.com>  
99 -Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>  
100 -Diego Araújo + Jefferson Fernandes <diegoamc90@gmail.com>  
101 -Diego Araujo + Jefferson Fernandes <jeffs.fernandes@gmail.com>  
102 -Diego Araújo + João Machini <diegoamc90@gmail.com>  
103 -Diego Araújo + João Machini <digoamc90@gmail.com>  
104 -Diego Araújo + João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>  
105 -Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>  
106 -Diego Araújo + João M. M. da Silva + João Machini <diegoamc90@gmail.com>  
107 -Diego Araújo + João M. M. da Silva + Pedro Leal <diegoamc90@gmail.com>  
108 -Diego Araújo + Paulo Meirelles <diegoamc90@gmail.com>  
109 -Diego Araújo + Pedro Leal <diegoamc90@gmail.com>  
110 -Diego Araujo + Rafael Manzo <diegoamc90@gmail.com>  
111 -Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>  
112 -Diego Araújo + Renan Teruo + Alessandro Palmeira <diegoamc90@gmail.com>  
113 -Diego Araújo + Renan Teruo <diegoamc90@gmail.com>  
114 -Diego Araujo + Rodrigo Souto + Rafael Manzo <rr.manzo@gmail.com>  
115 -Diego + Jefferson <diegoamc90@gmail.com>  
116 -Diego Martinez <diegoamc90@gmail.com>  
117 -Diego Martinez <diego@diego-K55A.(none)>  
118 -Diego + Renan <renanteruoc@gmail.com>  
119 -Eduardo Tourinho Edington <eduardo.edington@serpro.gov.br>  
120 -Fabio Teixeira <fabio1079@gmail.com>  
121 -Fernanda Lopes <nanda.listas+psl@gmail.com>  
122 -Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>  
123 -Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)>  
124 -Francisco Marcelo de Araújo Lima Júnior <francisco.lima-junior@serpro.gov.br>  
125 -Francisco Marcelo de Araújo Lima Júnior <maljunior@gmail.com>  
126 -Gabriela Navarro <navarro1703@gmail.com>  
127 -Grazieno Pellegrino <grazieno@gmail.com>  
128 -Gust <darksshades@hotmail.com>  
129 -Hugo Melo <hugo@riseup.net>  
130 -Isaac Canan <isaac@intelletto.com.br>  
131 -Italo Valcy <italo@dcc.ufba.br>  
132 -Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>  
133 -Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>  
134 -Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>  
135 -João da Silva <jaodsilv@linux.ime.usp.br>  
136 -João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>  
137 -João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br>  
138 -João M. M. da Silva + Alessandro Palmeira + Diego Araújo <jaodsilv@linux.ime.usp.br>  
139 -Joao M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>  
140 -João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>  
141 -João M. M. da Silva + Alessandro Palmeira + João Machini <jaodsilv@linux.ime.usp.br>  
142 -João M. M. da Silva + Caio Salgado + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>  
143 -João M. M. da Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>  
144 -João M. M. da Silva + Carlos Morais <jaodsilv@linux.ime.usp.br>  
145 -João M. M. da Silva + Diego Araújo <diegoamc90@gmail.com>  
146 -João M. M. da Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>  
147 -João M. M. da Silva + Diego Araújo + Pedro Leal <jaodsilv@linux.ime.usp.br>  
148 -João M. M. da Silva <jaodsilv@linux.ime.usp.br>  
149 -Joao M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>  
150 -João M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>  
151 -João M. M. da Silva + João M. Miranda <jaodsilv@linux.ime.usp.br>  
152 -João M. M. da Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>  
153 -João M. M. da Silva + Pedro Leal <jaodsilv@linux.ime.usp.br>  
154 -João M. M. da Silva + Rafael Manzo + Diego Araújo <jaodsilv@linux.ime.usp.br>  
155 -João M. M. da Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>  
156 -João M. M. da Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>  
157 -João M. M. Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>  
158 -João M. M. Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>  
159 -Joao M. M. Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>  
160 -João M. M. Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>  
161 -João M. M. Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>  
162 -João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>  
163 -Joenio Costa <joenio@colivre.coop.br>  
164 -Josef Spillner <josef.spillner@tu-dresden.de>  
165 -Junior Silva <junior@bajor.localhost.localdomain>  
166 -Junior Silva <juniorsilva1001@gmail.com>  
167 -Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>  
168 -Junior Silva <juniorsilva@colivre.coop.br>  
169 -Keilla Menezes <keilla@colivre.coop.br>  
170 -Larissa Reis <larissa@colivre.coop.br>  
171 -Larissa Reis <reiss.larissa@gmail.com>  
172 -Leandro Nunes dos Santos <81665687568@serpro-1541727.Home>  
173 -Leandro Nunes dos Santos <81665687568@serpro-1541727.(none)>  
174 -Leandro Nunes dos Santos <leandronunes@gmail.com>  
175 -Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>  
176 -LinguÁgil 2010 <linguagil.bahia@gmail.com>  
177 -Lucas Melo <lucas@colivre.coop.br>  
178 -Lucas Melo <lucaspradomelo@gmail.com>  
179 -Luis David Aguilar Carlos <ludwig9003@gmail.com>  
180 -Marcos Ramos <ms.ramos@outlook.com>  
181 -Martín Olivera <molivera@solar.org.ar>  
182 -Moises Machado <moises@colivre.coop.br>  
183 -Naíla Alves <naila@colivre.coop.br>  
184 -Nanda Lopes <nanda.listas+psl@gmail.com>  
185 -Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>  
186 -Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>  
187 -Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>  
188 -Paulo Meirelles + Diego Araújo <paulo@softwarelivre.org>  
189 -Paulo Meirelles + João M. M. da Silva <paulo@softwarelivre.org>  
190 -Paulo Meirelles <paulo@softwarelivre.org>  
191 -Paulo Meirelles + Rafael Manzo <paulo@softwarelivre.org>  
192 -Rafael Gomes <rafaelgomes@techfree.com.br>  
193 -Rafael Manzo + Alessandro Palmeira <rr.manzo@gmail.com>  
194 -Rafael Manzo + Daniel Alves <danpaulalves@gmail.com>  
195 -Rafael Manzo + Diego Araújo <rr.manzo@gmail.com>  
196 -Rafael Manzo + João M. M. Silva <rr.manzo@gmail.com>  
197 -Rafael Manzo + Paulo Meirelles <rr.manzo@gmail.com>  
198 -Rafael Martins <rmmartins@gmail.com>  
199 -Rafael Reggiani Manzo + Caio Salgado + Jefferson Fernandes <rr.manzo@gmail.com>  
200 -Rafael Reggiani Manzo + Diego Araujo <diegoamc90@gmail.com>  
201 -Rafael Reggiani Manzo + Diego Araujo <rr.manzo@gmail.com>  
202 -Rafael Reggiani Manzo + Diego Araújo <rr.manzo@gmail.com>  
203 -Rafael Reggiani Manzo + João M. M. da Silva <rr.manzo@gmail.com>  
204 -Rafael Reggiani Manzo <rr.manzo@gmail.com>  
205 -Raphaël Rousseau <raph@r4f.org>  
206 -Raquel Lira <raquel.lira@gmail.com>  
207 -Renan Teruo + Caio Salgado <renanteruoc@gmail.com>  
208 -Renan Teruoc + Diego Araujo <renanteruoc@gmail.com>  
209 -Renan Teruo + Diego Araujo <renanteruoc@gmail.com>  
210 -Renan Teruo + Diego Araújo <renanteruoc@gmail.com>  
211 -Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>  
212 -Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>  
213 -Rodrigo Souto + Ana Losnak + Daniel Bucher + Caio Almeida + Leandro Nunes + Daniela Feitosa + Mariel Zasso <noosfero-br@listas.softwarelivre.org>  
214 -Rodrigo Souto <diguliu@gmail.com>  
215 -Rodrigo Souto <rodrigo@colivre.coop.br>  
216 -Ronny Kursawe <kursawe.ronny@googlemail.com>  
217 -root <root@debian.sdr.serpro>  
218 -Samuel R. C. Vale <srcvale@holoscopio.com>  
219 -Valessio Brito <contato@valessiobrito.com.br>  
220 -Valessio Brito <contato@valessiobrito.info>  
221 -Valessio Brito <valessio@gmail.com>  
222 -vfcosta <vfcosta@gmail.com>  
223 -Victor Carvalho <victorhugodf.ac@gmail.com>  
224 -Victor Costa <vfcosta@gmail.com>  
225 -Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com>  
226 -Vinicius Cubas Brand <viniciuscb@gmail.com>  
227 -Visita <visita@debian.(none)>  
228 -Yann Lugrin <yann.lugrin@liquid-concept.ch>  
229 -  
230 -Ideas, specifications and incentive  
231 -===================================  
232 -Daniel Tygel <dtygel@fbes.org.br>  
233 -Guilherme Rocha <guilherme@gf7.com.br>  
234 -Raphael Rousseau <raph@r4f.org>  
235 -Théo Bondolfi <move@cooperation.net>  
236 -Vicente Aguiar <vicenteaguiar@colivre.coop.br>  
237 -  
238 -Arts  
239 -===================================  
240 -Nara Oliveira <narananet@gmail.com>  
1 -If you are not listed here, but should be, please write to the noosfero mailing list: http://listas.softwarelivre.org/cgi-bin/mailman/listinfo/noosfero-dev (this list requires subscription to post, but since you are an author of noosfero, that's not a problem). 1 +If you are not listed here, but should be, please write to the noosfero mailing
  2 +list: http://listas.softwarelivre.org/cgi-bin/mailman/listinfo/noosfero-dev
  3 +(this list requires subscription to post, but since you are an author of
  4 +noosfero, that's not a problem).
2 5
3 Developers 6 Developers
4 ========== 7 ==========
5 8
  9 +Ábner Silva de Oliveira <abner.oliveira@serpro.gov.br>
6 Alan Freihof Tygel <alantygel@gmail.com> 10 Alan Freihof Tygel <alantygel@gmail.com>
  11 +alcampelo <alcampelo@alcampelo.(none)>
7 Alessandro Palmeira <alessandro.palmeira@gmail.com> 12 Alessandro Palmeira <alessandro.palmeira@gmail.com>
8 Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com> 13 Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>
9 Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com> 14 Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>
@@ -35,9 +40,13 @@ Alessandro Palmeira + João M. M. Silva &lt;alessandro.palmeira@gmail.com&gt; @@ -35,9 +40,13 @@ Alessandro Palmeira + João M. M. Silva &lt;alessandro.palmeira@gmail.com&gt;
35 Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com> 40 Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
36 Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com> 41 Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
37 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com> 42 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
  43 +Ana Losnak <analosnak@gmail.com>
  44 +Andre Bernardes <andrebsguedes@gmail.com>
38 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br> 45 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
39 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br> 46 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
40 Antonio Terceiro <terceiro@colivre.coop.br> 47 Antonio Terceiro <terceiro@colivre.coop.br>
  48 +Arthur Del Esposte <arthurmde@gmail.com>
  49 +Arthur Del Esposte <arthurmde@yahoo.com.br>
41 Aurelio A. Heckert <aurelio@colivre.coop.br> 50 Aurelio A. Heckert <aurelio@colivre.coop.br>
42 Braulio Bhavamitra <brauliobo@gmail.com> 51 Braulio Bhavamitra <brauliobo@gmail.com>
43 Bráulio Bhavamitra <brauliobo@gmail.com> 52 Bráulio Bhavamitra <brauliobo@gmail.com>
@@ -65,11 +74,14 @@ Caio Salgado + Renan Teruo &lt;caio.salgado@gmail.com&gt; @@ -65,11 +74,14 @@ Caio Salgado + Renan Teruo &lt;caio.salgado@gmail.com&gt;
65 Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com> 74 Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
66 Caio Salgado + Renan Teruo <renanteruoc@gmail.com> 75 Caio Salgado + Renan Teruo <renanteruoc@gmail.com>
67 Caio SBA <caio@colivre.coop.br> 76 Caio SBA <caio@colivre.coop.br>
  77 +Caio Tiago Oliveira <caiotiago@colivre.coop.br>
  78 +Carlos Andre de Souza <carlos.andre.souza@msn.com>
68 Carlos Morais <carlos88morais@gmail.com> 79 Carlos Morais <carlos88morais@gmail.com>
69 Carlos Morais + Diego Araújo <diegoamc90@gmail.com> 80 Carlos Morais + Diego Araújo <diegoamc90@gmail.com>
70 Carlos Morais + Eduardo Morais <carlos88morais@gmail.com> 81 Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
71 Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com> 82 Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
72 Carlos Morais + Pedro Leal <carlos88morais@gmail.com> 83 Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
  84 +Daniela Feitosa <dani@dohko.(none)>
73 Daniel Alves + Diego Araújo <danpaulalves@gmail.com> 85 Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
74 Daniel Alves + Diego Araújo <diegoamc90@gmail.com> 86 Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
75 Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com> 87 Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
@@ -78,7 +90,9 @@ Daniel Alves + Diego Araújo + Guilherme Rojas &lt;guilhermehrojas@gmail.com&gt; @@ -78,7 +90,9 @@ Daniel Alves + Diego Araújo + Guilherme Rojas &lt;guilhermehrojas@gmail.com&gt;
78 Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com> 90 Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>
79 Daniel Alves + Rafael Manzo <rr.manzo@gmail.com> 91 Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
80 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> 92 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
  93 +Daniel Bucher <daniel.bucher88@gmail.com>
81 Daniel Cunha <daniel@colivre.coop.br> 94 Daniel Cunha <daniel@colivre.coop.br>
  95 +David Carlos <ddavidcarlos1392@gmail.com>
82 diegoamc <diegoamc90@gmail.com> 96 diegoamc <diegoamc90@gmail.com>
83 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com> 97 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
84 Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com> 98 Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>
@@ -107,15 +121,26 @@ Diego + Jefferson &lt;diegoamc90@gmail.com&gt; @@ -107,15 +121,26 @@ Diego + Jefferson &lt;diegoamc90@gmail.com&gt;
107 Diego Martinez <diegoamc90@gmail.com> 121 Diego Martinez <diegoamc90@gmail.com>
108 Diego Martinez <diego@diego-K55A.(none)> 122 Diego Martinez <diego@diego-K55A.(none)>
109 Diego + Renan <renanteruoc@gmail.com> 123 Diego + Renan <renanteruoc@gmail.com>
  124 +Eduardo Tourinho Edington <eduardo.edington@serpro.gov.br>
  125 +Evandro Jr <evandrojr@gmail.com>
  126 +Evandro Junior <evandrojr@gmail.com>
  127 +Fabio Teixeira <fabio1079@gmail.com>
110 Fernanda Lopes <nanda.listas+psl@gmail.com> 128 Fernanda Lopes <nanda.listas+psl@gmail.com>
111 Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br> 129 Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>
112 Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)> 130 Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)>
  131 +Francisco Marcelo de Araújo Lima Júnior <francisco.lima-junior@serpro.gov.br>
  132 +Francisco Marcelo de Araújo Lima Júnior <maljunior@gmail.com>
  133 +Gabriela Navarro <navarro1703@gmail.com>
113 Grazieno Pellegrino <grazieno@gmail.com> 134 Grazieno Pellegrino <grazieno@gmail.com>
  135 +Gust <darksshades@hotmail.com>
  136 +Hebert Douglas <hebertdougl@gmail.com>
  137 +Hugo Melo <hugo@riseup.net>
114 Isaac Canan <isaac@intelletto.com.br> 138 Isaac Canan <isaac@intelletto.com.br>
115 Italo Valcy <italo@dcc.ufba.br> 139 Italo Valcy <italo@dcc.ufba.br>
116 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com> 140 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
117 Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com> 141 Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
118 Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com> 142 Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>
  143 +João da Silva + Eduardo Morais + Rafael Manzo <rr.manzo@gmail.com>
119 João da Silva <jaodsilv@linux.ime.usp.br> 144 João da Silva <jaodsilv@linux.ime.usp.br>
120 João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br> 145 João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
121 João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br> 146 João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br>
@@ -146,17 +171,29 @@ João M. M. Silva + Rafael Manzo &lt;jaodsilv@linux.ime.usp.br&gt; @@ -146,17 +171,29 @@ João M. M. Silva + Rafael Manzo &lt;jaodsilv@linux.ime.usp.br&gt;
146 João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br> 171 João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
147 Joenio Costa <joenio@colivre.coop.br> 172 Joenio Costa <joenio@colivre.coop.br>
148 Josef Spillner <josef.spillner@tu-dresden.de> 173 Josef Spillner <josef.spillner@tu-dresden.de>
  174 +Jose Pedro <1jpsneto@gmail.com>
  175 +Junior Silva <junior@bajor.localhost.localdomain>
  176 +Junior Silva <junior@sedeantigo.colivre.coop.br>
149 Junior Silva <juniorsilva1001@gmail.com> 177 Junior Silva <juniorsilva1001@gmail.com>
150 Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)> 178 Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>
  179 +Junior Silva <juniorsilva@colivre.coop.br>
  180 +juniorsilva <juniorsilva@QonoS.localhost.localdomain>
151 Keilla Menezes <keilla@colivre.coop.br> 181 Keilla Menezes <keilla@colivre.coop.br>
152 Larissa Reis <larissa@colivre.coop.br> 182 Larissa Reis <larissa@colivre.coop.br>
153 Larissa Reis <reiss.larissa@gmail.com> 183 Larissa Reis <reiss.larissa@gmail.com>
  184 +Leandro Alves <leandrosustenido@gmail.com>
  185 +Leandro Nunes dos Santos <81665687568@serpro-1541727.Home>
  186 +Leandro Nunes dos Santos <81665687568@serpro-1541727.(none)>
154 Leandro Nunes dos Santos <leandronunes@gmail.com> 187 Leandro Nunes dos Santos <leandronunes@gmail.com>
155 Leandro Nunes dos Santos <leandro.santos@serpro.gov.br> 188 Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>
156 LinguÁgil 2010 <linguagil.bahia@gmail.com> 189 LinguÁgil 2010 <linguagil.bahia@gmail.com>
157 Lucas Melo <lucas@colivre.coop.br> 190 Lucas Melo <lucas@colivre.coop.br>
158 Lucas Melo <lucaspradomelo@gmail.com> 191 Lucas Melo <lucaspradomelo@gmail.com>
  192 +Luciano <lucianopcbr@gmail.com>
  193 +Luciano Prestes Cavalcanti <lucianopcbr@gmail.com>
159 Luis David Aguilar Carlos <ludwig9003@gmail.com> 194 Luis David Aguilar Carlos <ludwig9003@gmail.com>
  195 +Luiz Fernando de Freitas Matos <luiz@luizff.matos@gmail.com>
  196 +Marcos Ramos <ms.ramos@outlook.com>
160 Martín Olivera <molivera@solar.org.ar> 197 Martín Olivera <molivera@solar.org.ar>
161 Moises Machado <moises@colivre.coop.br> 198 Moises Machado <moises@colivre.coop.br>
162 Naíla Alves <naila@colivre.coop.br> 199 Naíla Alves <naila@colivre.coop.br>
@@ -189,14 +226,21 @@ Renan Teruo + Diego Araujo &lt;renanteruoc@gmail.com&gt; @@ -189,14 +226,21 @@ Renan Teruo + Diego Araujo &lt;renanteruoc@gmail.com&gt;
189 Renan Teruo + Diego Araújo <renanteruoc@gmail.com> 226 Renan Teruo + Diego Araújo <renanteruoc@gmail.com>
190 Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com> 227 Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
191 Renan Teruo + Rafael Manzo <renanteruoc@gmail.com> 228 Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
  229 +Rodrigo Souto + Ana Losnak + Daniel Bucher + Caio Almeida + Leandro Nunes + Daniela Feitosa + Mariel Zasso <noosfero-br@listas.softwarelivre.org>
192 Rodrigo Souto <diguliu@gmail.com> 230 Rodrigo Souto <diguliu@gmail.com>
193 Rodrigo Souto <rodrigo@colivre.coop.br> 231 Rodrigo Souto <rodrigo@colivre.coop.br>
194 Ronny Kursawe <kursawe.ronny@googlemail.com> 232 Ronny Kursawe <kursawe.ronny@googlemail.com>
195 root <root@debian.sdr.serpro> 233 root <root@debian.sdr.serpro>
196 Samuel R. C. Vale <srcvale@holoscopio.com> 234 Samuel R. C. Vale <srcvale@holoscopio.com>
  235 +Tallys Martins <tallysmartins@gmail.com>
  236 +tallys <tallys@tallys.(none)>
  237 +Valessio Brito <contato@valessiobrito.com.br>
  238 +Valessio Brito <contato@valessiobrito.info>
197 Valessio Brito <valessio@gmail.com> 239 Valessio Brito <valessio@gmail.com>
198 vfcosta <vfcosta@gmail.com> 240 vfcosta <vfcosta@gmail.com>
  241 +Victor Carvalho <victorhugodf.ac@gmail.com>
199 Victor Costa <vfcosta@gmail.com> 242 Victor Costa <vfcosta@gmail.com>
  243 +Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com>
200 Vinicius Cubas Brand <viniciuscb@gmail.com> 244 Vinicius Cubas Brand <viniciuscb@gmail.com>
201 Visita <visita@debian.(none)> 245 Visita <visita@debian.(none)>
202 Yann Lugrin <yann.lugrin@liquid-concept.ch> 246 Yann Lugrin <yann.lugrin@liquid-concept.ch>
1 source "https://rubygems.org" 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 gem 'rake', :require => false 17 gem 'rake', :require => false
  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'
18 22
19 # FIXME list here all actual dependencies (i.e. the ones in debian/control), 23 # FIXME list here all actual dependencies (i.e. the ones in debian/control),
20 # with their GEM names (not the Debian package names) 24 # with their GEM names (not the Debian package names)
21 25
22 group :production do 26 group :production do
23 - gem 'dalli' 27 + gem 'dalli', '~> 2.7.0'
24 end 28 end
25 29
26 group :test do 30 group :test do
27 - gem 'rspec'  
28 - gem 'rspec-rails' 31 + gem 'rspec', '~> 2.10.0'
  32 + gem 'rspec-rails', '~> 2.10.1'
  33 + gem 'mocha', '~> 1.1.0', :require => false
29 end 34 end
30 35
31 group :cucumber do 36 group :cucumber do
32 - gem 'rake'  
33 - gem 'cucumber-rails', :require => false  
34 - gem 'capybara'  
35 - gem 'cucumber'  
36 - gem 'database_cleaner'  
37 - 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'
38 end 42 end
39 43
40 # include plugin gemfiles 44 # include plugin gemfiles
Gemfile.lock
@@ -1,180 +0,0 @@ @@ -1,180 +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.11)  
65 - fast_gettext (0.6.8)  
66 - ffi (1.0.11)  
67 - gherkin (2.4.21)  
68 - json (>= 1.4.6)  
69 - hike (1.2.1)  
70 - hpricot (0.8.6)  
71 - i18n (0.6.0)  
72 - journey (1.0.3)  
73 - json (1.7.3)  
74 - mail (2.4.4)  
75 - i18n (>= 0.4.0)  
76 - mime-types (~> 1.16)  
77 - treetop (~> 1.4.8)  
78 - mime-types (1.19)  
79 - multi_json (1.3.6)  
80 - nokogiri (1.5.5)  
81 - pg (0.13.2)  
82 - polyglot (0.3.3)  
83 - prototype-rails (3.2.1)  
84 - rails (~> 3.2)  
85 - rack (1.4.1)  
86 - rack-cache (1.2)  
87 - rack (>= 0.4)  
88 - rack-ssl (1.3.2)  
89 - rack  
90 - rack-test (0.6.1)  
91 - rack (>= 1.0)  
92 - rails (3.2.6)  
93 - actionmailer (= 3.2.6)  
94 - actionpack (= 3.2.6)  
95 - activerecord (= 3.2.6)  
96 - activeresource (= 3.2.6)  
97 - activesupport (= 3.2.6)  
98 - bundler (~> 1.0)  
99 - railties (= 3.2.6)  
100 - rails_autolink (1.1.5)  
101 - rails (> 3.1)  
102 - railties (3.2.6)  
103 - actionpack (= 3.2.6)  
104 - activesupport (= 3.2.6)  
105 - rack-ssl (~> 1.3.2)  
106 - rake (>= 0.8.7)  
107 - rdoc (~> 3.4)  
108 - thor (>= 0.14.6, < 2.0)  
109 - rake (0.9.2.2)  
110 - rdoc (3.9.4)  
111 - rmagick (2.13.1)  
112 - rspec (2.10.0)  
113 - rspec-core (~> 2.10.0)  
114 - rspec-expectations (~> 2.10.0)  
115 - rspec-mocks (~> 2.10.0)  
116 - rspec-core (2.10.1)  
117 - rspec-expectations (2.10.0)  
118 - diff-lcs (~> 1.1.3)  
119 - rspec-mocks (2.10.1)  
120 - rspec-rails (2.10.1)  
121 - actionpack (>= 3.0)  
122 - activesupport (>= 3.0)  
123 - railties (>= 3.0)  
124 - rspec (~> 2.10.0)  
125 - ruby-feedparser (0.7)  
126 - rubyzip (1.1.2)  
127 - selenium-webdriver (2.39.0)  
128 - childprocess (>= 0.2.5)  
129 - multi_json (~> 1.0)  
130 - rubyzip (~> 1.0)  
131 - websocket (~> 1.0.4)  
132 - sprockets (2.1.3)  
133 - hike (~> 1.2)  
134 - multi_json (~> 1.0)  
135 - rack (~> 1.0)  
136 - tilt (~> 1.1, != 1.3.0)  
137 - term-ansicolor (1.0.7)  
138 - thin (1.3.1)  
139 - daemons (>= 1.0.9)  
140 - eventmachine (>= 0.12.6)  
141 - rack (>= 1.0.0)  
142 - thor (0.15.3)  
143 - tilt (1.3.3)  
144 - treetop (1.4.10)  
145 - polyglot  
146 - polyglot (>= 0.3.1)  
147 - tzinfo (0.3.33)  
148 - websocket (1.0.7)  
149 - will_paginate (3.0.3)  
150 - xpath (2.0.0)  
151 - nokogiri (~> 1.3)  
152 -  
153 -PLATFORMS  
154 - ruby  
155 -  
156 -DEPENDENCIES  
157 - RedCloth  
158 - acts-as-taggable-on  
159 - capybara  
160 - cucumber  
161 - cucumber-rails  
162 - daemons  
163 - dalli  
164 - database_cleaner  
165 - fast_gettext  
166 - hpricot  
167 - nokogiri  
168 - pg  
169 - prototype-rails  
170 - prototype_legacy_helper (= 0.0.0)!  
171 - rails  
172 - rails_autolink  
173 - rake  
174 - rmagick  
175 - rspec  
176 - rspec-rails  
177 - ruby-feedparser  
178 - selenium-webdriver  
179 - thin  
180 - will_paginate  
INSTALL.chat.md
1 -XMPP/Chat Client Setup  
2 -====================== 1 +XMPP/Chat Setup
  2 +===============
3 3
4 -To configure XMPP/BOSH in Noosfero you need: 4 +The samples of config file to configure a XMPP/BOSH server with ejabberd,
  5 +postgresql and apache2 can be found at util/chat directory.
5 6
6 -* REST Client - http://github.com/archiloque/rest-client  
7 -* SystemTimer - http://ph7spot.com/musings/system-timer  
8 -* Pidgin data files - http://www.pidgin.im/ 7 +This setup supposes that you are using Noosfero installed via Debian package
  8 +in a production environment.
9 9
10 -If you use Debian 6.0 (squeeze):  
11 -  
12 - # apt-get install librestclient-ruby pidgin-data ruby1.8-dev  
13 - # gem install SystemTimer  
14 -  
15 -The samples of config file to configure a XMPP/BOSH server with ejabberd, postgresql and apache2 can be found at util/chat directory.  
16 -  
17 -XMPP/Chat Server Setup  
18 -====================== 10 +Steps
  11 +=====
19 12
20 This is a step-by-step guide to get a XMPP service working, in a Debian system. 13 This is a step-by-step guide to get a XMPP service working, in a Debian system.
21 14
22 ## 1. Install the required packages 15 ## 1. Install the required packages
23 16
24 - # apt-get install ejabberd odbc-postgresql 17 + # apt-get install ejabberd odbc-postgresql librestclient-ruby pidgin-data ruby1.8-dev
  18 + # gem install SystemTimer
25 19
26 ## 2. Ejabberd configuration 20 ## 2. Ejabberd configuration
27 21
28 -All the following changes must be done in config file: `/etc/ejabberd/ejabberd.cfg`  
29 -  
30 -### 2.1. Set the default admin user  
31 -  
32 - { acl, admin, { user, "john", "www.example.com" } }.  
33 - { acl, admin, { user, "bart", "www.example.com" } }.  
34 -  
35 -### 2.2. Set the default host  
36 -  
37 - { hosts, [ "www.example.com" ] }.  
38 -  
39 -### 2.3. Http-Bind activation  
40 -  
41 - { 5280, ejabberd_http, [  
42 - http_bind,  
43 - web_admin  
44 - ]  
45 - }  
46 -  
47 - (...)  
48 -  
49 - { modules, [  
50 - {mod_http_bind, []},  
51 - ...  
52 - ] }.  
53 -  
54 -Ejabberd creates semi-anonymous rooms by default, but Noosfero's Jabber client needs non-anonymous room, then we need to change default params of creation rooms in ejabberd to create non-anonymous rooms.  
55 -  
56 -In non-anonymous rooms the jabber service sends the new occupant's full JID to all occupants in the room [[1]]. 22 + # cp /usr/share/noosfero/util/chat/ejabberd.cfg /etc/ejabberd/
57 23
58 -Add option "`{default_room_options, [{anonymous, false}]}`" to `/etc/ejabberd/ejabberd.cfg` in mod_muc session. See below: 24 +Edit the /etc/ejabberd/ejabberd.cfg file and set your domain on the first 2 lines.
59 25
60 - { mod_muc, [  
61 - %%{host, "conference.@HOST@"},  
62 - {access, muc},  
63 - {access_create, muc},  
64 - {access_persistent, muc},  
65 - {access_admin, muc_admin},  
66 - {max_users, 500},  
67 - {default_room_options, [{anonymous, false}]}  
68 - ]},  
69 -  
70 -[1]: http://xmpp.org/extensions/xep-0045.html#enter-nonanon  
71 -  
72 -  
73 -### 2.4. Authentication method  
74 -  
75 -To use Postgresql through ODBC, the following modifications must be done:  
76 -  
77 - * Disable the default method:  
78 - `{auth_method, internal}.`  
79 -  
80 - * Enable autheticantion through ODBC:  
81 - `{auth_method, odbc}.` 26 +## 3. Configuring Postgresql
82 27
83 - * Set database server name  
84 - `{odbc_server, "DSN=PostgreSQLEjabberdNoosfero"}.` 28 +Give permission to noosfero user create new roles, login as
  29 +postgres user and execute:
85 30
  31 + $ psql
  32 + postgres=# GRANT CREATE ON DATABASE noosfero TO noosfero;
86 33
87 -### 2.5. Increase the shaper traffic limit 34 +Change the postgresql authentication method to md5 instead of ident,
  35 +add the following line to the file /etc/postgresql/8.4/main/pg_hba.conf:
88 36
89 - { shaper, normal, { maxrate, 10000000 } }. 37 + # Noosfero user
  38 + local noosfero noosfero md5
90 39
  40 +(add this line before the following line)
91 41
92 -### 2.6. Disable unused modules 42 + # "local" is for Unix domain socket connections only
  43 + local all all ident
93 44
94 -Unused modules can be disabled, for example: 45 +Restart postgresql server:
95 46
96 - * s2s  
97 - * web_admin  
98 - * mod_pubsub  
99 - * mod_irc  
100 - * mod_offline  
101 - * mod_admin_extra  
102 - * mod_register 47 + # service postgresql restart
103 48
  49 +Login as noosfero user, and execute:
104 50
105 -### 2.7. Enable ODBC modules 51 + $ psql -U noosfero -W noosfero < /usr/share/noosfero/util/chat/postgresql/ejabberd.sql
106 52
107 - * mod_privacy -> mod_privacy_odbc  
108 - * mod_private -> mod_private_odbc  
109 - * mod_roster -> mod_roster_odbc 53 +(see database password in the /etc/noosfero/database.yml file)
110 54
111 -## 3. Configuring Postgresql 55 +This will create a new schema inside the noosfero database, called `ejabberd`.
112 56
113 -Login as noosfero user, and execute: 57 +Note that there should be at least one domain with `is_default = true` in
  58 +`domains` table, otherwise people won't be able to see their friends online.
114 59
115 - $ psql noosfero < /path/to/noosfero/util/chat/postgresql/ejabberd.sql 60 +## 4. ODBC configuration
116 61
117 -Where `noosfero` may need to be replace by the name of the database used for Noosfero. 62 +Create the following files:
118 63
119 -This will create a new schema inside the noosfero database, called `ejabberd`. 64 + # cp /usr/share/noosfero/util/chat/odbc.ini /etc/
  65 + # cp /usr/share/noosfero/util/chat/odbcinst.ini /etc/
120 66
121 -Note `noosfero` user should have permission to create Postgresql schemas. Also, there should be at least one domain with `is_default = true` in `domains` table, otherwise people won't be able to see their friends online. 67 +Edit the odbc.ini file and set the password for the database user, see
  68 +the file /etc/noosfero/database.yml to get the password.
122 69
123 -## 4. ODBC configuration 70 +Adjust premissions:
124 71
125 -The following files must be created:  
126 -  
127 -`/etc/odbc.ini`:  
128 -  
129 - [PostgreSQLEjabberdNoosfero]  
130 - Description = PostgreSQL Noosfero ejabberd database  
131 - Driver = PostgreSQL Unicode  
132 - Trace = No  
133 - TraceFile = /tmp/psqlodbc.log  
134 - Database = noosfero  
135 - Servername = localhost  
136 - UserName = <DBUSER>  
137 - Password = <DBPASS>  
138 - Port =  
139 - ReadOnly = No  
140 - RowVersioning = No  
141 - ShowSystemTables = No  
142 - ShowOidColumn = No  
143 - FakeOidIndex = No  
144 - ConnSettings = SET search_path TO ejabberd  
145 -  
146 -`/etc/odbcinst.ini`:  
147 -  
148 - [PostgreSQL Unicode]  
149 - Description = PostgreSQL ODBC driver (Unicode version)  
150 - Driver = /usr/lib/odbc/psqlodbcw.so  
151 - Setup = /usr/lib/odbc/libodbcpsqlS.so  
152 - Debug = 0  
153 - CommLog = 1  
154 - UsageCount = 3 72 + # chmod 640 /etc/odbc.ini
  73 + # chown ejabberd /etc/odbc.ini
155 74
156 ## 4.1 testing all: 75 ## 4.1 testing all:
157 76
@@ -159,7 +78,6 @@ The following files must be created: @@ -159,7 +78,6 @@ The following files must be created:
159 78
160 If the configuration was done right, the message "Connected!" will be displayed. 79 If the configuration was done right, the message "Connected!" will be displayed.
161 80
162 -  
163 ## 5. Enabling kernel polling and SMP in `/etc/default/ejabberd` 81 ## 5. Enabling kernel polling and SMP in `/etc/default/ejabberd`
164 82
165 POLL=true 83 POLL=true
@@ -205,32 +123,45 @@ Note: module proxy_http must be enabled: @@ -205,32 +123,45 @@ Note: module proxy_http must be enabled:
205 123
206 # a2enmod proxy_http 124 # a2enmod proxy_http
207 125
208 -## 8. DNS configuration 126 +Restart services:
209 127
210 -For this point, we assume you are using BIND as your DNS server. You need to add the following entries to the DNS zone file corresponding to the domain of your noosfero site: 128 + # service ejabberd restart
  129 + # service noosfero restart
  130 + # service apache2 restart
211 131
212 - _xmpp-client._tcp SRV 5 100 5222 master  
213 - conference CNAME master  
214 - _xmpp-client._tcp.conference SRV 5 100 5222 master 132 +## 8. Test Apache Configuration
215 133
216 -If you are running a DNS server other than BIND, you will have to figure out how to create equivalente rules for your zone file. Patches to this documentation are welcome. 134 +Open in your browser the address:
217 135
218 -## 9. Testing this Setup 136 + http://<yout domain>/http-bind
219 137
220 -Adjust shell limits to proceed with some benchmarks and load tests: 138 +You should see a page with a message like that:
221 139
222 - # ulimit −s 256  
223 - # ulimit −n 8192  
224 - # echo 10 > /proc/sys/net/ipv4/tcp_syn_retries 140 + ejabberd mod_http_bind
  141 + An implementation of XMPP over BOSH (XEP-0206)
  142 + This web page is only informative. To use HTTP-Bind you need a Jabber/XMPP
  143 + client that supports it.
225 144
226 -To measure the bandwidth between server and client: 145 +## 9. Test chat session
227 146
228 - * at server side:  
229 - `# iperf −s` 147 +Open Noosfero console and execute:
230 148
231 - * at client side:  
232 - `# iperf −c server_ip` 149 +>> environment = Environment.default
  150 +>> user = Person['guest']
  151 +>> password = user.user.crypted_password
  152 +>> login = user.jid
  153 +>> RubyBOSH.initialize_session(login, password, "http://#{environment.default_hostname}/http-bind", :wait => 30, :hold => 1, :window => 5
233 154
234 -For heavy load tests, clone and use this software: 155 +If you have luck, should see something like that:
235 156
236 - $ git clone http://git.holoscopio.com/git/metal/tester.git 157 +Ruby-BOSH - SEND
  158 +<body window="5" rid="60265" xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" to="vagrant-debian-squeeze.vagrantup.com" wait="30" xmpp:version="1.0" hold="1"/>
  159 +Ruby-BOSH - SEND
  160 +<body rid="60266" xmlns="http://jabber.org/protocol/httpbind" sid="24cdfc43646a2af1059a7060b677c2e11b26f34f" xmlns:xmpp="urn:xmpp:xbosh" xmpp:version="1.0"><auth mechanism="PLAIN" xmlns="urn:ietf:params:xml:ns:xmpp-sasl">Z3Vlc3RAdmFncmFudC1kZWJpYW4tc3F1ZWV6ZS52YWdyYW50dXAuY29tAGd1ZXN0ADEzZTFhYWVlYjRhYjZlMTA0MmRkNWI1YWY0MzM4MjA1OGJiOWZmNzk=</auth></body>
  161 +Ruby-BOSH - SEND
  162 +<body xmpp:restart="true" rid="60267" xmlns="http://jabber.org/protocol/httpbind" sid="24cdfc43646a2af1059a7060b677c2e11b26f34f" xmlns:xmpp="urn:xmpp:xbosh" xmpp:version="1.0"/>
  163 +Ruby-BOSH - SEND
  164 +<body rid="60268" xmlns="http://jabber.org/protocol/httpbind" sid="24cdfc43646a2af1059a7060b677c2e11b26f34f" xmlns:xmpp="urn:xmpp:xbosh" xmpp:version="1.0"><iq type="set" xmlns="jabber:client" id="bind_29330"><bind xmlns="urn:ietf:params:xml:ns:xmpp-bind"><resource>bosh_9631</resource></bind></iq></body>
  165 +Ruby-BOSH - SEND
  166 +<body rid="60269" xmlns="http://jabber.org/protocol/httpbind" sid="24cdfc43646a2af1059a7060b677c2e11b26f34f" xmlns:xmpp="urn:xmpp:xbosh" xmpp:version="1.0"><iq type="set" xmlns="jabber:client" id="sess_21557"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq></body>
  167 +=> ["guest@vagrant-debian-squeeze.vagrantup.com", "24cdfc43646a2af1059a7060b677c2e11b26f34f", 60270]
INSTALL.https.md 0 → 100644
@@ -0,0 +1,115 @@ @@ -0,0 +1,115 @@
  1 +Setup Noosfero to use HTTPS
  2 +===========================
  3 +
  4 +This document assumes that you have a fully and clean Noosfero
  5 +installation as explained at the `INSTALL.md` file.
  6 +
  7 +SSL certificate
  8 ++++++++++++++++
  9 +
  10 +You should get a valid SSL certificate, but if you want to test
  11 +your setup before, you could generate a self-signed certificate
  12 +as below:
  13 +
  14 + # mkdir /etc/noosfero/ssl
  15 + # cd /etc/noosfero/ssl
  16 + # openssl genrsa 1024 > noosfero.key
  17 + # openssl req -new -x509 -nodes -sha1 -days $[10*365] -key noosfero.key > noosfero.cert
  18 + # cat noosfero.key noosfero.cert > noosfero.pem
  19 +
  20 +There are two ways of using SSL with Noosfero: 1) If you are not using
  21 +Varnish; and 2) If you are using Varnish.
  22 +
  23 +1) If you are are not using Varnish
  24 ++++++++++++++++++++++++++++++++++++
  25 +
  26 +Simply do a redirect in apache to force all connections with SSL:
  27 +
  28 + <VirtualHost *:8080>
  29 + ServerName test.stoa.usp.br
  30 +
  31 + Redirect / https://example.com/
  32 + </VirtualHost>
  33 +
  34 +And set a vhost to receive then:
  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>
  45 +
  46 +Be aware that if you had configured varnish, the requests won't reach
  47 +it with this configuration.
  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:
  55 +
  56 + $ sudo apt-get install pound
  57 +
  58 +Set Varnish to listen in other port than 80:
  59 +
  60 +/etc/defaults/varnish
  61 +---------------------
  62 +
  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"
  68 +
  69 +Configure Pound:
  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.
  74 +
  75 +Configure Pound to start at system initialization:
  76 +
  77 +/etc/default/pound
  78 +------------------
  79 +
  80 + startup=1
  81 +
  82 +Set Apache to only listen to localhost:
  83 +
  84 +/etc/apache2/ports.conf
  85 +-----------------------
  86 +
  87 + Listen 127.0.0.1:8080
  88 +
  89 +Restart the services:
  90 +
  91 + $ sudo service apache2 restart
  92 + $ sudo service varnish restart
  93 +
  94 +Start pound:
  95 +
  96 + $ sudo service pound start
  97 +
  98 +[1] http://www.apsis.ch/pound
  99 +
  100 +Noosfero XMPP chat
  101 +++++++++++++++++++
  102 +
  103 +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:
  105 +
  106 +/etc/hosts
  107 +----------
  108 +
  109 + 192.168.1.86 mydomain.example.com
  110 +
  111 +Also, it's recomended that you remove lines above from the file
  112 +`/etc/apache2/sites-enabled/noosfero`:
  113 +
  114 + RewriteEngine On
  115 + Include /usr/share/noosfero/util/chat/apache/xmpp.conf
@@ -186,8 +186,8 @@ Apache instalation @@ -186,8 +186,8 @@ Apache instalation
186 186
187 # apt-get install apache2 187 # apt-get install apache2
188 188
189 -Apache configuration  
190 --------------------- 189 +Configuration - noosfero at /
  190 +-----------------------------
191 191
192 First you have to enable the following some apache modules: 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,6 +257,62 @@ Now restart your apache server (as root):
257 257
258 # invoke-rc.d apache2 restart 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 Enabling exception notifications 317 Enabling exception notifications
262 ================================ 318 ================================
INSTALL.varnish.md
@@ -24,10 +24,6 @@ Install the RPAF apache module (or skip this step if not using apache): @@ -24,10 +24,6 @@ Install the RPAF apache module (or skip this step if not using apache):
24 24
25 3b) Edit `/etc/apache2/sites-enabled/*`, and change `<VirtualHost *:80>` to `<VirtualHost *:8080>` 25 3b) Edit `/etc/apache2/sites-enabled/*`, and change `<VirtualHost *:80>` to `<VirtualHost *:8080>`
26 26
27 -3c) Restart apache  
28 -  
29 - # invoke-rc.d apache2 restart  
30 -  
31 4) Varnish configuration 27 4) Varnish configuration
32 28
33 4a) Edit `/etc/default/varnish` 29 4a) Edit `/etc/default/varnish`
@@ -44,10 +40,6 @@ On manual installations, change `/etc/noosfero/*` to `{Rails.root}/etc/noosfero/ @@ -44,10 +40,6 @@ On manual installations, change `/etc/noosfero/*` to `{Rails.root}/etc/noosfero/
44 40
45 **NOTE**: it is very important that the `*.vcl` files are included in that order, i.e. *first* include `varnish-noosfero.vcl`, and *after* `noosfero-accept-language.cvl`. 41 **NOTE**: it is very important that the `*.vcl` files are included in that order, i.e. *first* include `varnish-noosfero.vcl`, and *after* `noosfero-accept-language.cvl`.
46 42
47 -4c) Restart Varnish  
48 -  
49 - # invoke-rc.d varnish restart  
50 -  
51 5) Enable varnish logging: 43 5) Enable varnish logging:
52 44
53 5a) Edit `/etc/default/varnishncsa` and uncomment the line that contains: 45 5a) Edit `/etc/default/varnishncsa` and uncomment the line that contains:
@@ -56,8 +48,10 @@ On manual installations, change `/etc/noosfero/*` to `{Rails.root}/etc/noosfero/ @@ -56,8 +48,10 @@ On manual installations, change `/etc/noosfero/*` to `{Rails.root}/etc/noosfero/
56 48
57 The varnish log will be written to `/var/log/varnish/varnishncsa.log` in an apache-compatible format. You should change your statistics generation software (e.g. awstats) to use that instead of apache logs. 49 The varnish log will be written to `/var/log/varnish/varnishncsa.log` in an apache-compatible format. You should change your statistics generation software (e.g. awstats) to use that instead of apache logs.
58 50
59 -5b) Restart Varnish Logging service 51 +Thanks to Cosimo Streppone for varnish-accept-language. See http://github.com/cosimo/varnish-accept-language for more information.
60 52
61 - # invoke-rc.d varnishncsa restart 53 +6) Restart services
62 54
63 -Thanks to Cosimo Streppone for varnish-accept-language. See http://github.com/cosimo/varnish-accept-language for more information. 55 + # service apache2 restart
  56 + # service varnish restart
  57 + # service varnishncsa restart
1 #!/usr/bin/env rake 1 #!/usr/bin/env rake
  2 +
2 # Add your own tasks in files placed in lib/tasks ending in .rake, 3 # Add your own tasks in files placed in lib/tasks ending in .rake,
3 # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 4 # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 5
5 require File.expand_path('../config/application', __FILE__) 6 require File.expand_path('../config/application', __FILE__)
6 7
7 Noosfero::Application.load_tasks 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
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 3
4 VAGRANTFILE_API_VERSION = "2" 4 VAGRANTFILE_API_VERSION = "2"
5 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 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 config.vm.network :forwarded_port, host: 3000, guest: 3000 7 config.vm.network :forwarded_port, host: 3000, guest: 3000
8 config.vm.provision :shell do |shell| 8 config.vm.provision :shell do |shell|
9 shell.inline = 'su vagrant -c /vagrant/script/vagrant' 9 shell.inline = 'su vagrant -c /vagrant/script/vagrant'
app/controllers/admin/admin_panel_controller.rb
@@ -7,6 +7,7 @@ class AdminPanelController &lt; AdminController @@ -7,6 +7,7 @@ class AdminPanelController &lt; AdminController
7 end 7 end
8 8
9 def site_info 9 def site_info
  10 + @no_design_blocks = true
10 if request.post? 11 if request.post?
11 if params[:environment][:languages] 12 if params[:environment][:languages]
12 params[:environment][:languages] = params[:environment][:languages].map {|lang, value| lang if value=='true'}.compact 13 params[:environment][:languages] = params[:environment][:languages].map {|lang, value| lang if value=='true'}.compact
app/controllers/admin/categories_controller.rb
@@ -45,9 +45,11 @@ class CategoriesController &lt; AdminController @@ -45,9 +45,11 @@ class CategoriesController &lt; AdminController
45 if request.post? 45 if request.post?
46 @category.update_attributes!(params[:category]) 46 @category.update_attributes!(params[:category])
47 @saved = true 47 @saved = true
  48 + session[:notice] = _("Category %s saved." % @category.name)
48 redirect_to :action => 'index' 49 redirect_to :action => 'index'
49 end 50 end
50 rescue Exception => e 51 rescue Exception => e
  52 + session[:notice] = _('Could not save category.')
51 render :action => 'edit' 53 render :action => 'edit'
52 end 54 end
53 end 55 end
app/controllers/admin/environment_design_controller.rb
@@ -3,9 +3,7 @@ class EnvironmentDesignController &lt; BoxOrganizerController @@ -3,9 +3,7 @@ class EnvironmentDesignController &lt; BoxOrganizerController
3 protect 'edit_environment_design', :environment 3 protect 'edit_environment_design', :environment
4 4
5 def available_blocks 5 def available_blocks
6 - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
7 - # the Noosfero core soon, see ActionItem3045  
8 - @available_blocks ||= [ ArticleBlock, LoginBlock, EnvironmentStatisticsBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, PeopleBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ] 6 + @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
9 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment) 7 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
10 end 8 end
11 9
app/controllers/admin/features_controller.rb
@@ -51,4 +51,10 @@ class FeaturesController &lt; AdminController @@ -51,4 +51,10 @@ class FeaturesController &lt; AdminController
51 redirect_to :action => 'manage_fields' 51 redirect_to :action => 'manage_fields'
52 end 52 end
53 53
  54 + def search_members
  55 + arg = params[:q].downcase
  56 + result = environment.people.find(:all, :conditions => ['LOWER(name) LIKE ? OR identifier LIKE ?', "%#{arg}%", "%#{arg}%"])
  57 + render :text => prepare_to_token_input(result).to_json
  58 + end
  59 +
54 end 60 end
app/controllers/application_controller.rb
@@ -7,6 +7,12 @@ class ApplicationController &lt; ActionController::Base @@ -7,6 +7,12 @@ class ApplicationController &lt; ActionController::Base
7 before_filter :detect_stuff_by_domain 7 before_filter :detect_stuff_by_domain
8 before_filter :init_noosfero_plugins 8 before_filter :init_noosfero_plugins
9 before_filter :allow_cross_domain_access 9 before_filter :allow_cross_domain_access
  10 + before_filter :login_required, :if => :private_environment?
  11 + before_filter :verify_members_whitelist, :if => [:private_environment?, :user]
  12 +
  13 + def verify_members_whitelist
  14 + render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
  15 + end
10 16
11 after_filter :set_csrf_cookie 17 after_filter :set_csrf_cookie
12 18
@@ -34,7 +40,7 @@ class ApplicationController &lt; ActionController::Base @@ -34,7 +40,7 @@ class ApplicationController &lt; ActionController::Base
34 40
35 theme_layout = theme_option(:layout) 41 theme_layout = theme_option(:layout)
36 if theme_layout 42 if theme_layout
37 - theme_view_file('layouts/'+theme_layout) || theme_layout 43 + (theme_view_file('layouts/'+theme_layout) || theme_layout).to_s
38 else 44 else
39 'application' 45 'application'
40 end 46 end
@@ -187,4 +193,8 @@ class ApplicationController &lt; ActionController::Base @@ -187,4 +193,8 @@ class ApplicationController &lt; ActionController::Base
187 {:results => scope.paginate(paginate_options)} 193 {:results => scope.paginate(paginate_options)}
188 end 194 end
189 195
  196 + def private_environment?
  197 + @environment.enabled?(:restrict_to_members)
  198 + end
  199 +
190 end 200 end
app/controllers/my_profile/cms_controller.rb
@@ -4,6 +4,12 @@ class CmsController &lt; MyProfileController @@ -4,6 +4,12 @@ class CmsController &lt; MyProfileController
4 4
5 include ArticleHelper 5 include ArticleHelper
6 6
  7 + def search_tags
  8 + arg = params[:term].downcase
  9 + result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
  10 + render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json'
  11 + end
  12 +
7 def self.protect_if(*args) 13 def self.protect_if(*args)
8 before_filter(*args) do |c| 14 before_filter(*args) do |c|
9 user, profile = c.send(:user), c.send(:profile) 15 user, profile = c.send(:user), c.send(:profile)
@@ -143,7 +149,9 @@ class CmsController &lt; MyProfileController @@ -143,7 +149,9 @@ class CmsController &lt; MyProfileController
143 end 149 end
144 150
145 @article.profile = profile 151 @article.profile = profile
  152 + @article.author = user
146 @article.last_changed_by = user 153 @article.last_changed_by = user
  154 + @article.created_by = user
147 155
148 translations if @article.translatable? 156 translations if @article.translatable?
149 157
@@ -187,7 +195,18 @@ class CmsController &lt; MyProfileController @@ -187,7 +195,18 @@ class CmsController &lt; MyProfileController
187 end 195 end
188 if request.post? && params[:uploaded_files] 196 if request.post? && params[:uploaded_files]
189 params[:uploaded_files].each do |file| 197 params[:uploaded_files].each do |file|
190 - @uploaded_files << UploadedFile.create({:uploaded_data => file, :profile => profile, :parent => @parent, :last_changed_by => user}, :without_protection => true) unless file == '' 198 + unless file == ''
  199 + @uploaded_files << UploadedFile.create(
  200 + {
  201 + :uploaded_data => file,
  202 + :profile => profile,
  203 + :parent => @parent,
  204 + :last_changed_by => user,
  205 + :author => user,
  206 + },
  207 + :without_protection => true
  208 + )
  209 + end
191 end 210 end
192 @errors = @uploaded_files.select { |f| f.errors.any? } 211 @errors = @uploaded_files.select { |f| f.errors.any? }
193 if @errors.any? 212 if @errors.any?
@@ -208,7 +227,7 @@ class CmsController &lt; MyProfileController @@ -208,7 +227,7 @@ class CmsController &lt; MyProfileController
208 @article = profile.articles.find(params[:id]) 227 @article = profile.articles.find(params[:id])
209 if request.post? 228 if request.post?
210 @article.destroy 229 @article.destroy
211 - session[:notice] = _("\"#{@article.name}\" was removed.") 230 + session[:notice] = _("\"%s\" was removed." % @article.name)
212 referer = Rails.application.routes.recognize_path URI.parse(request.referer).path rescue nil 231 referer = Rails.application.routes.recognize_path URI.parse(request.referer).path rescue nil
213 if referer and referer[:controller] == 'cms' and referer[:action] != 'edit' 232 if referer and referer[:controller] == 'cms' and referer[:action] != 'edit'
214 redirect_to referer 233 redirect_to referer
@@ -231,7 +250,7 @@ class CmsController &lt; MyProfileController @@ -231,7 +250,7 @@ class CmsController &lt; MyProfileController
231 @current_category = Category.find(params[:category_id]) 250 @current_category = Category.find(params[:category_id])
232 @categories = @current_category.children 251 @categories = @current_category.children
233 end 252 end
234 - render :template => 'shared/update_categories', :locals => { :category => @current_category } 253 + render :template => 'shared/update_categories', :locals => { :category => @current_category, :object_name => 'article' }
235 end 254 end
236 255
237 def publish 256 def publish
@@ -247,12 +266,15 @@ class CmsController &lt; MyProfileController @@ -247,12 +266,15 @@ class CmsController &lt; MyProfileController
247 end.compact unless params[:marked_groups].nil? 266 end.compact unless params[:marked_groups].nil?
248 if request.post? 267 if request.post?
249 @failed = {} 268 @failed = {}
  269 + if @marked_groups.empty?
  270 + return session[:notice] = _("Select some group to publish your article")
  271 + end
250 @marked_groups.each do |item| 272 @marked_groups.each do |item|
251 task = ApproveArticle.create!(:article => @article, :name => item[:name], :target => item[:group], :requestor => profile) 273 task = ApproveArticle.create!(:article => @article, :name => item[:name], :target => item[:group], :requestor => profile)
252 begin 274 begin
253 task.finish unless item[:group].moderated_articles? 275 task.finish unless item[:group].moderated_articles?
254 rescue Exception => ex 276 rescue Exception => ex
255 - @failed[ex.message] ? @failed[ex.message] << item[:group].name : @failed[ex.message] = [item[:group].name] 277 + @failed[ex.message] ? @failed[ex.message] << item[:group].name : @failed[ex.message] = [item[:group].name]
256 end 278 end
257 end 279 end
258 if @failed.blank? 280 if @failed.blank?
app/controllers/my_profile/friends_controller.rb 100644 → 100755
@@ -11,7 +11,7 @@ class FriendsController &lt; MyProfileController @@ -11,7 +11,7 @@ class FriendsController &lt; MyProfileController
11 def remove 11 def remove
12 @friend = profile.friends.find(params[:id]) 12 @friend = profile.friends.find(params[:id])
13 if request.post? && params[:confirmation] 13 if request.post? && params[:confirmation]
14 - profile.remove_friend(@friend) 14 + Friendship.remove_friendship(profile, @friend)
15 redirect_to :action => 'index' 15 redirect_to :action => 'index'
16 end 16 end
17 end 17 end
@@ -20,7 +20,7 @@ class FriendsController &lt; MyProfileController @@ -20,7 +20,7 @@ class FriendsController &lt; MyProfileController
20 20
21 class << self 21 class << self
22 def per_page 22 def per_page
23 - 10 23 + 12
24 end 24 end
25 end 25 end
26 def per_page 26 def per_page
app/controllers/my_profile/memberships_controller.rb
@@ -7,9 +7,9 @@ class MembershipsController &lt; MyProfileController @@ -7,9 +7,9 @@ class MembershipsController &lt; MyProfileController
7 ra = profile.role_assignments.find_by_role_id(role.id) 7 ra = profile.role_assignments.find_by_role_id(role.id)
8 ra.present? && ra.resource_type == 'Profile' 8 ra.present? && ra.resource_type == 'Profile'
9 end 9 end
10 - @filter = params[:filter_type].blank? ? nil : params[:filter_type] 10 + @filter = params[:filter_type].to_i
11 begin 11 begin
12 - @memberships = @filter.nil? ? profile.memberships : profile.memberships_by_role(environment.roles.find(@filter)) 12 + @memberships = @filter.zero? ? profile.memberships : profile.memberships_by_role(environment.roles.find(@filter))
13 rescue ActiveRecord::RecordNotFound 13 rescue ActiveRecord::RecordNotFound
14 @memberships = [] 14 @memberships = []
15 end 15 end
@@ -21,6 +21,9 @@ class MembershipsController &lt; MyProfileController @@ -21,6 +21,9 @@ class MembershipsController &lt; MyProfileController
21 @back_to = params[:back_to] || url_for(:action => 'index') 21 @back_to = params[:back_to] || url_for(:action => 'index')
22 if request.post? && @community.valid? 22 if request.post? && @community.valid?
23 @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment})) 23 @community = Community.create_after_moderation(user, params[:community].merge({:environment => environment}))
  24 + if @community.new_record?
  25 + session[:notice] = _('Your new community creation request will be evaluated by an administrator. You will be notified.')
  26 + end
24 redirect_to @back_to 27 redirect_to @back_to
25 return 28 return
26 end 29 end
app/controllers/my_profile/profile_design_controller.rb
@@ -9,14 +9,8 @@ class ProfileDesignController &lt; BoxOrganizerController @@ -9,14 +9,8 @@ class ProfileDesignController &lt; BoxOrganizerController
9 9
10 blocks += plugins.dispatch(:extra_blocks) 10 blocks += plugins.dispatch(:extra_blocks)
11 11
12 - # blocks exclusive for organizations  
13 - if profile.has_members?  
14 - blocks << MembersBlock  
15 - end  
16 -  
17 # blocks exclusive to people 12 # blocks exclusive to people
18 if profile.person? 13 if profile.person?
19 - blocks << FriendsBlock  
20 blocks << FavoriteEnterprisesBlock 14 blocks << FavoriteEnterprisesBlock
21 blocks << CommunitiesBlock 15 blocks << CommunitiesBlock
22 blocks << EnterprisesBlock 16 blocks << EnterprisesBlock
app/controllers/my_profile/profile_editor_controller.rb
@@ -54,7 +54,7 @@ class ProfileEditorController &lt; MyProfileController @@ -54,7 +54,7 @@ class ProfileEditorController &lt; MyProfileController
54 @current_category = Category.find(params[:category_id]) 54 @current_category = Category.find(params[:category_id])
55 @categories = @current_category.children 55 @categories = @current_category.children
56 end 56 end
57 - render :template => 'shared/update_categories', :locals => { :category => @current_category } 57 + render :template => 'shared/update_categories', :locals => { :category => @current_category, :object_name => 'profile_data' }
58 end 58 end
59 59
60 def header_footer 60 def header_footer
app/controllers/my_profile/tasks_controller.rb
@@ -4,6 +4,7 @@ class TasksController &lt; MyProfileController @@ -4,6 +4,7 @@ class TasksController &lt; MyProfileController
4 4
5 def index 5 def index
6 @filter = params[:filter_type].blank? ? nil : params[:filter_type] 6 @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  7 + @task_types = Task.pending_types_for(profile)
7 @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) 8 @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
8 @failed = params ? params[:failed] : {} 9 @failed = params ? params[:failed] : {}
9 end 10 end
app/controllers/public/account_controller.rb
@@ -2,7 +2,7 @@ class AccountController &lt; ApplicationController @@ -2,7 +2,7 @@ class AccountController &lt; ApplicationController
2 2
3 no_design_blocks 3 no_design_blocks
4 4
5 - before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise] 5 + before_filter :login_required, :only => [:activation_question, :accept_terms, :activate_enterprise, :change_password]
6 before_filter :redirect_if_logged_in, :only => [:login, :signup] 6 before_filter :redirect_if_logged_in, :only => [:login, :signup]
7 before_filter :protect_from_bots, :only => :signup 7 before_filter :protect_from_bots, :only => :signup
8 8
@@ -15,9 +15,23 @@ class AccountController &lt; ApplicationController @@ -15,9 +15,23 @@ class AccountController &lt; ApplicationController
15 15
16 def activate 16 def activate
17 @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code] 17 @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code]
18 - if @user and @user.activate  
19 - @message = _("Your account has been activated, now you can log in!")  
20 - render :action => 'login', :userlogin => @user.login 18 + if @user
  19 + unless @user.environment.enabled?('admin_must_approve_new_users')
  20 + if @user.activate
  21 + @message = _("Your account has been activated, now you can log in!")
  22 + check_redirection
  23 + session[:join] = params[:join] unless params[:join].blank?
  24 + render :action => 'login', :userlogin => @user.login
  25 + end
  26 + else
  27 + if @user.create_moderate_task
  28 + session[:notice] = _('Thanks for registering. The administrators were notified.')
  29 + @register_pending = true
  30 + @user.activation_code = nil
  31 + @user.save!
  32 + redirect_to :controller => :home
  33 + end
  34 + end
21 else 35 else
22 session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?") 36 session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
23 redirect_to :controller => :home 37 redirect_to :controller => :home
@@ -35,6 +49,7 @@ class AccountController &lt; ApplicationController @@ -35,6 +49,7 @@ class AccountController &lt; ApplicationController
35 self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user] 49 self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user]
36 50
37 if logged_in? 51 if logged_in?
  52 + check_join_in_community(self.current_user)
38 if params[:remember_me] == "1" 53 if params[:remember_me] == "1"
39 self.current_user.remember_me 54 self.current_user.remember_me
40 cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at } 55 cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
@@ -82,6 +97,7 @@ class AccountController &lt; ApplicationController @@ -82,6 +97,7 @@ class AccountController &lt; ApplicationController
82 @user.return_to = session[:return_to] 97 @user.return_to = session[:return_to]
83 @person = Person.new(params[:profile_data]) 98 @person = Person.new(params[:profile_data])
84 @person.environment = @user.environment 99 @person.environment = @user.environment
  100 +
85 if request.post? 101 if request.post?
86 if may_be_a_bot 102 if may_be_a_bot
87 set_signup_start_time_for_now 103 set_signup_start_time_for_now
@@ -91,6 +107,7 @@ class AccountController &lt; ApplicationController @@ -91,6 +107,7 @@ class AccountController &lt; ApplicationController
91 if session[:may_be_a_bot] 107 if session[:may_be_a_bot]
92 return false unless verify_recaptcha :model=>@user, :message=>_('Captcha (the human test)') 108 return false unless verify_recaptcha :model=>@user, :message=>_('Captcha (the human test)')
93 end 109 end
  110 + @user.community_to_join = session[:join]
94 @user.signup! 111 @user.signup!
95 owner_role = Role.find_by_name('owner') 112 owner_role = Role.find_by_name('owner')
96 @user.person.affiliate(@user.person, [owner_role]) if owner_role 113 @user.person.affiliate(@user.person, [owner_role]) if owner_role
@@ -99,10 +116,20 @@ class AccountController &lt; ApplicationController @@ -99,10 +116,20 @@ class AccountController &lt; ApplicationController
99 invitation.update_attributes!({:friend => @user.person}) 116 invitation.update_attributes!({:friend => @user.person})
100 invitation.finish 117 invitation.finish
101 end 118 end
  119 +
  120 + unless params[:file].nil?
  121 + image = Image::new :uploaded_data=> params[:file][:image]
  122 +
  123 + @user.person.image = image
  124 + @user.person.save
  125 + end
  126 +
102 if @user.activated? 127 if @user.activated?
103 self.current_user = @user 128 self.current_user = @user
  129 + check_join_in_community(@user)
104 go_to_signup_initial_page 130 go_to_signup_initial_page
105 else 131 else
  132 + session[:notice] = _('Thanks for registering!')
106 @register_pending = true 133 @register_pending = true
107 end 134 end
108 end 135 end
@@ -388,12 +415,6 @@ class AccountController &lt; ApplicationController @@ -388,12 +415,6 @@ class AccountController &lt; ApplicationController
388 end 415 end
389 416
390 def go_to_initial_page 417 def go_to_initial_page
391 - if params[:redirection]  
392 - session[:return_to] = @user.return_to  
393 - @user.return_to = nil  
394 - @user.save  
395 - end  
396 -  
397 if params[:return_to] 418 if params[:return_to]
398 redirect_to params[:return_to] 419 redirect_to params[:return_to]
399 elsif environment.enabled?('allow_change_of_redirection_after_login') 420 elsif environment.enabled?('allow_change_of_redirection_after_login')
@@ -444,4 +465,19 @@ class AccountController &lt; ApplicationController @@ -444,4 +465,19 @@ class AccountController &lt; ApplicationController
444 redirect_back_or_default(default) 465 redirect_back_or_default(default)
445 end 466 end
446 end 467 end
  468 +
  469 + def check_redirection
  470 + unless params[:redirection].blank?
  471 + session[:return_to] = @user.return_to
  472 + @user.update_attributes(:return_to => nil)
  473 + end
  474 + end
  475 +
  476 + def check_join_in_community(user)
  477 + profile_to_join = session[:join]
  478 + unless profile_to_join.blank?
  479 + environment.profiles.find_by_identifier(profile_to_join).add_member(user.person)
  480 + session.delete(:join)
  481 + end
  482 + end
447 end 483 end
app/controllers/public/catalog_controller.rb
@@ -11,7 +11,7 @@ class CatalogController &lt; PublicController @@ -11,7 +11,7 @@ class CatalogController &lt; PublicController
11 protected 11 protected
12 12
13 def check_enterprise_and_environment 13 def check_enterprise_and_environment
14 - unless profile.kind_of?(Enterprise) && @profile.environment.enabled?('products_for_enterprises') 14 + unless profile.enterprise? && @profile.environment.enabled?('products_for_enterprises')
15 redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index' 15 redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index'
16 end 16 end
17 end 17 end
app/controllers/public/chat_controller.rb
@@ -19,9 +19,13 @@ class ChatController &lt; PublicController @@ -19,9 +19,13 @@ class ChatController &lt; PublicController
19 def avatar 19 def avatar
20 profile = environment.profiles.find_by_identifier(params[:id]) 20 profile = environment.profiles.find_by_identifier(params[:id])
21 filename, mimetype = profile_icon(profile, :minor, true) 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 end 29 end
26 30
27 def index 31 def index
app/controllers/public/content_viewer_controller.rb
@@ -8,49 +8,32 @@ class ContentViewerController &lt; ApplicationController @@ -8,49 +8,32 @@ class ContentViewerController &lt; ApplicationController
8 helper TagsHelper 8 helper TagsHelper
9 9
10 def view_page 10 def view_page
11 - path = params[:page]  
12 - path = path.join('/') if path.kind_of?(Array)  
13 - path = "#{path}.#{params[:format]}" if params[:format] 11 + path = get_path(params[:page], params[:format])
  12 +
14 @version = params[:version].to_i 13 @version = params[:version].to_i
15 14
16 if path.blank? 15 if path.blank?
17 - @page = profile.home_page  
18 - if @page.nil?  
19 - redirect_to :controller => 'profile', :action => 'index', :profile => profile.identifier  
20 - return  
21 - end 16 + @page = profile.home_page
  17 + return if redirected_to_profile_index
22 else 18 else
23 @page = profile.articles.find_by_path(path) 19 @page = profile.articles.find_by_path(path)
24 - unless @page  
25 - page_from_old_path = profile.articles.find_by_old_path(path)  
26 - if page_from_old_path  
27 - redirect_to profile.url.merge(:page => page_from_old_path.explode_path)  
28 - return  
29 - end  
30 - end 20 + return if redirected_page_from_old_path(path)
31 end 21 end
32 22
33 return unless allow_access_to_page(path) 23 return unless allow_access_to_page(path)
34 24
35 if @version > 0 25 if @version > 0
36 return render_access_denied unless @page.display_versions? 26 return render_access_denied unless @page.display_versions?
37 - @versioned_article = @page.versions.find_by_version(@version)  
38 - if @versioned_article && @page.versions.latest.version != @versioned_article.version  
39 - render :template => 'content_viewer/versioned_article.html.erb'  
40 - return  
41 - end 27 + return if rendered_versioned_article
42 end 28 end
43 29
44 redirect_to_translation and return if @page.profile.redirect_l10n 30 redirect_to_translation and return if @page.profile.redirect_l10n
45 31
46 - if request.post?  
47 - if @page.forum? && @page.has_terms_of_use && params[:terms_accepted] == "true"  
48 - @page.add_agreed_user(user)  
49 - end  
50 - elsif !@page.parent.nil? && @page.parent.forum?  
51 - unless @page.parent.agrees_with_terms?(user)  
52 - redirect_to @page.parent.url  
53 - end 32 + if request.post? && @page.forum?
  33 + process_forum_terms_of_use(user, params[:terms_accepted])
  34 + elsif is_a_forum_topic?(@page) && !@page.parent.agrees_with_terms?(user)
  35 + redirect_to @page.parent.url
  36 + return
54 end 37 end
55 38
56 # At this point the page will be showed 39 # At this point the page will be showed
@@ -58,64 +41,22 @@ class ContentViewerController &lt; ApplicationController @@ -58,64 +41,22 @@ class ContentViewerController &lt; ApplicationController
58 41
59 @page = FilePresenter.for @page 42 @page = FilePresenter.for @page
60 43
61 - if @page.download? params[:view]  
62 - headers['Content-Type'] = @page.mime_type  
63 - headers.merge! @page.download_headers  
64 - data = @page.data  
65 -  
66 - # TODO test the condition  
67 - if data.nil?  
68 - raise "No data for file"  
69 - end  
70 -  
71 - render :text => data, :layout => false  
72 - return  
73 - end 44 + return if rendered_file_download(params[:view])
74 45
75 @form_div = params[:form] 46 @form_div = params[:form]
76 47
77 #FIXME see a better way to do this. It's not need to pass this variable anymore 48 #FIXME see a better way to do this. It's not need to pass this variable anymore
78 @comment = Comment.new 49 @comment = Comment.new
79 50
80 - if @page.has_posts?  
81 - posts = if params[:year] and params[:month]  
82 - filter_date = DateTime.parse("#{params[:year]}-#{params[:month]}-01")  
83 - @page.posts.by_range(filter_date..filter_date.at_end_of_month)  
84 - else  
85 - @page.posts  
86 - end  
87 -  
88 - #FIXME Need to run this before the pagination because this version of  
89 - # will_paginate returns a will_paginate collection instead of a  
90 - # relation.  
91 - blog_with_translation = @page.blog? && @page.display_posts_in_current_language?  
92 - posts = posts.native_translations if blog_with_translation  
93 -  
94 - @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile))).to_a  
95 -  
96 - if blog_with_translation  
97 - @posts.replace @posts.map{ |p| p.get_translation_to(FastGettext.locale) }.compact  
98 - end  
99 - end 51 + process_page_posts(params)
100 52
101 if @page.folder? && @page.gallery? 53 if @page.folder? && @page.gallery?
102 - @images = @page.images.select{ |a| a.display_to? user }  
103 - @images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow] 54 + @images = get_images(@page, params[:npage], params[:slideshow])
104 end 55 end
105 56
106 - @unfollow_form = params[:unfollow] && params[:unfollow] == 'true'  
107 - if params[:unfollow] && params[:unfollow] == 'commit' && request.post?  
108 - @page.followers -= [params[:email]]  
109 - if @page.save  
110 - session[:notice] = _("Notification of new comments to '%s' was successfully canceled") % params[:email]  
111 - end  
112 - end 57 + process_page_followers(params)
113 58
114 - @comments = @page.comments.without_spam  
115 - @comments = @plugins.filter(:unavailable_comments, @comments)  
116 - @comments_count = @comments.count  
117 - @comments = @comments.without_reply.paginate(:per_page => per_page, :page => params[:comment_page] )  
118 - @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order] 59 + process_comments(params)
119 60
120 if request.xhr? and params[:comment_order] 61 if request.xhr? and params[:comment_order]
121 if @comment_order == 'newest' 62 if @comment_order == 'newest'
@@ -133,7 +74,7 @@ class ContentViewerController &lt; ApplicationController @@ -133,7 +74,7 @@ class ContentViewerController &lt; ApplicationController
133 end 74 end
134 75
135 def versions_diff 76 def versions_diff
136 - path = params[:page].join('/') 77 + path = params[:page]
137 @page = profile.articles.find_by_path(path) 78 @page = profile.articles.find_by_path(path)
138 @v1, @v2 = @page.versions.find_by_version(params[:v1]), @page.versions.find_by_version(params[:v2]) 79 @v1, @v2 = @page.versions.find_by_version(params[:v1]), @page.versions.find_by_version(params[:v2])
139 end 80 end
@@ -185,7 +126,7 @@ class ContentViewerController &lt; ApplicationController @@ -185,7 +126,7 @@ class ContentViewerController &lt; ApplicationController
185 elsif !@page.display_to?(user) 126 elsif !@page.display_to?(user)
186 if !profile.public? 127 if !profile.public?
187 private_profile_partial_parameters 128 private_profile_partial_parameters
188 - render :template => 'profile/_private_profile', :status => 403 129 + render :template => 'profile/_private_profile', :status => 403, :formats => [:html]
189 allowed = false 130 allowed = false
190 else #if !profile.visible? 131 else #if !profile.visible?
191 render_access_denied 132 render_access_denied
@@ -203,4 +144,127 @@ class ContentViewerController &lt; ApplicationController @@ -203,4 +144,127 @@ class ContentViewerController &lt; ApplicationController
203 user_agent.match(/crawler/) || 144 user_agent.match(/crawler/) ||
204 user_agent.match(/\(.*https?:\/\/.*\)/) 145 user_agent.match(/\(.*https?:\/\/.*\)/)
205 end 146 end
  147 +
  148 + def get_path(page, format = nil)
  149 + path = page
  150 + path = path.join('/') if path.kind_of?(Array)
  151 + path = "#{path}.#{format}" if format
  152 +
  153 + return path
  154 + end
  155 +
  156 + def redirected_to_profile_index
  157 + if @page.nil?
  158 + redirect_to :controller => 'profile', :action => 'index', :profile => profile.identifier
  159 + return true
  160 + end
  161 +
  162 + return false
  163 + end
  164 +
  165 + def redirected_page_from_old_path(path)
  166 + unless @page
  167 + page_from_old_path = profile.articles.find_by_old_path(path)
  168 + if page_from_old_path
  169 + redirect_to profile.url.merge(:page => page_from_old_path.explode_path)
  170 + return true
  171 + end
  172 + end
  173 +
  174 + return false
  175 + end
  176 +
  177 + def process_forum_terms_of_use(user, terms_accepted = nil)
  178 + if @page.forum? && @page.has_terms_of_use && terms_accepted == "true"
  179 + @page.add_agreed_user(user)
  180 + end
  181 + end
  182 +
  183 + def is_a_forum_topic? (page)
  184 + return (!@page.parent.nil? && @page.parent.forum?)
  185 + end
  186 +
  187 + def rendered_versioned_article
  188 + @versioned_article = @page.versions.find_by_version(@version)
  189 + if @versioned_article && @page.versions.latest.version != @versioned_article.version
  190 + render :template => 'content_viewer/versioned_article.html.erb'
  191 + return true
  192 + end
  193 +
  194 + return false
  195 + end
  196 +
  197 + def rendered_file_download(view = nil)
  198 + if @page.download? view
  199 + headers['Content-Type'] = @page.mime_type
  200 + headers.merge! @page.download_headers
  201 + data = @page.data
  202 +
  203 + # TODO test the condition
  204 + if data.nil?
  205 + raise "No data for file"
  206 + end
  207 +
  208 + render :text => data, :layout => false
  209 + return true
  210 + end
  211 +
  212 + return false
  213 + end
  214 +
  215 + def process_page_posts(params)
  216 + if @page.has_posts?
  217 + posts = get_posts(params[:year], params[:month])
  218 +
  219 + #FIXME Need to run this before the pagination because this version of
  220 + # will_paginate returns a will_paginate collection instead of a
  221 + # relation.
  222 + posts = posts.native_translations if blog_with_translation?(@page)
  223 +
  224 + @posts = posts.paginate({ :page => params[:npage], :per_page => @page.posts_per_page }.merge(Article.display_filter(user, profile))).to_a
  225 +
  226 + if blog_with_translation?(@page)
  227 + @posts.replace @posts.map{ |p| p.get_translation_to(FastGettext.locale) }.compact
  228 + end
  229 + end
  230 + end
  231 +
  232 + def get_posts(year = nil, month = nil)
  233 + if year && month
  234 + filter_date = DateTime.parse("#{year}-#{month}-01")
  235 + return @page.posts.by_range(filter_date..filter_date.at_end_of_month)
  236 + else
  237 + return @page.posts
  238 + end
  239 + end
  240 +
  241 + def blog_with_translation?(page)
  242 + return (page.blog? && page.display_posts_in_current_language?)
  243 + end
  244 +
  245 + def get_images(page, npage, slideshow)
  246 + images = page.images.select{ |a| a.display_to? user }
  247 + images = images.paginate(:per_page => per_page, :page => npage) unless slideshow
  248 +
  249 + return images
  250 + end
  251 +
  252 + def process_page_followers(params)
  253 + @unfollow_form = params[:unfollow] == 'true'
  254 + if params[:unfollow] == 'commit' && request.post?
  255 + @page.followers -= [params[:email]]
  256 + if @page.save
  257 + session[:notice] = _("Notification of new comments to '%s' was successfully canceled") % params[:email]
  258 + end
  259 + end
  260 + end
  261 +
  262 + def process_comments(params)
  263 + @comments = @page.comments.without_spam
  264 + @comments = @plugins.filter(:unavailable_comments, @comments)
  265 + @comments_count = @comments.count
  266 + @comments = @comments.without_reply.paginate(:per_page => per_page, :page => params[:comment_page] )
  267 + @comment_order = params[:comment_order].nil? ? 'oldest' : params[:comment_order]
  268 + end
  269 +
206 end 270 end
app/controllers/public/profile_controller.rb
@@ -3,7 +3,7 @@ class ProfileController &lt; PublicController @@ -3,7 +3,7 @@ class ProfileController &lt; PublicController
3 needs_profile 3 needs_profile
4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail] 5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
6 - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail] 6 + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
7 7
8 helper TagsHelper 8 helper TagsHelper
9 9
@@ -18,6 +18,7 @@ class ProfileController &lt; PublicController @@ -18,6 +18,7 @@ class ProfileController &lt; PublicController
18 @tags = profile.article_tags 18 @tags = profile.article_tags
19 unless profile.display_info_to?(user) 19 unless profile.display_info_to?(user)
20 profile.visible? ? private_profile : invisible_profile 20 profile.visible? ? private_profile : invisible_profile
  21 + render :action => 'index', :status => 403
21 end 22 end
22 end 23 end
23 24
@@ -51,7 +52,7 @@ class ProfileController &lt; PublicController @@ -51,7 +52,7 @@ class ProfileController &lt; PublicController
51 52
52 def communities 53 def communities
53 if is_cache_expired?(profile.communities_cache_key(params)) 54 if is_cache_expired?(profile.communities_cache_key(params))
54 - @communities = profile.communities.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage]) 55 + @communities = profile.communities.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.communities.count)
55 end 56 end
56 end 57 end
57 58
@@ -97,21 +98,12 @@ class ProfileController &lt; PublicController @@ -97,21 +98,12 @@ class ProfileController &lt; PublicController
97 end 98 end
98 99
99 def join_not_logged 100 def join_not_logged
100 - if request.post?  
101 - profile.add_member(user)  
102 - session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed?  
103 - redirect_to_previous_location 101 + session[:join] = profile.identifier
  102 +
  103 + if user
  104 + redirect_to :controller => 'profile', :action => 'join'
104 else 105 else
105 - if user.memberships.include?(profile)  
106 - session[:notice] = _('You are already a member of %s.') % profile.name  
107 - redirect_to profile.url  
108 - return  
109 - end  
110 - if request.xhr?  
111 - render :layout => false  
112 - else  
113 - redirect_to profile.url  
114 - end 106 + redirect_to :controller => '/account', :action => 'login'
115 end 107 end
116 end 108 end
117 109
@@ -211,7 +203,8 @@ class ProfileController &lt; PublicController @@ -211,7 +203,8 @@ class ProfileController &lt; PublicController
211 end 203 end
212 204
213 def more_comments 205 def more_comments
214 - activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity], :user_id => @profile}) 206 + profile_filter = @profile.person? ? {:user_id => @profile} : {:target_id => @profile}
  207 + activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity]}.merge(profile_filter))
215 comments_count = activity.comments.count 208 comments_count = activity.comments.count
216 comment_page = (params[:comment_page] || 1).to_i 209 comment_page = (params[:comment_page] || 1).to_i
217 comments_per_page = 5 210 comments_per_page = 5
@@ -323,7 +316,7 @@ class ProfileController &lt; PublicController @@ -323,7 +316,7 @@ class ProfileController &lt; PublicController
323 abuse_report = AbuseReport.new(params[:abuse_report]) 316 abuse_report = AbuseReport.new(params[:abuse_report])
324 if !params[:content_type].blank? 317 if !params[:content_type].blank?
325 article = params[:content_type].constantize.find(params[:content_id]) 318 article = params[:content_type].constantize.find(params[:content_id])
326 - abuse_report.content = instance_eval(&article.reported_version) 319 + abuse_report.content = article_reported_version(article)
327 end 320 end
328 321
329 user.register_report(abuse_report, profile) 322 user.register_report(abuse_report, profile)
app/helpers/account_helper.rb
@@ -15,12 +15,17 @@ module AccountHelper @@ -15,12 +15,17 @@ module AccountHelper
15 15
16 def suggestion_based_on_username(requested_username='') 16 def suggestion_based_on_username(requested_username='')
17 return "" if requested_username.empty? 17 return "" if requested_username.empty?
  18 +
  19 + requested_username = requested_username.downcase.tr("^#{Profile::IDENTIFIER_FORMAT}", '')
18 usernames = [] 20 usernames = []
  21 + tries = 0
19 3.times do 22 3.times do
20 begin 23 begin
21 valid_name = requested_username + rand(1000).to_s 24 valid_name = requested_username + rand(1000).to_s
22 - end while (usernames.include?(valid_name) || !Person.is_available?(valid_name, environment))  
23 - usernames << valid_name 25 + tries += 1
  26 + invalid = usernames.include?(valid_name) || !Person.is_available?(valid_name, environment)
  27 + end while tries <= 10 && invalid
  28 + usernames << valid_name unless invalid
24 end 29 end
25 usernames 30 usernames
26 end 31 end
app/helpers/application_helper.rb
@@ -304,7 +304,7 @@ module ApplicationHelper @@ -304,7 +304,7 @@ module ApplicationHelper
304 def partial_for_class(klass, prefix=nil, suffix=nil) 304 def partial_for_class(klass, prefix=nil, suffix=nil)
305 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? 305 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil?
306 name = klass.name.underscore 306 name = klass.name.underscore
307 - controller.view_paths.reverse_each do |view_path| 307 + controller.view_paths.each do |view_path|
308 partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix) 308 partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix)
309 return partial if partial 309 return partial if partial
310 end 310 end
@@ -312,13 +312,13 @@ module ApplicationHelper @@ -312,13 +312,13 @@ module ApplicationHelper
312 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' 312 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?'
313 end 313 end
314 314
315 - def view_for_profile_actions(klass)  
316 - raise ArgumentError, 'No profile actions view for this class.' if klass.nil?  
317 -  
318 - name = klass.name.underscore  
319 - return "blocks/profile_info_actions/" + name + '.html.erb' if File.exists?(Rails.root.join('app', 'views', 'blocks', 'profile_info_actions', name + '.html.erb'))  
320 -  
321 - view_for_profile_actions(klass.superclass) 315 + def render_profile_actions klass
  316 + name = klass.to_s.underscore
  317 + begin
  318 + render "blocks/profile_info_actions/#{name}"
  319 + rescue ActionView::MissingTemplate
  320 + render_profile_actions klass.superclass
  321 + end
322 end 322 end
323 323
324 def user 324 def user
@@ -482,7 +482,12 @@ module ApplicationHelper @@ -482,7 +482,12 @@ module ApplicationHelper
482 '/images/icons-app/enterprise-'+ size.to_s() +'.png' 482 '/images/icons-app/enterprise-'+ size.to_s() +'.png'
483 end 483 end
484 else 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 end 491 end
487 filename = default_or_themed_icon(icon) 492 filename = default_or_themed_icon(icon)
488 end 493 end
@@ -602,7 +607,7 @@ module ApplicationHelper @@ -602,7 +607,7 @@ module ApplicationHelper
602 end 607 end
603 608
604 def gravatar_default 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 end 611 end
607 612
608 attr_reader :environment 613 attr_reader :environment
@@ -671,7 +676,7 @@ module ApplicationHelper @@ -671,7 +676,7 @@ module ApplicationHelper
671 676
672 def theme_javascript_ng 677 def theme_javascript_ng
673 script = File.join(theme_path, 'theme.js') 678 script = File.join(theme_path, 'theme.js')
674 - if File.exists?(Rails.root.join('public', script)) 679 + if File.exists?(File.join(Rails.root, 'public', script))
675 javascript_include_tag script 680 javascript_include_tag script
676 else 681 else
677 nil 682 nil
@@ -1002,17 +1007,26 @@ module ApplicationHelper @@ -1002,17 +1007,26 @@ module ApplicationHelper
1002 def display_category_menu(block, categories, root = true) 1007 def display_category_menu(block, categories, root = true)
1003 categories = categories.sort{|x,y| x.name <=> y.name} 1008 categories = categories.sort{|x,y| x.name <=> y.name}
1004 return "" if categories.blank? 1009 return "" if categories.blank?
1005 - content_tag(:ul, 1010 + content_tag(:ul) do
1006 categories.map do |category| 1011 categories.map do |category|
1007 category_path = category.kind_of?(ProductCategory) ? {:controller => 'search', :action => 'assets', :asset => 'products', :product_category => category.id} : { :controller => 'search', :action => 'category_index', :category_path => category.explode_path } 1012 category_path = category.kind_of?(ProductCategory) ? {:controller => 'search', :action => 'assets', :asset => 'products', :product_category => category.id} : { :controller => 'search', :action => 'category_index', :category_path => category.explode_path }
1008 - category.display_in_menu? ?  
1009 - content_tag(:li,  
1010 - ( !category.is_leaf_displayable_in_menu? ? content_tag(:a, collapsed_item_icon, :href => "#", :id => "block_#{block.id}_category_#{category.id}", :class => 'category-link-expand ' + (root ? 'category-root' : 'category-no-root'), :onclick => "expandCategory(#{block.id}, #{category.id}); return false", :style => 'display: none') : leaf_item_icon) +  
1011 - link_to(content_tag(:span, category.name, :class => 'category-name'), category_path, :class => ("category-leaf" if category.is_leaf_displayable_in_menu?)) +  
1012 - content_tag(:div, display_category_menu(block, category.children, false), :id => "block_#{block.id}_category_content_#{category.id}", :class => 'child-category')  
1013 - ) : ''  
1014 - end  
1015 - ) + 1013 + if category.display_in_menu?
  1014 + content_tag(:li) do
  1015 + if !category.is_leaf_displayable_in_menu?
  1016 + content_tag(:a, collapsed_item_icon, :href => "#", :id => "block_#{block.id}_category_#{category.id}", :class => "category-link-expand " + (root ? "category-root" : "category-no-root"), :onclick => "expandCategory(#{block.id}, #{category.id}); return false", :style => "display: none")
  1017 + else
  1018 + leaf_item_icon
  1019 + end +
  1020 + link_to(content_tag(:span, category.name, :class => "category-name"), category_path, :class => ("category-leaf" if category.is_leaf_displayable_in_menu?)) +
  1021 + content_tag(:div, :id => "block_#{block.id}_category_content_#{category.id}", :class => 'child-category') do
  1022 + display_category_menu(block, category.children, false)
  1023 + end
  1024 + end
  1025 + else
  1026 + ""
  1027 + end
  1028 + end.join.html_safe
  1029 + end +
1016 content_tag(:p) + 1030 content_tag(:p) +
1017 (root ? javascript_tag(" 1031 (root ? javascript_tag("
1018 jQuery('.child-category').hide(); 1032 jQuery('.child-category').hide();
@@ -1034,7 +1048,7 @@ module ApplicationHelper @@ -1034,7 +1048,7 @@ module ApplicationHelper
1034 end 1048 end
1035 1049
1036 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') + 1050 link_to(content_tag(:span, _('Contents'), :class => 'icon-menu-articles'), {:controller => "search", :action => 'contents', :category_path => nil}, :id => 'submenu-contents') +
1037 - link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger') 1051 + link_to(content_tag(:span, _('Contents menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-contents-trigger')
1038 end 1052 end
1039 alias :browse_contents_menu :search_contents_menu 1053 alias :browse_contents_menu :search_contents_menu
1040 1054
@@ -1050,7 +1064,7 @@ module ApplicationHelper @@ -1050,7 +1064,7 @@ module ApplicationHelper
1050 end 1064 end
1051 1065
1052 link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') + 1066 link_to(content_tag(:span, _('People'), :class => 'icon-menu-people'), {:controller => "search", :action => 'people', :category_path => ''}, :id => 'submenu-people') +
1053 - link_to(content_tag(:span, _('People menu')), '#', :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger') 1067 + link_to(content_tag(:span, _('People menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-people-trigger')
1054 end 1068 end
1055 alias :browse_people_menu :search_people_menu 1069 alias :browse_people_menu :search_people_menu
1056 1070
@@ -1066,7 +1080,7 @@ module ApplicationHelper @@ -1066,7 +1080,7 @@ module ApplicationHelper
1066 end 1080 end
1067 1081
1068 link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') + 1082 link_to(content_tag(:span, _('Communities'), :class => 'icon-menu-community'), {:controller => "search", :action => 'communities'}, :id => 'submenu-communities') +
1069 - link_to(content_tag(:span, _('Communities menu')), '#', :onclick => "toggleSubmenu(this,'',#{j links.to_json}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger') 1083 + link_to(content_tag(:span, _('Communities menu')), '#', :onclick => "toggleSubmenu(this,'',#{CGI::escapeHTML(links.to_json)}); return false", :class => 'menu-submenu-trigger up', :id => 'submenu-communities-trigger')
1070 end 1084 end
1071 alias :browse_communities_menu :search_communities_menu 1085 alias :browse_communities_menu :search_communities_menu
1072 1086
@@ -1086,47 +1100,51 @@ module ApplicationHelper @@ -1086,47 +1100,51 @@ module ApplicationHelper
1086 result 1100 result
1087 end 1101 end
1088 1102
1089 - def manage_link(list, kind) 1103 + def manage_link(list, kind, title)
1090 if list.present? 1104 if list.present?
1091 link_to_all = nil 1105 link_to_all = nil
1092 if list.count > 5 1106 if list.count > 5
1093 list = list.first(5) 1107 list = list.first(5)
1094 - link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => current_user.login) 1108 + link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => user.identifier)
1095 end 1109 end
1096 link = list.map do |element| 1110 link = list.map do |element|
1097 - link_to(content_tag('strong', [_('<span>Manage</span> %s') % element.short_name(25)]), @environment.top_url + "/myprofile/#{element.identifier}", :class => "icon-menu-"+element.class.identification.underscore, :title => [_('Manage %s') % element.short_name]) 1111 + link_to(content_tag('strong', _('<span>Manage</span> %s') % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s') % element.short_name)
1098 end 1112 end
1099 if link_to_all 1113 if link_to_all
1100 link << link_to_all 1114 link << link_to_all
1101 end 1115 end
1102 - render :partial => "shared/manage_link", :locals => {:link => link, :kind => kind.to_s} 1116 + render :partial => "shared/manage_link", :locals => {:link => link, :kind => kind.to_s, :title => title}
1103 end 1117 end
1104 end 1118 end
1105 1119
1106 def manage_enterprises 1120 def manage_enterprises
1107 - return unless user && user.environment.enabled?(:display_my_enterprises_on_user_menu)  
1108 - manage_link(user.enterprises, :enterprises) 1121 + return '' unless user && user.environment.enabled?(:display_my_enterprises_on_user_menu)
  1122 + manage_link(user.enterprises, :enterprises, _('My enterprises')).to_s
1109 end 1123 end
1110 1124
1111 def manage_communities 1125 def manage_communities
1112 - return unless user && user.environment.enabled?(:display_my_communities_on_user_menu) 1126 + return '' unless user && user.environment.enabled?(:display_my_communities_on_user_menu)
1113 administered_communities = user.communities.more_popular.select {|c| c.admins.include? user} 1127 administered_communities = user.communities.more_popular.select {|c| c.admins.include? user}
1114 - manage_link(administered_communities, :communities) 1128 + manage_link(administered_communities, :communities, _('My communities')).to_s
  1129 + end
  1130 +
  1131 + def admin_link
  1132 + user.is_admin?(environment) ? link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') : ''
1115 end 1133 end
1116 1134
1117 def usermenu_logged_in 1135 def usermenu_logged_in
1118 pending_tasks_count = '' 1136 pending_tasks_count = ''
1119 count = user ? Task.to(user).pending.count : -1 1137 count = user ? Task.to(user).pending.count : -1
1120 if count > 0 1138 if count > 0
1121 - pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) 1139 + pending_tasks_count = link_to(count.to_s, user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1122 end 1140 end
1123 1141
1124 - (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i style="background-image:url({avatar})"></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) + 1142 + (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage'))) +
1125 render_environment_features(:usermenu) + 1143 render_environment_features(:usermenu) +
1126 - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +  
1127 - manage_enterprises.to_s +  
1128 - manage_communities.to_s +  
1129 - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :class => 'ctrl-panel', :title => _("Configure your personal account and content")) + 1144 + admin_link +
  1145 + manage_enterprises +
  1146 + manage_communities +
  1147 + link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content")) +
1130 pending_tasks_count + 1148 pending_tasks_count +
1131 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) 1149 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
1132 end 1150 end
@@ -1210,22 +1228,9 @@ module ApplicationHelper @@ -1210,22 +1228,9 @@ module ApplicationHelper
1210 end 1228 end
1211 1229
1212 def add_zoom_to_images 1230 def add_zoom_to_images
1213 - stylesheet_link_tag('fancybox') +  
1214 - javascript_include_tag('jquery.fancybox-1.3.4.pack') +  
1215 - javascript_tag("jQuery(function($) {  
1216 - $(window).load( function() {  
1217 - $('#article .article-body img').each( function(index) {  
1218 - var original = original_image_dimensions($(this).attr('src'));  
1219 - if ($(this).width() < original['width'] || $(this).height() < original['height']) {  
1220 - $(this).wrap('<div class=\"zoomable-image\" />');  
1221 - $(this).parent('.zoomable-image').attr('style', $(this).attr('style'));  
1222 - $(this).attr('style', '');  
1223 - $(this).after(\'<a href=\"' + $(this).attr('src') + '\" class=\"zoomify-image\"><span class=\"zoomify-text\">%s</span></a>');  
1224 - }  
1225 - });  
1226 - $('.zoomify-image').fancybox();  
1227 - });  
1228 - });" % _('Zoom in')) 1231 + stylesheet_link_tag('jquery.fancybox') +
  1232 + javascript_include_tag('jquery.fancybox.pack') +
  1233 + javascript_tag("apply_zoom_to_images(#{_('Zoom in').to_json})")
1229 end 1234 end
1230 1235
1231 def render_dialog_error_messages(instance_name) 1236 def render_dialog_error_messages(instance_name)
@@ -1281,9 +1286,9 @@ module ApplicationHelper @@ -1281,9 +1286,9 @@ module ApplicationHelper
1281 1286
1282 def delete_article_message(article) 1287 def delete_article_message(article)
1283 if article.folder? 1288 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!") 1289 + _("Are you sure that you want to remove the folder \"%s\"? Note that all the items inside it will also be removed!") % article.name
1285 else 1290 else
1286 - _("Are you sure that you want to remove the item \"#{article.name}\"?") 1291 + _("Are you sure that you want to remove the item \"%s\"?") % article.name
1287 end 1292 end
1288 end 1293 end
1289 1294
@@ -1360,7 +1365,7 @@ module ApplicationHelper @@ -1360,7 +1365,7 @@ module ApplicationHelper
1360 @message = _("The content here is available to %s's friends only.") % profile.short_name 1365 @message = _("The content here is available to %s's friends only.") % profile.short_name
1361 else 1366 else
1362 @action = :join 1367 @action = :join
1363 - @message = _('The contents in this community is available to members only.') 1368 + @message = _('The contents in this profile is available to members only.')
1364 end 1369 end
1365 @no_design_blocks = true 1370 @no_design_blocks = true
1366 end 1371 end
@@ -1402,4 +1407,14 @@ module ApplicationHelper @@ -1402,4 +1407,14 @@ module ApplicationHelper
1402 content_tag('ul', article.versions.map {|v| link_to("r#{v.version}", @page.url.merge(:version => v.version))}) 1407 content_tag('ul', article.versions.map {|v| link_to("r#{v.version}", @page.url.merge(:version => v.version))})
1403 end 1408 end
1404 1409
  1410 + def labelled_colorpicker_field(human_name, object_name, method, options = {})
  1411 + options[:id] ||= 'text-field-' + FormsHelper.next_id_number
  1412 + content_tag('label', human_name, :for => options[:id], :class => 'formlabel') +
  1413 + colorpicker_field(object_name, method, options.merge(:class => 'colorpicker_field'))
  1414 + end
  1415 +
  1416 + def colorpicker_field(object_name, method, options = {})
  1417 + text_field(object_name, method, options.merge(:class => 'colorpicker_field'))
  1418 + end
  1419 +
1405 end 1420 end
app/helpers/article_helper.rb
@@ -3,6 +3,12 @@ module ArticleHelper @@ -3,6 +3,12 @@ module ArticleHelper
3 include PrototypeHelper 3 include PrototypeHelper
4 include TokenHelper 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 def custom_options_for_article(article, tokenized_children) 12 def custom_options_for_article(article, tokenized_children)
7 @article = article 13 @article = article
8 14
@@ -83,6 +89,10 @@ module ArticleHelper @@ -83,6 +89,10 @@ module ArticleHelper
83 array.map { |object| {:id => object.id, :name => object.name} } 89 array.map { |object| {:id => object.id, :name => object.name} }
84 end 90 end
85 91
  92 + def prepare_to_token_input_by_label(array)
  93 + array.map { |object| {:label => object.name, :value => object.name} }
  94 + end
  95 +
86 def cms_label_for_new_children 96 def cms_label_for_new_children
87 _('New article') 97 _('New article')
88 end 98 end
app/helpers/block_helper.rb
@@ -6,19 +6,20 @@ module BlockHelper @@ -6,19 +6,20 @@ module BlockHelper
6 content_tag 'h3', content_tag('span', h(title)), :class => tag_class 6 content_tag 'h3', content_tag('span', h(title)), :class => tag_class
7 end 7 end
8 8
9 - def highlights_block_config_image_fields(block, image={}) 9 + def highlights_block_config_image_fields(block, image={}, row_number=nil)
10 " 10 "
11 - <tr class=\"image-data-line\"> 11 + <tr class=\"image-data-line\" data-row-number='#{row_number}'>
12 <td> 12 <td>
13 #{select_tag 'block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(block.folder_choices, :images, :name, :id, :name, image[:image_id].to_i).html_safe} 13 #{select_tag 'block[images][][image_id]', content_tag(:option) + option_groups_from_collection_for_select(block.folder_choices, :images, :name, :id, :name, image[:image_id].to_i).html_safe}
14 </td> 14 </td>
15 <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td> 15 <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td>
16 <td>#{text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 1}</td> 16 <td>#{text_field_tag 'block[images][][position]', image[:position], :class => 'highlight-position', :size => 1}</td>
17 - </tr><tr class=\"image-title\"> 17 + </tr><tr class=\"image-title\" data-row-number='#{row_number}'>
18 <td colspan=\"3\"><label>#{ 18 <td colspan=\"3\"><label>#{
19 content_tag('span', _('Title')) + 19 content_tag('span', _('Title')) +
20 text_field_tag('block[images][][title]', image[:title], :class => 'highlight-title', :size => 45) 20 text_field_tag('block[images][][title]', image[:title], :class => 'highlight-title', :size => 45)
21 }</label></td> 21 }</label></td>
  22 + <td>#{link_to '', '#', :class=>'button icon-button icon-delete delete-highlight', :confirm=>_('Are you sure you want to remove this highlight')}</td>
22 </tr> 23 </tr>
23 " 24 "
24 end 25 end
app/helpers/blog_helper.rb
@@ -17,13 +17,13 @@ module BlogHelper @@ -17,13 +17,13 @@ module BlogHelper
17 _('Configure blog') 17 _('Configure blog')
18 end 18 end
19 19
20 - def list_posts(articles, format = 'full') 20 + def list_posts(articles, format = 'full', paginate = true)
21 pagination = will_paginate(articles, { 21 pagination = will_paginate(articles, {
22 :param_name => 'npage', 22 :param_name => 'npage',
23 :previous_label => _('&laquo; Newer posts'), 23 :previous_label => _('&laquo; Newer posts'),
24 :next_label => _('Older posts &raquo;'), 24 :next_label => _('Older posts &raquo;'),
25 :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"} 25 :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
26 - }) if articles.present? 26 + }) if articles.present? && paginate
27 content = [] 27 content = []
28 artic_len = articles.length 28 artic_len = articles.length
29 articles.each_with_index{ |art,i| 29 articles.each_with_index{ |art,i|
@@ -45,9 +45,9 @@ module BlogHelper @@ -45,9 +45,9 @@ module BlogHelper
45 45
46 def display_post(article, format = 'full') 46 def display_post(article, format = 'full')
47 no_comments = (format == 'full') ? false : true 47 no_comments = (format == 'full') ? false : true
  48 + title = article_title(article, :no_comments => no_comments)
48 html = send("display_#{format}_format", FilePresenter.for(article)).html_safe 49 html = send("display_#{format}_format", FilePresenter.for(article)).html_safe
49 -  
50 - article_title(article, :no_comments => no_comments) + html 50 + title + html
51 end 51 end
52 52
53 def display_full_format(article) 53 def display_full_format(article)
app/helpers/categories_helper.rb
1 module CategoriesHelper 1 module CategoriesHelper
2 2
3 -  
4 - COLORS = [  
5 - [ N_('Do not display at the menu'), nil ],  
6 - [ N_('Orange'), 1],  
7 - [ N_('Green'), 2],  
8 - [ N_('Purple'), 3],  
9 - [ N_('Red'), 4],  
10 - [ N_('Dark Green'), 5],  
11 - [ N_('Blue Oil'), 6],  
12 - [ N_('Blue'), 7],  
13 - [ N_('Brown'), 8],  
14 - [ N_('Light Green'), 9],  
15 - [ N_('Light Blue'), 10],  
16 - [ N_('Dark Blue'), 11],  
17 - [ N_('Blue Pool'), 12],  
18 - [ N_('Beige'), 13],  
19 - [ N_('Yellow'), 14],  
20 - [ N_('Light Brown'), 15]  
21 - ]  
22 -  
23 TYPES = [ 3 TYPES = [
24 [ _('General Category'), Category.to_s ], 4 [ _('General Category'), Category.to_s ],
25 [ _('Product Category'), ProductCategory.to_s ], 5 [ _('Product Category'), ProductCategory.to_s ],
26 [ _('Region'), Region.to_s ], 6 [ _('Region'), Region.to_s ],
27 ] 7 ]
28 8
29 - def select_color_for_category  
30 - if @category.top_level?  
31 - labelled_form_field(_('Display at the menu?'), select('category', 'display_color', CategoriesHelper::COLORS.map {|item| [gettext(item[0]), item[1]] }))  
32 - else  
33 - ""  
34 - end  
35 - end  
36 -  
37 - def display_color_for_category(category)  
38 - color = category.display_color  
39 - if color.nil?  
40 - ""  
41 - else  
42 - "[" + gettext(CategoriesHelper::COLORS.find {|item| item[1] == color}.first) + "]"  
43 - end  
44 - end  
45 -  
46 def select_category_type(field) 9 def select_category_type(field)
47 value = params[field] 10 value = params[field]
48 labelled_form_field(_('Type of category'), select_tag('type', options_for_select(TYPES, value))) 11 labelled_form_field(_('Type of category'), select_tag('type', options_for_select(TYPES, value)))
49 end 12 end
50 13
  14 + def category_color_style(category)
  15 + return '' if category.nil? or category.display_color.blank?
  16 + 'background-color: #'+category.display_color+';'
  17 + end
  18 +
51 #FIXME make this test 19 #FIXME make this test
52 def selected_category_link(cat) 20 def selected_category_link(cat)
53 js_remove = "jQuery('#selected-category-#{cat.id}').remove();" 21 js_remove = "jQuery('#selected-category-#{cat.id}').remove();"
app/helpers/content_viewer_helper.rb
@@ -10,7 +10,7 @@ module ContentViewerHelper @@ -10,7 +10,7 @@ module ContentViewerHelper
10 end 10 end
11 11
12 def number_of_comments(article) 12 def number_of_comments(article)
13 - display_number_of_comments(article.comments.without_spam.count) 13 + display_number_of_comments(article.comments_count - article.spam_comments_count)
14 end 14 end
15 15
16 def article_title(article, args = {}) 16 def article_title(article, args = {})
@@ -26,7 +26,7 @@ module ContentViewerHelper @@ -26,7 +26,7 @@ module ContentViewerHelper
26 end 26 end
27 title << content_tag('span', 27 title << content_tag('span',
28 content_tag('span', show_date(article.published_at), :class => 'date') + 28 content_tag('span', show_date(article.published_at), :class => 'date') +
29 - content_tag('span', _(", by %s") % link_to(article.author_name, article.author_url), :class => 'author') + 29 + content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') +
30 content_tag('span', comments, :class => 'comments'), 30 content_tag('span', comments, :class => 'comments'),
31 :class => 'created-at' 31 :class => 'created-at'
32 ) 32 )
app/helpers/folder_helper.rb
@@ -5,15 +5,17 @@ module FolderHelper @@ -5,15 +5,17 @@ module FolderHelper
5 include ShortFilename 5 include ShortFilename
6 include ArticleHelper 6 include ArticleHelper
7 7
8 - def list_articles(articles, recursive = false)  
9 - if !articles.blank?  
10 - articles = articles.paginate( 8 + def list_contents(configure={})
  9 + configure[:recursive] ||= false
  10 + configure[:list_type] ||= :folder
  11 + if !configure[:contents].blank?
  12 + configure[:contents] = configure[:contents].paginate(
11 :order => "updated_at DESC", 13 :order => "updated_at DESC",
12 :per_page => 10, 14 :per_page => 10,
13 :page => params[:npage] 15 :page => params[:npage]
14 ) 16 )
15 17
16 - render :file => 'shared/articles_list', :locals => {:articles => articles, :recursive => recursive} 18 + render :file => 'shared/content_list', :locals => configure
17 else 19 else
18 content_tag('em', _('(empty folder)')) 20 content_tag('em', _('(empty folder)'))
19 end 21 end
@@ -23,21 +25,33 @@ module FolderHelper @@ -23,21 +25,33 @@ module FolderHelper
23 articles.select {|article| article.display_to?(user)} 25 articles.select {|article| article.display_to?(user)}
24 end 26 end
25 27
26 - def display_article_in_listing(article, recursive = false, level = 0)  
27 - article = FilePresenter.for article  
28 - article_link = if article.image?  
29 - link_to('&nbsp;' * (level * 4) + image_tag(icon_for_article(article)) + short_filename(article.name), article.url.merge(:view => true)) 28 + def display_content_in_listing(configure={})
  29 + recursive = configure[:recursive] || false
  30 + list_type = configure[:list_type] || :folder
  31 + level = configure[:level] || 0
  32 + content = FilePresenter.for configure[:content]
  33 + content_link = if content.image?
  34 + link_to('&nbsp;' * (level * 4) +
  35 + image_tag(icon_for_article(content)) + short_filename(content.name),
  36 + content.url.merge(:view => true)
  37 + )
30 else 38 else
31 - link_to('&nbsp;' * (level * 4) + short_filename(article.name), article.url.merge(:view => true), :class => icon_for_article(article)) 39 + link_to('&nbsp;' * (level * 4) +
  40 + short_filename(content.name),
  41 + content.url.merge(:view => true), :class => icon_for_article(content)
  42 + )
32 end 43 end
33 result = content_tag( 44 result = content_tag(
34 'tr', 45 'tr',
35 - content_tag('td', article_link )+  
36 - content_tag('td', show_date(article.updated_at), :class => 'last-update'),  
37 - :class => 'sitemap-item' 46 + content_tag('td', content_link ) +
  47 + content_tag('td', show_date(content.updated_at), :class => 'last-update'),
  48 + :class => "#{list_type}-item"
38 ) 49 )
39 if recursive 50 if recursive
40 - result + article.children.map {|item| display_article_in_listing(item, recursive, level + 1) }.join('') 51 + result + content.children.map {|item|
  52 + display_content_in_listing :content=>item, :recursive=>recursive,
  53 + :list_type=>list_type, :level=>level+1
  54 + }.join("\n")
41 else 55 else
42 result 56 result
43 end 57 end
app/helpers/layout_helper.rb
@@ -27,6 +27,7 @@ module LayoutHelper @@ -27,6 +27,7 @@ module LayoutHelper
27 'thickbox', 27 'thickbox',
28 'lightbox', 28 'lightbox',
29 'colorbox', 29 'colorbox',
  30 + 'inputosaurus',
30 pngfix_stylesheet_path, 31 pngfix_stylesheet_path,
31 ] + tokeninput_stylesheets 32 ] + tokeninput_stylesheets
32 plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') } 33 plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }
app/helpers/profile_helper.rb
1 module ProfileHelper 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 unless force || profile.may_display_field_to?(field, user) 74 unless force || profile.may_display_field_to?(field, user)
5 return '' 75 return ''
6 end 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 else 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 end 90 end
16 end 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 end 132 end
31 end 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 else 188 else
39 - content_tag('tr', content_tag('th', _('Work'), { :colspan => 2 })) + organization + organization_site 189 + super
40 end 190 end
41 end 191 end
42 192
app/helpers/sweeper_helper.rb
@@ -18,9 +18,7 @@ module SweeperHelper @@ -18,9 +18,7 @@ module SweeperHelper
18 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s)) 18 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s))
19 end 19 end
20 20
21 - # friends blocks  
22 - blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)}  
23 - BlockSweeper.expire_blocks(blocks) 21 + expire_blocks_cache(profile, [:profile])
24 end 22 end
25 23
26 def expire_communities(profile) 24 def expire_communities(profile)
app/helpers/tinymce_helper.rb 0 → 100644
@@ -0,0 +1,51 @@ @@ -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 => environment.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/helpers/token_helper.rb
@@ -18,6 +18,7 @@ module TokenHelper @@ -18,6 +18,7 @@ module TokenHelper
18 options[:on_add] ||= 'null' 18 options[:on_add] ||= 'null'
19 options[:on_delete] ||= 'null' 19 options[:on_delete] ||= 'null'
20 options[:on_ready] ||= 'null' 20 options[:on_ready] ||= 'null'
  21 + options[:query_param] ||= 'q'
21 22
22 result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id}))) 23 result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id})))
23 result += javascript_tag("jQuery('##{element_id}') 24 result += javascript_tag("jQuery('##{element_id}')
@@ -30,7 +31,7 @@ module TokenHelper @@ -30,7 +31,7 @@ module TokenHelper
30 searchDelay: #{options[:search_delay].to_json}, 31 searchDelay: #{options[:search_delay].to_json},
31 preventDuplicates: #{options[:prevent_duplicates].to_json}, 32 preventDuplicates: #{options[:prevent_duplicates].to_json},
32 backspaceDeleteItem: #{options[:backspace_delete_item].to_json}, 33 backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
33 - queryParam: #{name.to_json}, 34 + queryParam: #{options[:query_param].to_json},
34 tokenLimit: #{options[:token_limit].to_json}, 35 tokenLimit: #{options[:token_limit].to_json},
35 onResult: #{options[:on_result]}, 36 onResult: #{options[:on_result]},
36 onAdd: #{options[:on_add]}, 37 onAdd: #{options[:on_add]},
@@ -48,4 +49,4 @@ module TokenHelper @@ -48,4 +49,4 @@ module TokenHelper
48 result 49 result
49 end 50 end
50 51
51 -end  
52 \ No newline at end of file 52 \ No newline at end of file
  53 +end
app/mailers/user_mailer.rb
@@ -15,10 +15,12 @@ class UserMailer &lt; ActionMailer::Base @@ -15,10 +15,12 @@ class UserMailer &lt; ActionMailer::Base
15 end 15 end
16 16
17 def activation_code(user) 17 def activation_code(user)
18 - @recipient = user.name, 18 + @recipient = user.name
19 @activation_code = user.activation_code 19 @activation_code = user.activation_code
20 @environment = user.environment.name 20 @environment = user.environment.name
21 @url = user.environment.top_url 21 @url = user.environment.top_url
  22 + @redirection = (true if user.return_to)
  23 + @join = (user.community_to_join if user.community_to_join)
22 24
23 mail( 25 mail(
24 from: "#{user.environment.name} <#{user.environment.contact_email}>", 26 from: "#{user.environment.name} <#{user.environment.contact_email}>",
app/models/approve_article.rb
@@ -48,7 +48,7 @@ class ApproveArticle &lt; Task @@ -48,7 +48,7 @@ class ApproveArticle &lt; Task
48 end 48 end
49 49
50 def perform 50 def perform
51 - article.copy!(:name => name, :abstract => abstract, :body => body, :profile => target, :reference_article => article, :parent => article_parent, :highlighted => highlighted, :source => article.source, :last_changed_by_id => article.author_id) 51 + article.copy!(:name => name, :abstract => abstract, :body => body, :profile => target, :reference_article => article, :parent => article_parent, :highlighted => highlighted, :source => article.source, :last_changed_by_id => article.last_changed_by_id, :created_by_id => article.created_by_id)
52 end 52 end
53 53
54 def title 54 def title
app/models/article.rb
@@ -2,7 +2,7 @@ require &#39;hpricot&#39; @@ -2,7 +2,7 @@ require &#39;hpricot&#39;
2 2
3 class Article < ActiveRecord::Base 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 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
6 6
7 acts_as_having_image 7 acts_as_having_image
8 8
@@ -41,8 +41,8 @@ class Article &lt; ActiveRecord::Base @@ -41,8 +41,8 @@ class Article &lt; ActiveRecord::Base
41 before_save :sanitize_tag_list 41 before_save :sanitize_tag_list
42 42
43 before_create do |article| 43 before_create do |article|
44 - if article.last_changed_by_id  
45 - article.author_name = Person.find(article.last_changed_by_id).name 44 + if article.author
  45 + article.author_name = article.author.name
46 end 46 end
47 end 47 end
48 48
@@ -54,7 +54,9 @@ class Article &lt; ActiveRecord::Base @@ -54,7 +54,9 @@ class Article &lt; ActiveRecord::Base
54 54
55 validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? } 55 validates_uniqueness_of :slug, :scope => ['profile_id', 'parent_id'], :message => N_('The title (article name) is already being used by another article, please use another title.'), :if => lambda { |article| !article.slug.blank? }
56 56
  57 + belongs_to :author, :class_name => 'Person'
57 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id' 58 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
  59 + belongs_to :created_by, :class_name => 'Person', :foreign_key => 'created_by_id'
58 60
59 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc' 61 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
60 62
@@ -89,6 +91,11 @@ class Article &lt; ActiveRecord::Base @@ -89,6 +91,11 @@ class Article &lt; ActiveRecord::Base
89 article.parent = article.profile.blog 91 article.parent = article.profile.blog
90 end 92 end
91 end 93 end
  94 +
  95 + if article.created_by
  96 + article.author_name = article.created_by.name
  97 + end
  98 +
92 end 99 end
93 100
94 after_destroy :destroy_activity 101 after_destroy :destroy_activity
@@ -150,14 +157,17 @@ class Article &lt; ActiveRecord::Base @@ -150,14 +157,17 @@ class Article &lt; ActiveRecord::Base
150 self.profile 157 self.profile
151 end 158 end
152 159
153 - def self.human_attribute_name(attrib, options = {}) 160 + def self.human_attribute_name_with_customization(attrib, options={})
154 case attrib.to_sym 161 case attrib.to_sym
155 when :name 162 when :name
156 _('Title') 163 _('Title')
157 else 164 else
158 - _(self.superclass.human_attribute_name(attrib)) 165 + _(self.human_attribute_name_without_customization(attrib))
159 end 166 end
160 end 167 end
  168 + class << self
  169 + alias_method_chain :human_attribute_name, :customization
  170 + end
161 171
162 def css_class_list 172 def css_class_list
163 [self.class.name.to_css_class] 173 [self.class.name.to_css_class]
@@ -205,6 +215,10 @@ class Article &lt; ActiveRecord::Base @@ -205,6 +215,10 @@ class Article &lt; ActiveRecord::Base
205 acts_as_versioned 215 acts_as_versioned
206 self.non_versioned_columns << 'setting' 216 self.non_versioned_columns << 'setting'
207 217
  218 + def version_condition_met?
  219 + (['name', 'body', 'abstract', 'filename', 'start_date', 'end_date', 'image_id', 'license_id'] & changed).length > 0
  220 + end
  221 +
208 def comment_data 222 def comment_data
209 comments.map {|item| [item.title, item.body].join(' ') }.join(' ') 223 comments.map {|item| [item.title, item.body].join(' ') }.join(' ')
210 end 224 end
@@ -271,13 +285,6 @@ class Article &lt; ActiveRecord::Base @@ -271,13 +285,6 @@ class Article &lt; ActiveRecord::Base
271 end 285 end
272 end 286 end
273 287
274 - def reported_version(options = {})  
275 - article = self  
276 - search_path = Rails.root.join('app', 'views', 'shared', 'reported_versions')  
277 - partial_path = File.join('shared', 'reported_versions', partial_for_class_in_view_path(article.class, search_path))  
278 - lambda { render_to_string(:partial => partial_path, :locals => {:article => article}) }  
279 - end  
280 -  
281 # returns the data of the article. Must be overriden in each subclass to 288 # returns the data of the article. Must be overriden in each subclass to
282 # provide the correct content for the article. 289 # provide the correct content for the article.
283 def data 290 def data
@@ -452,10 +459,10 @@ class Article &lt; ActiveRecord::Base @@ -452,10 +459,10 @@ class Article &lt; ActiveRecord::Base
452 ['TextArticle', 'TextileArticle', 'TinyMceArticle'] 459 ['TextArticle', 'TextileArticle', 'TinyMceArticle']
453 end 460 end
454 461
455 - scope :published, :conditions => { :published => true }  
456 - scope :folders, lambda {|profile|{:conditions => { :type => profile.folder_types} }}  
457 - scope :no_folders, lambda {|profile|{:conditions => ['type NOT IN (?)', profile.folder_types]}}  
458 - scope :galleries, :conditions => { :type => 'Gallery' } 462 + scope :published, :conditions => ['articles.published = ?', true]
  463 + scope :folders, lambda {|profile|{:conditions => ['articles.type IN (?)', profile.folder_types] }}
  464 + scope :no_folders, lambda {|profile|{:conditions => ['articles.type NOT IN (?)', profile.folder_types]}}
  465 + scope :galleries, :conditions => [ "articles.type IN ('Gallery')" ]
459 scope :images, :conditions => { :is_image => true } 466 scope :images, :conditions => { :is_image => true }
460 scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ] 467 scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
461 scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } } 468 scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } }
@@ -465,7 +472,7 @@ class Article &lt; ActiveRecord::Base @@ -465,7 +472,7 @@ class Article &lt; ActiveRecord::Base
465 scope :more_recent, :order => "created_at DESC" 472 scope :more_recent, :order => "created_at DESC"
466 473
467 def self.display_filter(user, profile) 474 def self.display_filter(user, profile)
468 - return {:conditions => ['published = ?', true]} if !user 475 + return {:conditions => ['articles.published = ?', true]} if !user
469 {:conditions => [" articles.published = ? OR 476 {:conditions => [" articles.published = ? OR
470 articles.last_changed_by_id = ? OR 477 articles.last_changed_by_id = ? OR
471 articles.profile_id = ? OR 478 articles.profile_id = ? OR
@@ -492,6 +499,7 @@ class Article &lt; ActiveRecord::Base @@ -492,6 +499,7 @@ class Article &lt; ActiveRecord::Base
492 end 499 end
493 500
494 def allow_post_content?(user = nil) 501 def allow_post_content?(user = nil)
  502 + return true if allow_edit_topic?(user)
495 user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == author)) 503 user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == author))
496 end 504 end
497 505
@@ -511,9 +519,14 @@ class Article &lt; ActiveRecord::Base @@ -511,9 +519,14 @@ class Article &lt; ActiveRecord::Base
511 end 519 end
512 520
513 def allow_edit?(user) 521 def allow_edit?(user)
  522 + return true if allow_edit_topic?(user)
514 allow_post_content?(user) || user && allow_members_to_edit && user.is_member_of?(profile) 523 allow_post_content?(user) || user && allow_members_to_edit && user.is_member_of?(profile)
515 end 524 end
516 525
  526 + def allow_edit_topic?(user)
  527 + self.belongs_to_forum? && (user == author) && user.present? && user.is_member_of?(profile)
  528 + end
  529 +
517 def moderate_comments? 530 def moderate_comments?
518 moderate_comments == true 531 moderate_comments == true
519 end 532 end
@@ -628,39 +641,36 @@ class Article &lt; ActiveRecord::Base @@ -628,39 +641,36 @@ class Article &lt; ActiveRecord::Base
628 can_display_versions? && display_versions 641 can_display_versions? && display_versions
629 end 642 end
630 643
631 - def author(version_number = nil)  
632 - if version_number  
633 - version = versions.find_by_version(version_number)  
634 - author_id = version.last_changed_by_id if version  
635 - Person.exists?(author_id) ? Person.find(author_id) : nil  
636 - else  
637 - if versions.empty?  
638 - last_changed_by  
639 - else  
640 - author_id = versions.first.last_changed_by_id  
641 - Person.exists?(author_id) ? Person.find(author_id) : nil  
642 - end  
643 - end 644 + def get_version(version_number = nil)
  645 + version_number ? versions.find(:first, :order => 'version', :offset => version_number - 1) : versions.earliest
  646 + end
  647 +
  648 + def author_by_version(version_number = nil)
  649 + version_number ? profile.environment.people.find_by_id(get_version(version_number).author_id) : author
644 end 650 end
645 651
646 def author_name(version_number = nil) 652 def author_name(version_number = nil)
647 - person = author(version_number)  
648 - person ? person.name : (setting[:author_name] || _('Unknown')) 653 + person = author_by_version(version_number)
  654 + if version_number
  655 + person ? person.name : _('Unknown')
  656 + else
  657 + person ? person.name : (setting[:author_name] || _('Unknown'))
  658 + end
649 end 659 end
650 660
651 def author_url(version_number = nil) 661 def author_url(version_number = nil)
652 - person = author(version_number) 662 + person = author_by_version(version_number)
653 person ? person.url : nil 663 person ? person.url : nil
654 end 664 end
655 665
656 def author_id(version_number = nil) 666 def author_id(version_number = nil)
657 - person = author(version_number) 667 + person = author_by_version(version_number)
658 person ? person.id : nil 668 person ? person.id : nil
659 end 669 end
660 670
661 def version_license(version_number = nil) 671 def version_license(version_number = nil)
662 return license if version_number.nil? 672 return license if version_number.nil?
663 - profile.environment.licenses.find_by_id(versions.find_by_version(version_number).license_id) 673 + profile.environment.licenses.find_by_id(get_version(version_number).license_id)
664 end 674 end
665 675
666 alias :active_record_cache_key :cache_key 676 alias :active_record_cache_key :cache_key
app/models/block.rb
@@ -22,6 +22,10 @@ class Block &lt; ActiveRecord::Base @@ -22,6 +22,10 @@ class Block &lt; ActiveRecord::Base
22 false 22 false
23 end 23 end
24 24
  25 + def get_limit
  26 + [0,limit].max
  27 + end
  28 +
25 def embed_code 29 def embed_code
26 me = self 30 me = self
27 proc do 31 proc do
@@ -188,7 +192,7 @@ class Block &lt; ActiveRecord::Base @@ -188,7 +192,7 @@ class Block &lt; ActiveRecord::Base
188 192
189 # Override in your subclasses. 193 # Override in your subclasses.
190 # Define which events and context should cause the block cache to expire 194 # Define which events and context should cause the block cache to expire
191 - # Possible events are: :article, :profile, :friendship, :category 195 + # Possible events are: :article, :profile, :friendship, :category, :role_assignment
192 # Possible contexts are: :profile, :environment 196 # Possible contexts are: :profile, :environment
193 def self.expire_on 197 def self.expire_on
194 { 198 {
@@ -230,4 +234,9 @@ class Block &lt; ActiveRecord::Base @@ -230,4 +234,9 @@ class Block &lt; ActiveRecord::Base
230 duplicated_block 234 duplicated_block
231 end 235 end
232 236
  237 + def copy_from(block)
  238 + self.settings = block.settings
  239 + self.position = block.position
  240 + end
  241 +
233 end 242 end
app/models/box.rb
@@ -28,20 +28,14 @@ class Box &lt; ActiveRecord::Base @@ -28,20 +28,14 @@ class Box &lt; ActiveRecord::Base
28 CategoriesBlock, 28 CategoriesBlock,
29 CommunitiesBlock, 29 CommunitiesBlock,
30 EnterprisesBlock, 30 EnterprisesBlock,
31 - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
32 - # the Noosfero core soon, see ActionItem3045  
33 - EnvironmentStatisticsBlock,  
34 FansBlock, 31 FansBlock,
35 FavoriteEnterprisesBlock, 32 FavoriteEnterprisesBlock,
36 FeedReaderBlock, 33 FeedReaderBlock,
37 - FriendsBlock,  
38 HighlightsBlock, 34 HighlightsBlock,
39 LinkListBlock, 35 LinkListBlock,
40 LoginBlock, 36 LoginBlock,
41 MainBlock, 37 MainBlock,
42 - MembersBlock,  
43 MyNetworkBlock, 38 MyNetworkBlock,
44 - PeopleBlock,  
45 ProfileImageBlock, 39 ProfileImageBlock,
46 RawHTMLBlock, 40 RawHTMLBlock,
47 RecentDocumentsBlock, 41 RecentDocumentsBlock,
@@ -56,21 +50,15 @@ class Box &lt; ActiveRecord::Base @@ -56,21 +50,15 @@ class Box &lt; ActiveRecord::Base
56 CommunitiesBlock, 50 CommunitiesBlock,
57 DisabledEnterpriseMessageBlock, 51 DisabledEnterpriseMessageBlock,
58 EnterprisesBlock, 52 EnterprisesBlock,
59 - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
60 - # the Noosfero core soon, see ActionItem3045  
61 - EnvironmentStatisticsBlock,  
62 FansBlock, 53 FansBlock,
63 FavoriteEnterprisesBlock, 54 FavoriteEnterprisesBlock,
64 FeaturedProductsBlock, 55 FeaturedProductsBlock,
65 FeedReaderBlock, 56 FeedReaderBlock,
66 - FriendsBlock,  
67 HighlightsBlock, 57 HighlightsBlock,
68 LinkListBlock, 58 LinkListBlock,
69 LocationBlock, 59 LocationBlock,
70 LoginBlock, 60 LoginBlock,
71 - MembersBlock,  
72 MyNetworkBlock, 61 MyNetworkBlock,
73 - PeopleBlock,  
74 ProductsBlock, 62 ProductsBlock,
75 ProductCategoriesBlock, 63 ProductCategoriesBlock,
76 ProfileImageBlock, 64 ProfileImageBlock,
app/models/categories_block.rb
@@ -8,6 +8,8 @@ class CategoriesBlock &lt; Block @@ -8,6 +8,8 @@ class CategoriesBlock &lt; Block
8 8
9 settings_items :category_types, :type => Array, :default => [] 9 settings_items :category_types, :type => Array, :default => []
10 10
  11 + attr_accessible :category_types
  12 +
11 def self.description 13 def self.description
12 _("Categories Menu") 14 _("Categories Menu")
13 end 15 end
app/models/category.rb
@@ -14,9 +14,6 @@ class Category &lt; ActiveRecord::Base @@ -14,9 +14,6 @@ class Category &lt; ActiveRecord::Base
14 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('{fn} is already being used by another category.').fix_i18n 14 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('{fn} is already being used by another category.').fix_i18n
15 belongs_to :environment 15 belongs_to :environment
16 16
17 - validates_inclusion_of :display_color, :in => 1..15, :allow_nil => true  
18 - validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('{fn} was already assigned to another category.').fix_i18n  
19 -  
20 # Finds all top level categories for a given environment. 17 # Finds all top level categories for a given environment.
21 scope :top_level_for, lambda { |environment| 18 scope :top_level_for, lambda { |environment|
22 {:conditions => ['parent_id is null and environment_id = ?', environment.id ]} 19 {:conditions => ['parent_id is null and environment_id = ?', environment.id ]}
@@ -42,6 +39,13 @@ class Category &lt; ActiveRecord::Base @@ -42,6 +39,13 @@ class Category &lt; ActiveRecord::Base
42 39
43 acts_as_having_image 40 acts_as_having_image
44 41
  42 + before_save :normalize_display_color
  43 +
  44 + def normalize_display_color
  45 + display_color.gsub!('#', '') if display_color
  46 + display_color = nil if display_color.blank?
  47 + end
  48 +
45 scope :from_types, lambda { |types| 49 scope :from_types, lambda { |types|
46 types.select{ |t| t.blank? }.empty? ? 50 types.select{ |t| t.blank? }.empty? ?
47 { :conditions => { :type => types } } : 51 { :conditions => { :type => types } } :
@@ -101,4 +105,12 @@ class Category &lt; ActiveRecord::Base @@ -101,4 +105,12 @@ class Category &lt; ActiveRecord::Base
101 self.children.find(:all, :conditions => {:display_in_menu => true}).empty? 105 self.children.find(:all, :conditions => {:display_in_menu => true}).empty?
102 end 106 end
103 107
  108 + def with_color
  109 + if display_color.blank?
  110 + parent.nil? ? nil : parent.with_color
  111 + else
  112 + self
  113 + end
  114 + end
  115 +
104 end 116 end
app/models/change_password.rb
@@ -2,16 +2,19 @@ class ChangePassword &lt; Task @@ -2,16 +2,19 @@ class ChangePassword &lt; Task
2 2
3 attr_accessor :password, :password_confirmation 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 case attrib.to_sym 6 case attrib.to_sym
7 when :password 7 when :password
8 _('Password') 8 _('Password')
9 when :password_confirmation 9 when :password_confirmation
10 _('Password Confirmation') 10 _('Password Confirmation')
11 else 11 else
12 - _(self.superclass.human_attribute_name(attrib)) 12 + _(self.human_attribute_name_without_customization(attrib))
13 end 13 end
14 end 14 end
  15 + class << self
  16 + alias_method_chain :human_attribute_name, :customization
  17 + end
15 18
16 validates_presence_of :requestor 19 validates_presence_of :requestor
17 20
app/models/comment.rb
@@ -111,14 +111,17 @@ class Comment &lt; ActiveRecord::Base @@ -111,14 +111,17 @@ class Comment &lt; ActiveRecord::Base
111 include Noosfero::Plugin::HotSpot 111 include Noosfero::Plugin::HotSpot
112 112
113 include Spammable 113 include Spammable
  114 + include CacheCounterHelper
114 115
115 def after_spam! 116 def after_spam!
116 SpammerLogger.log(ip_address, self) 117 SpammerLogger.log(ip_address, self)
117 Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam)) 118 Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam))
  119 + update_cache_counter(:spam_comments_count, source, 1) if source.kind_of?(Article)
118 end 120 end
119 121
120 def after_ham! 122 def after_ham!
121 Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham)) 123 Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham))
  124 + update_cache_counter(:spam_comments_count, source, -1) if source.kind_of?(Article)
122 end 125 end
123 126
124 def verify_and_notify 127 def verify_and_notify
app/models/community.rb
1 class Community < Organization 1 class Community < Organization
2 2
3 - attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type 3 + attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type, :address_reference, :district, :tag_list, :language
4 after_destroy :check_invite_member_for_destroy 4 after_destroy :check_invite_member_for_destroy
5 5
6 def self.type_name 6 def self.type_name
@@ -50,16 +50,6 @@ class Community &lt; Organization @@ -50,16 +50,6 @@ class Community &lt; Organization
50 super + FIELDS 50 super + FIELDS
51 end 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 def active_fields 53 def active_fields
64 environment ? environment.active_community_fields : [] 54 environment ? environment.active_community_fields : []
65 end 55 end
@@ -85,10 +75,6 @@ class Community &lt; Organization @@ -85,10 +75,6 @@ class Community &lt; Organization
85 recent_documents(limit, ["articles.type != ? AND articles.highlighted = ?", 'Folder', highlight]) 75 recent_documents(limit, ["articles.type != ? AND articles.highlighted = ?", 'Folder', highlight])
86 end 76 end
87 77
88 - def blocks_to_expire_cache  
89 - [MembersBlock]  
90 - end  
91 -  
92 def each_member(offset=0) 78 def each_member(offset=0)
93 while member = self.members.first(:order => :id, :offset => offset) 79 while member = self.members.first(:order => :id, :offset => offset)
94 yield member 80 yield member
app/models/domain.rb
@@ -2,7 +2,7 @@ require &#39;noosfero/multi_tenancy&#39; @@ -2,7 +2,7 @@ require &#39;noosfero/multi_tenancy&#39;
2 2
3 class Domain < ActiveRecord::Base 3 class Domain < ActiveRecord::Base
4 4
5 - attr_accessible :name, :owner 5 + attr_accessible :name, :owner, :is_default
6 6
7 # relationships 7 # relationships
8 ############### 8 ###############
app/models/enterprise.rb
@@ -2,6 +2,8 @@ @@ -2,6 +2,8 @@
2 # only enterprises can offer products and services. 2 # only enterprises can offer products and services.
3 class Enterprise < Organization 3 class Enterprise < Organization
4 4
  5 + attr_accessible :business_name, :address_reference, :district, :tag_list, :organization_website, :historic_and_current_context, :activities_short_description, :products_per_catalog_page
  6 +
5 SEARCH_DISPLAYS += %w[map full] 7 SEARCH_DISPLAYS += %w[map full]
6 8
7 def self.type_name 9 def self.type_name
@@ -23,7 +25,10 @@ class Enterprise &lt; Organization @@ -23,7 +25,10 @@ class Enterprise &lt; Organization
23 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code') 25 N_('Organization website'); N_('Historic and current context'); N_('Activities short description'); N_('City'); N_('State'); N_('Country'); N_('ZIP code')
24 26
25 settings_items :organization_website, :historic_and_current_context, :activities_short_description 27 settings_items :organization_website, :historic_and_current_context, :activities_short_description
  28 +
26 settings_items :products_per_catalog_page, :type => :integer, :default => 6 29 settings_items :products_per_catalog_page, :type => :integer, :default => 6
  30 + alias_method :products_per_catalog_page_before_type_cast, :products_per_catalog_page
  31 + validates_numericality_of :products_per_catalog_page, :allow_nil => true, :greater_than => 0
27 32
28 extend SetProfileRegionFromCityState::ClassMethods 33 extend SetProfileRegionFromCityState::ClassMethods
29 set_profile_region_from_city_state 34 set_profile_region_from_city_state
@@ -54,16 +59,6 @@ class Enterprise &lt; Organization @@ -54,16 +59,6 @@ class Enterprise &lt; Organization
54 super + FIELDS 59 super + FIELDS
55 end 60 end
56 61
57 - validate :presence_of_required_fieds  
58 -  
59 - def presence_of_required_fieds  
60 - self.required_fields.each do |field|  
61 - if self.send(field).blank?  
62 - self.errors.add_on_blank(field)  
63 - end  
64 - end  
65 - end  
66 -  
67 def active_fields 62 def active_fields
68 environment ? environment.active_enterprise_fields : [] 63 environment ? environment.active_enterprise_fields : []
69 end 64 end
app/models/environment.rb
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 # domains. 3 # domains.
4 class Environment < ActiveRecord::Base 4 class Environment < ActiveRecord::Base
5 5
6 - attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound 6 + attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body, :members_whitelist_enabled, :members_whitelist
7 7
8 has_many :users 8 has_many :users
9 9
@@ -124,6 +124,7 @@ class Environment &lt; ActiveRecord::Base @@ -124,6 +124,7 @@ class Environment &lt; ActiveRecord::Base
124 'organizations_are_moderated_by_default' => _("Organizations have moderated publication by default"), 124 'organizations_are_moderated_by_default' => _("Organizations have moderated publication by default"),
125 'enable_organization_url_change' => _("Allow organizations to change their URL"), 125 'enable_organization_url_change' => _("Allow organizations to change their URL"),
126 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"), 126 'admin_must_approve_new_communities' => _("Admin must approve creation of communities"),
  127 + 'admin_must_approve_new_users' => _("Admin must approve registration of new users"),
127 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'), 128 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'),
128 'xmpp_chat' => _('XMPP/Jabber based chat'), 129 'xmpp_chat' => _('XMPP/Jabber based chat'),
129 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'), 130 'show_zoom_button_on_article_images' => _('Show a zoom link on all article images'),
@@ -132,7 +133,8 @@ class Environment &lt; ActiveRecord::Base @@ -132,7 +133,8 @@ class Environment &lt; ActiveRecord::Base
132 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'), 133 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'),
133 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'), 134 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'),
134 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage'), 135 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage'),
135 - 'display_my_enterprises_on_user_menu' => _('Display on menu the list of enterprises the user can manage') 136 + 'display_my_enterprises_on_user_menu' => _('Display on menu the list of enterprises the user can manage'),
  137 + 'restrict_to_members' => _('Show content only to members')
136 } 138 }
137 end 139 end
138 140
@@ -175,14 +177,10 @@ class Environment &lt; ActiveRecord::Base @@ -175,14 +177,10 @@ class Environment &lt; ActiveRecord::Base
175 177
176 # "left" area 178 # "left" area
177 env.boxes[1].blocks << LoginBlock.new 179 env.boxes[1].blocks << LoginBlock.new
178 - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
179 - # the Noosfero core soon, see ActionItem3045  
180 - env.boxes[1].blocks << EnvironmentStatisticsBlock.new  
181 env.boxes[1].blocks << RecentDocumentsBlock.new 180 env.boxes[1].blocks << RecentDocumentsBlock.new
182 181
183 # "right" area 182 # "right" area
184 env.boxes[2].blocks << CommunitiesBlock.new(:limit => 6) 183 env.boxes[2].blocks << CommunitiesBlock.new(:limit => 6)
185 - env.boxes[2].blocks << PeopleBlock.new(:limit => 6)  
186 end 184 end
187 185
188 # One Environment can be reached by many domains 186 # One Environment can be reached by many domains
@@ -287,7 +285,7 @@ class Environment &lt; ActiveRecord::Base @@ -287,7 +285,7 @@ class Environment &lt; ActiveRecord::Base
287 www.youtube.com 285 www.youtube.com
288 ] + ('a' .. 'z').map{|i| "#{i}.yimg.com"} 286 ] + ('a' .. 'z').map{|i| "#{i}.yimg.com"}
289 287
290 - settings_items :enabled_plugins, :type => Array, :default => [] 288 + settings_items :enabled_plugins, :type => Array, :default => Noosfero::Plugin.available_plugin_names
291 289
292 settings_items :search_hints, :type => Hash, :default => {} 290 settings_items :search_hints, :type => Hash, :default => {}
293 291
@@ -298,6 +296,23 @@ class Environment &lt; ActiveRecord::Base @@ -298,6 +296,23 @@ class Environment &lt; ActiveRecord::Base
298 settings_items :access_control_allow_origin, :type => Array, :default => [] 296 settings_items :access_control_allow_origin, :type => Array, :default => []
299 settings_items :access_control_allow_methods, :type => String 297 settings_items :access_control_allow_methods, :type => String
300 298
  299 + settings_items :signup_welcome_screen_body, :type => String
  300 +
  301 + def has_custom_welcome_screen?
  302 + settings[:signup_welcome_screen_body].present?
  303 + end
  304 +
  305 + settings_items :members_whitelist_enabled, :type => :boolean, :default => false
  306 + settings_items :members_whitelist, :type => Array, :default => []
  307 +
  308 + def in_whitelist?(person)
  309 + !members_whitelist_enabled || members_whitelist.include?(person.id)
  310 + end
  311 +
  312 + def members_whitelist=(members)
  313 + settings[:members_whitelist] = members.split(',').map(&:to_i)
  314 + end
  315 +
301 def news_amount_by_folder=(amount) 316 def news_amount_by_folder=(amount)
302 settings[:news_amount_by_folder] = amount.to_i 317 settings[:news_amount_by_folder] = amount.to_i
303 end 318 end
@@ -637,10 +652,15 @@ class Environment &lt; ActiveRecord::Base @@ -637,10 +652,15 @@ class Environment &lt; ActiveRecord::Base
637 domain 652 domain
638 end 653 end
639 654
  655 + def admin_url
  656 + { :controller => 'admin_panel', :action => 'index' }
  657 + end
  658 +
640 def top_url 659 def top_url
641 url = 'http://' 660 url = 'http://'
642 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname) 661 url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname)
643 url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port) 662 url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port)
  663 + url << Noosfero.root('')
644 url 664 url
645 end 665 end
646 666
@@ -785,7 +805,7 @@ class Environment &lt; ActiveRecord::Base @@ -785,7 +805,7 @@ class Environment &lt; ActiveRecord::Base
785 end 805 end
786 806
787 def notification_emails 807 def notification_emails
788 - [noreply_email.blank? ? nil : noreply_email].compact + admins.map(&:email) 808 + [contact_email].select(&:present?) + admins.map(&:email)
789 end 809 end
790 810
791 after_create :create_templates 811 after_create :create_templates
app/models/environment_statistics_block.rb
@@ -1,33 +0,0 @@ @@ -1,33 +0,0 @@
1 -# TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
2 -# the Noosfero core soon, see ActionItem3045  
3 -  
4 -class EnvironmentStatisticsBlock < Block  
5 -  
6 - def self.description  
7 - _('Environment stastistics (DEPRECATED)')  
8 - end  
9 -  
10 - def default_title  
11 - _('Statistics for %s') % owner.name  
12 - end  
13 -  
14 - def help  
15 - _('This block presents some statistics about your environment.')  
16 - end  
17 -  
18 - def content(args={})  
19 - users = owner.people.visible.count  
20 - enterprises = owner.enterprises.visible.count  
21 - communities = owner.communities.visible.count  
22 -  
23 - info = []  
24 - info << (n_('One user', '%{num} users', users) % { :num => users })  
25 - unless owner.enabled?('disable_asset_enterprises')  
26 - info << (n_('One enterprise', '%{num} enterprises', enterprises) % { :num => enterprises })  
27 - end  
28 - info << (n_('One community', '%{num} communities', communities) % { :num => communities })  
29 -  
30 - block_title(title) + content_tag('ul', info.map {|item| content_tag('li', item) }.join("\n"))  
31 - end  
32 -  
33 -end  
app/models/external_feed.rb
@@ -13,6 +13,7 @@ class ExternalFeed &lt; ActiveRecord::Base @@ -13,6 +13,7 @@ class ExternalFeed &lt; ActiveRecord::Base
13 attr_accessible :address, :enabled 13 attr_accessible :address, :enabled
14 14
15 def add_item(title, link, date, content) 15 def add_item(title, link, date, content)
  16 + return if content.blank?
16 doc = Hpricot(content) 17 doc = Hpricot(content)
17 doc.search('*').each do |p| 18 doc.search('*').each do |p|
18 if p.instance_of? Hpricot::Elem 19 if p.instance_of? Hpricot::Elem
@@ -30,6 +31,7 @@ class ExternalFeed &lt; ActiveRecord::Base @@ -30,6 +31,7 @@ class ExternalFeed &lt; ActiveRecord::Base
30 article.source = link 31 article.source = link
31 article.profile = blog.profile 32 article.profile = blog.profile
32 article.parent = blog 33 article.parent = blog
  34 + article.author_name = self.feed_title
33 unless blog.children.exists?(:slug => article.slug) 35 unless blog.children.exists?(:slug => article.slug)
34 article.save! 36 article.save!
35 article.delay.create_activity 37 article.delay.create_activity
app/models/featured_products_block.rb
1 class FeaturedProductsBlock < Block 1 class FeaturedProductsBlock < Block
2 2
  3 + attr_accessible :product_ids, :groups_of, :speed, :reflect
  4 +
3 settings_items :product_ids, :type => Array, :default => [] 5 settings_items :product_ids, :type => Array, :default => []
4 settings_items :groups_of, :type => :integer, :default => 3 6 settings_items :groups_of, :type => :integer, :default => 3
5 settings_items :speed, :type => :integer, :default => 1000 7 settings_items :speed, :type => :integer, :default => 1000
app/models/feed_reader_block.rb
@@ -85,8 +85,4 @@ class FeedReaderBlock &lt; Block @@ -85,8 +85,4 @@ class FeedReaderBlock &lt; Block
85 block_title(title) + formatted_feed_content 85 block_title(title) + formatted_feed_content
86 end 86 end
87 87
88 - def editable?  
89 - true  
90 - end  
91 -  
92 end 88 end
app/models/forum.rb
@@ -3,7 +3,7 @@ class Forum &lt; Folder @@ -3,7 +3,7 @@ class Forum &lt; Folder
3 acts_as_having_posts :order => 'updated_at DESC' 3 acts_as_having_posts :order => 'updated_at DESC'
4 include PostsLimit 4 include PostsLimit
5 5
6 - attr_accessible :has_terms_of_use, :terms_of_use 6 + attr_accessible :has_terms_of_use, :terms_of_use, :allows_members_to_create_topics
7 7
8 settings_items :terms_of_use, :type => :string, :default => "" 8 settings_items :terms_of_use, :type => :string, :default => ""
9 settings_items :has_terms_of_use, :type => :boolean, :default => false 9 settings_items :has_terms_of_use, :type => :boolean, :default => false
app/models/friends_block.rb
@@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
1 -class FriendsBlock < ProfileListBlock  
2 -  
3 - def self.description  
4 - _('Friends')  
5 - end  
6 -  
7 - def default_title  
8 - n_('{#} friend', '{#} friends', profile_count)  
9 - end  
10 -  
11 - def help  
12 - _('This block displays your friends.')  
13 - end  
14 -  
15 - def footer  
16 - owner_id = owner.identifier  
17 - proc do  
18 - link_to s_('friends|View all'), :profile => owner_id, :controller => 'profile', :action => 'friends'  
19 - end  
20 - end  
21 -  
22 - def profiles  
23 - owner.friends  
24 - end  
25 -  
26 -end  
app/models/friendship.rb
@@ -15,4 +15,9 @@ class Friendship &lt; ActiveRecord::Base @@ -15,4 +15,9 @@ class Friendship &lt; ActiveRecord::Base
15 Friendship.update_cache_counter(:friends_count, friendship.person, -1) 15 Friendship.update_cache_counter(:friends_count, friendship.person, -1)
16 Friendship.update_cache_counter(:friends_count, friendship.friend, -1) 16 Friendship.update_cache_counter(:friends_count, friendship.friend, -1)
17 end 17 end
  18 +
  19 + def self.remove_friendship(person1, person2)
  20 + person1.remove_friend(person2)
  21 + person2.remove_friend(person1)
  22 + end
18 end 23 end
app/models/highlights_block.rb
1 class HighlightsBlock < Block 1 class HighlightsBlock < Block
2 2
3 - attr_accessible :images 3 + attr_accessible :images, :interval, :shuffle, :navigation
4 4
5 settings_items :images, :type => Array, :default => [] 5 settings_items :images, :type => Array, :default => []
6 settings_items :interval, :type => 'integer', :default => 4 6 settings_items :interval, :type => 'integer', :default => 4
app/models/image.rb
@@ -25,4 +25,7 @@ class Image &lt; ActiveRecord::Base @@ -25,4 +25,7 @@ class Image &lt; ActiveRecord::Base
25 25
26 attr_accessible :uploaded_data 26 attr_accessible :uploaded_data
27 27
  28 + def current_data
  29 + File.file?(full_filename) ? File.read(full_filename) : nil
  30 + end
28 end 31 end
app/models/input.rb
1 class Input < ActiveRecord::Base 1 class Input < ActiveRecord::Base
2 2
3 - attr_accessible :product, :product_category 3 + attr_accessible :product, :product_category, :product_category_id, :amount_used, :unit_id, :price_per_unit, :relevant_to_price
4 4
5 belongs_to :product 5 belongs_to :product
6 belongs_to :product_category 6 belongs_to :product_category
app/models/link_list_block.rb
@@ -78,16 +78,17 @@ class LinkListBlock &lt; Block @@ -78,16 +78,17 @@ class LinkListBlock &lt; Block
78 address 78 address
79 end 79 end
80 if add !~ /^[a-z]+:\/\// && add !~ /^\// 80 if add !~ /^[a-z]+:\/\// && add !~ /^\//
81 - 'http://' + add 81 + '//' + add
82 else 82 else
  83 + if root = Noosfero.root
  84 + if !add.starts_with?(root)
  85 + add = root + add
  86 + end
  87 + end
83 add 88 add
84 end 89 end
85 end 90 end
86 91
87 - def editable?  
88 - true  
89 - end  
90 -  
91 def icons_options 92 def icons_options
92 ICONS.map do |i| 93 ICONS.map do |i|
93 "<span title=\"#{i[1]}\" class=\"icon-#{i[0]}\" onclick=\"changeIcon(this, '#{i[0]}')\"></span>".html_safe 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,4 +101,5 @@ class LinkListBlock &lt; Block
100 sanitizer = HTML::WhiteListSanitizer.new 101 sanitizer = HTML::WhiteListSanitizer.new
101 sanitizer.sanitize(text) 102 sanitizer.sanitize(text)
102 end 103 end
  104 +
103 end 105 end
app/models/location_block.rb
1 class LocationBlock < Block 1 class LocationBlock < Block
2 2
  3 + attr_accessible :zoom, :map_type
  4 +
3 settings_items :zoom, :type => :integer, :default => 4 5 settings_items :zoom, :type => :integer, :default => 4
4 settings_items :map_type, :type => :string, :default => 'roadmap' 6 settings_items :map_type, :type => :string, :default => 'roadmap'
5 7
app/models/main_block.rb
@@ -16,10 +16,6 @@ class MainBlock &lt; Block @@ -16,10 +16,6 @@ class MainBlock &lt; Block
16 true 16 true
17 end 17 end
18 18
19 - def editable?  
20 - true  
21 - end  
22 -  
23 def cacheable? 19 def cacheable?
24 false 20 false
25 end 21 end
app/models/members_block.rb
@@ -1,52 +0,0 @@ @@ -1,52 +0,0 @@
1 -class MembersBlock < ProfileListBlock  
2 - settings_items :show_join_leave_button, :type => :boolean, :default => false  
3 -  
4 - attr_accessible :show_join_leave_button  
5 -  
6 - def self.description  
7 - _('Members')  
8 - end  
9 -  
10 - def default_title  
11 - _('{#} members')  
12 - end  
13 -  
14 - def help  
15 - _('This block presents the members of a collective.')  
16 - end  
17 -  
18 - def footer  
19 - profile = self.owner  
20 - s = show_join_leave_button  
21 -  
22 - proc do  
23 - render :file => 'blocks/members', :locals => { :profile => profile, :show_join_leave_button => s}  
24 - end  
25 - end  
26 -  
27 - def profiles  
28 - owner.members  
29 - end  
30 -  
31 - def extra_option  
32 - data = {  
33 - :human_name => _("Show join leave button"),  
34 - :name => 'block[show_join_leave_button]',  
35 - :value => true,  
36 - :checked => show_join_leave_button,  
37 - :options => {}  
38 - }  
39 - end  
40 -  
41 - def cache_key(language='en', user=nil)  
42 - logged = ''  
43 - if user  
44 - logged += '-logged-in'  
45 - if user.is_member_of? self.owner  
46 - logged += '-member'  
47 - end  
48 - end  
49 - super + logged  
50 - end  
51 -  
52 -end  
app/models/moderate_user_registration.rb 0 → 100644
@@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
  1 +class ModerateUserRegistration < Task
  2 +
  3 + settings_items :user_id, :type => String
  4 + settings_items :name, :type => String
  5 + settings_items :author_name, :type => String
  6 + settings_items :email, :type => String
  7 +
  8 + after_create :schedule_spam_checking
  9 +
  10 + alias :environment :target
  11 + alias :environment= :target=
  12 +
  13 + def schedule_spam_checking
  14 + self.delay.check_for_spam
  15 + end
  16 +
  17 + include Noosfero::Plugin::HotSpot
  18 +
  19 + def sender
  20 + "#{name} (#{email})"
  21 + end
  22 +
  23 + def perform
  24 + user=environment.users.find_by_id(user_id)
  25 + user.activate
  26 + end
  27 +
  28 + def title
  29 + _("New user")
  30 + end
  31 +
  32 + def subject
  33 + name
  34 + end
  35 +
  36 + def information
  37 + { :message => _('%{sender} wants to register.'),
  38 + :variables => {:sender => sender} }
  39 + end
  40 +
  41 + def icon
  42 + result = {:type => :defined_image, :src => '/images/icons-app/person-minor.png', :name => name}
  43 + end
  44 +
  45 + def target_notification_description
  46 + _('%{sender} tried to register.') %
  47 + {:sender => sender}
  48 + end
  49 +
  50 + def target_notification_message
  51 + target_notification_description + "\n\n" +
  52 + _('You need to login on %{system} in order to approve or reject this user.') % { :environment => self.environment }
  53 + end
  54 +
  55 + def target_notification_message
  56 + _("User \"%{user}\" just requested to register. You have to approve or reject it through the \"Pending Validations\" section in your control panel.\n") % { :user => self.name }
  57 + end
  58 +
  59 +end
0 \ No newline at end of file 60 \ No newline at end of file
app/models/organization.rb
@@ -30,6 +30,16 @@ class Organization &lt; Profile @@ -30,6 +30,16 @@ class Organization &lt; Profile
30 30
31 scope :more_popular, :order => 'members_count DESC' 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 def validation_methodology 43 def validation_methodology
34 self.validation_info ? self.validation_info.validation_methodology : nil 44 self.validation_info ? self.validation_info.validation_methodology : nil
35 end 45 end
@@ -123,7 +133,7 @@ class Organization &lt; Profile @@ -123,7 +133,7 @@ class Organization &lt; Profile
123 [ 133 [
124 [MainBlock.new], 134 [MainBlock.new],
125 [ProfileImageBlock.new, LinkListBlock.new(:links => links)], 135 [ProfileImageBlock.new, LinkListBlock.new(:links => links)],
126 - [MembersBlock.new, RecentDocumentsBlock.new] 136 + [RecentDocumentsBlock.new]
127 ] 137 ]
128 end 138 end
129 139
@@ -135,7 +145,11 @@ class Organization &lt; Profile @@ -135,7 +145,11 @@ class Organization &lt; Profile
135 end 145 end
136 146
137 def notification_emails 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 end 153 end
140 154
141 def already_request_membership?(person) 155 def already_request_membership?(person)
app/models/people_block.rb
@@ -1,25 +0,0 @@ @@ -1,25 +0,0 @@
1 -class PeopleBlock < ProfileListBlock  
2 -  
3 - def default_title  
4 - _('People')  
5 - end  
6 -  
7 - def help  
8 - _('Clicking a person takes you to his/her homepage')  
9 - end  
10 -  
11 - def self.description  
12 - _('Random people')  
13 - end  
14 -  
15 - def profiles  
16 - owner.people  
17 - end  
18 -  
19 - def footer  
20 - lambda do |context|  
21 - link_to _('View all'), :controller => 'search', :action => 'people'  
22 - end  
23 - end  
24 -  
25 -end  
app/models/person.rb
1 # A person is the profile of an user holding all relationships with the rest of the system 1 # A person is the profile of an user holding all relationships with the rest of the system
2 class Person < Profile 2 class Person < Profile
3 3
4 - attr_accessible :organization, :contact_information, :sex, :birth_date 4 + attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website
5 5
6 SEARCH_FILTERS += %w[ 6 SEARCH_FILTERS += %w[
7 more_popular 7 more_popular
@@ -161,7 +161,7 @@ class Person &lt; Profile @@ -161,7 +161,7 @@ class Person &lt; Profile
161 FIELDS 161 FIELDS
162 end 162 end
163 163
164 - validate :presence_of_required_fields 164 + validate :presence_of_required_fields, :unless => :is_template
165 165
166 def presence_of_required_fields 166 def presence_of_required_fields
167 self.required_fields.each do |field| 167 self.required_fields.each do |field|
@@ -269,7 +269,7 @@ class Person &lt; Profile @@ -269,7 +269,7 @@ class Person &lt; Profile
269 [ 269 [
270 [MainBlock.new], 270 [MainBlock.new],
271 [ProfileImageBlock.new(:show_name => true), LinkListBlock.new(:links => links), RecentDocumentsBlock.new], 271 [ProfileImageBlock.new(:show_name => true), LinkListBlock.new(:links => links), RecentDocumentsBlock.new],
272 - [FriendsBlock.new, CommunitiesBlock.new] 272 + [CommunitiesBlock.new]
273 ] 273 ]
274 end 274 end
275 275
app/models/person_notifier.rb
@@ -82,7 +82,7 @@ class PersonNotifier @@ -82,7 +82,7 @@ class PersonNotifier
82 @url = @profile.environment.top_url 82 @url = @profile.environment.top_url
83 mail( 83 mail(
84 content_type: "text/html", 84 content_type: "text/html",
85 - from: "#{@profile.environment.name} <#{@profile.environment.contact_email}>", 85 + from: "#{@profile.environment.name} <#{@profile.environment.noreply_email}>",
86 to: @profile.email, 86 to: @profile.email,
87 subject: _("[%s] Network Activity") % [@profile.environment.name] 87 subject: _("[%s] Network Activity") % [@profile.environment.name]
88 ) 88 )
app/models/product.rb
@@ -11,7 +11,7 @@ class Product &lt; ActiveRecord::Base @@ -11,7 +11,7 @@ class Product &lt; ActiveRecord::Base
11 11
12 SEARCH_DISPLAYS = %w[map full] 12 SEARCH_DISPLAYS = %w[map full]
13 13
14 - attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers 14 + attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs
15 15
16 def self.default_search_display 16 def self.default_search_display
17 'full' 17 'full'
app/models/product_categories_block.rb
@@ -17,7 +17,7 @@ class ProductCategoriesBlock &lt; Block @@ -17,7 +17,7 @@ class ProductCategoriesBlock &lt; Block
17 profile = owner 17 profile = owner
18 proc do 18 proc do
19 if @categories.nil? or @categories.length == 0 19 if @categories.nil? or @categories.length == 0
20 - categories = ProductCategory.on_level().order(:name) 20 + categories = ProductCategory.on_level(nil).order(:name)
21 if @categories and @categories.length == 0 21 if @categories and @categories.length == 0
22 notice = _('There are no sub-categories for %s') % @category.name 22 notice = _('There are no sub-categories for %s') % @category.name
23 end 23 end
@@ -33,7 +33,7 @@ class ProductCategoriesBlock &lt; Block @@ -33,7 +33,7 @@ class ProductCategoriesBlock &lt; Block
33 end 33 end
34 end 34 end
35 35
36 - DISPLAY_OPTIONS['catalog_only'] = _('Only on the catalog') 36 + DISPLAY_OPTIONS = DISPLAY_OPTIONS.merge('catalog_only' => _('Only on the catalog'))
37 37
38 def display 38 def display
39 settings[:display].nil? ? 'catalog_only' : super 39 settings[:display].nil? ? 'catalog_only' : super
app/models/products_block.rb
@@ -49,17 +49,10 @@ class ProductsBlock &lt; Block @@ -49,17 +49,10 @@ class ProductsBlock &lt; Block
49 49
50 def products(reload = false) 50 def products(reload = false)
51 if product_ids.blank? 51 if product_ids.blank?
52 - products_list = owner.products(reload)  
53 - result = []  
54 - [4, products_list.size].min.times do  
55 - p = products_list.sample  
56 - result << p  
57 - products_list -= [p]  
58 - end  
59 - result 52 + owner.products.order('RANDOM()').limit([4,owner.products.count].min)
60 else 53 else
61 - product_ids.map {|item| owner.products.find(item) }  
62 - end 54 + owner.products.where(:id => product_ids)
  55 + end.compact
63 end 56 end
64 57
65 end 58 end
app/models/profile.rb
@@ -3,7 +3,7 @@ @@ -3,7 +3,7 @@
3 # which by default is the one returned by Environment:default. 3 # which by default is the one returned by Environment:default.
4 class Profile < ActiveRecord::Base 4 class Profile < ActiveRecord::Base
5 5
6 - attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time 6 + attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, :redirection_after_login
7 7
8 # use for internationalizable human type names in search facets 8 # use for internationalizable human type names in search facets
9 # reimplement on subclasses 9 # reimplement on subclasses
@@ -346,16 +346,17 @@ class Profile &lt; ActiveRecord::Base @@ -346,16 +346,17 @@ class Profile &lt; ActiveRecord::Base
346 end 346 end
347 347
348 def copy_blocks_from(profile) 348 def copy_blocks_from(profile)
  349 + template_boxes = profile.boxes.select{|box| box.position}
349 self.boxes.destroy_all 350 self.boxes.destroy_all
350 - profile.boxes.each do |box|  
351 - new_box = Box.new 351 + self.boxes = template_boxes.size.times.map { Box.new }
  352 +
  353 + template_boxes.each_with_index do |box, i|
  354 + new_box = self.boxes[i]
352 new_box.position = box.position 355 new_box.position = box.position
353 - self.boxes << new_box  
354 box.blocks.each do |block| 356 box.blocks.each do |block|
355 new_block = block.class.new(:title => block[:title]) 357 new_block = block.class.new(:title => block[:title])
356 - new_block.settings = block.settings  
357 - new_block.position = block.position  
358 - self.boxes[-1].blocks << new_block 358 + new_block.copy_from(block)
  359 + new_box.blocks << new_block
359 end 360 end
360 end 361 end
361 end 362 end
app/models/profile_image_block.rb
@@ -23,10 +23,6 @@ class ProfileImageBlock &lt; Block @@ -23,10 +23,6 @@ class ProfileImageBlock &lt; Block
23 end 23 end
24 end 24 end
25 25
26 - def editable?  
27 - true  
28 - end  
29 -  
30 def cacheable? 26 def cacheable?
31 false 27 false
32 end 28 end
app/models/profile_info_block.rb
@@ -15,10 +15,6 @@ class ProfileInfoBlock &lt; Block @@ -15,10 +15,6 @@ class ProfileInfoBlock &lt; Block
15 end 15 end
16 end 16 end
17 17
18 - def editable?  
19 - false  
20 - end  
21 -  
22 def cacheable? 18 def cacheable?
23 false 19 false
24 end 20 end
app/models/profile_list_block.rb
1 class ProfileListBlock < Block 1 class ProfileListBlock < Block
2 2
3 - attr_accessible :limit, :prioritize_profiles_with_image 3 + attr_accessible :prioritize_profiles_with_image
4 4
5 settings_items :limit, :type => :integer, :default => 6 5 settings_items :limit, :type => :integer, :default => 6
6 settings_items :prioritize_profiles_with_image, :type => :boolean, :default => true 6 settings_items :prioritize_profiles_with_image, :type => :boolean, :default => true
@@ -18,13 +18,13 @@ class ProfileListBlock &lt; Block @@ -18,13 +18,13 @@ class ProfileListBlock &lt; Block
18 result = nil 18 result = nil
19 visible_profiles = profiles.visible.includes([:image,:domains,:preferred_domain,:environment]) 19 visible_profiles = profiles.visible.includes([:image,:domains,:preferred_domain,:environment])
20 if !prioritize_profiles_with_image 20 if !prioritize_profiles_with_image
21 - result = visible_profiles.all(:limit => limit, :order => 'updated_at DESC').sort_by{ rand }  
22 - elsif profiles.visible.with_image.count >= limit  
23 - result = visible_profiles.with_image.all(:limit => limit * 5, :order => 'updated_at DESC').sort_by{ rand } 21 + result = visible_profiles.all(:limit => get_limit, :order => 'profiles.updated_at DESC').sort_by{ rand }
  22 + elsif profiles.visible.with_image.count >= get_limit
  23 + result = visible_profiles.with_image.all(:limit => get_limit * 5, :order => 'profiles.updated_at DESC').sort_by{ rand }
24 else 24 else
25 - result = visible_profiles.with_image.sort_by{ rand } + visible_profiles.without_image.all(:limit => limit * 5, :order => 'profiles.updated_at DESC').sort_by{ rand } 25 + result = visible_profiles.with_image.sort_by{ rand } + visible_profiles.without_image.all(:limit => get_limit * 5, :order => 'profiles.updated_at DESC').sort_by{ rand }
26 end 26 end
27 - result.slice(0..limit-1) 27 + result.slice(0..get_limit-1)
28 end 28 end
29 29
30 def profile_count 30 def profile_count
app/models/profile_search_block.rb
@@ -11,8 +11,4 @@ class ProfileSearchBlock &lt; Block @@ -11,8 +11,4 @@ class ProfileSearchBlock &lt; Block
11 end 11 end
12 end 12 end
13 13
14 - def editable?  
15 - true  
16 - end  
17 -  
18 end 14 end
app/models/recent_documents_block.rb
@@ -33,7 +33,7 @@ class RecentDocumentsBlock &lt; Block @@ -33,7 +33,7 @@ class RecentDocumentsBlock &lt; Block
33 end 33 end
34 34
35 def docs 35 def docs
36 - self.limit.nil? ? owner.recent_documents(nil, {}, false) : owner.recent_documents(self.limit, {}, false) 36 + self.limit.nil? ? owner.recent_documents(nil, {}, false) : owner.recent_documents(self.get_limit, {}, false)
37 end 37 end
38 38
39 def self.expire_on 39 def self.expire_on
app/models/rss_feed.rb
1 class RssFeed < Article 1 class RssFeed < Article
2 2
3 - attr_accessible :limit, :enabled, :language, :include 3 + attr_accessible :limit, :enabled, :language, :include, :feed_item_description
4 4
5 def self.type_name 5 def self.type_name
6 _('RssFeed') 6 _('RssFeed')
app/models/slideshow_block.rb
@@ -6,6 +6,8 @@ class SlideshowBlock &lt; Block @@ -6,6 +6,8 @@ class SlideshowBlock &lt; Block
6 settings_items :navigation, :type => 'boolean', :default => false 6 settings_items :navigation, :type => 'boolean', :default => false
7 settings_items :image_size, :type => 'string', :default => 'thumb' 7 settings_items :image_size, :type => 'string', :default => 'thumb'
8 8
  9 + attr_accessible :gallery_id, :image_size, :interval, :shuffle, :navigation
  10 +
9 def self.description 11 def self.description
10 _('Slideshow') 12 _('Slideshow')
11 end 13 end
app/models/task.rb
@@ -73,10 +73,6 @@ class Task &lt; ActiveRecord::Base @@ -73,10 +73,6 @@ class Task &lt; ActiveRecord::Base
73 end 73 end
74 end 74 end
75 75
76 - def self.all_types  
77 - %w[Invitation EnterpriseActivation AddMember Ticket SuggestArticle AddFriend CreateCommunity AbuseComplaint ApproveComment ApproveArticle CreateEnterprise ChangePassword EmailActivation InviteFriend InviteMember]  
78 - end  
79 -  
80 # this method finished the task. It calls #perform, which must be overriden 76 # this method finished the task. It calls #perform, which must be overriden
81 # by subclasses. At the end a message (as returned by #finish_message) is 77 # by subclasses. At the end a message (as returned by #finish_message) is
82 # sent to the requestor with #notify_requestor. 78 # sent to the requestor with #notify_requestor.
@@ -254,6 +250,10 @@ class Task &lt; ActiveRecord::Base @@ -254,6 +250,10 @@ class Task &lt; ActiveRecord::Base
254 { :conditions => [environment_condition, profile_condition].compact.join(' OR ') } 250 { :conditions => [environment_condition, profile_condition].compact.join(' OR ') }
255 } 251 }
256 252
  253 + def self.pending_types_for(profile)
  254 + Task.to(profile).pending.select('distinct type').map { |t| [t.class.name, t.title] }
  255 + end
  256 +
257 def opened? 257 def opened?
258 status == Task::Status::ACTIVE || status == Task::Status::HIDDEN 258 status == Task::Status::ACTIVE || status == Task::Status::HIDDEN
259 end 259 end
app/models/user.rb
@@ -5,7 +5,7 @@ require &#39;user_activation_job&#39; @@ -5,7 +5,7 @@ require &#39;user_activation_job&#39;
5 # Rails generator. 5 # Rails generator.
6 class User < ActiveRecord::Base 6 class User < ActiveRecord::Base
7 7
8 - attr_accessible :login, :email, :password, :password_confirmation 8 + attr_accessible :login, :email, :password, :password_confirmation, :activated_at
9 9
10 N_('Password') 10 N_('Password')
11 N_('Password confirmation') 11 N_('Password confirmation')
@@ -16,15 +16,18 @@ class User &lt; ActiveRecord::Base @@ -16,15 +16,18 @@ class User &lt; ActiveRecord::Base
16 end 16 end
17 17
18 # FIXME ugly workaround 18 # FIXME ugly workaround
19 - def self.human_attribute_name(attrib, options={}) 19 + def self.human_attribute_name_with_customization(attrib, options={})
20 case attrib.to_sym 20 case attrib.to_sym
21 when :login 21 when :login
22 return [_('Username'), _('Email')].join(' / ') 22 return [_('Username'), _('Email')].join(' / ')
23 when :email 23 when :email
24 return _('e-Mail') 24 return _('e-Mail')
25 - else _(self.superclass.human_attribute_name(attrib)) 25 + else _(self.human_attribute_name_without_customization(attrib))
26 end 26 end
27 end 27 end
  28 + class << self
  29 + alias_method_chain :human_attribute_name, :customization
  30 + end
28 31
29 before_create do |user| 32 before_create do |user|
30 if user.environment.nil? 33 if user.environment.nil?
@@ -47,8 +50,12 @@ class User &lt; ActiveRecord::Base @@ -47,8 +50,12 @@ class User &lt; ActiveRecord::Base
47 50
48 user.person = p 51 user.person = p
49 end 52 end
50 - if user.environment.enabled?('skip_new_user_email_confirmation')  
51 - user.activate 53 + if user.environment.enabled?('skip_new_user_email_confirmation')
  54 + if user.environment.enabled?('admin_must_approve_new_users')
  55 + create_moderate_task
  56 + else
  57 + user.activate
  58 + end
52 end 59 end
53 end 60 end
54 after_create :deliver_activation_code 61 after_create :deliver_activation_code
@@ -63,43 +70,8 @@ class User &lt; ActiveRecord::Base @@ -63,43 +70,8 @@ class User &lt; ActiveRecord::Base
63 self.person.preferred_domain && self.person.preferred_domain.name || self.environment.default_hostname(true) 70 self.person.preferred_domain && self.person.preferred_domain.name || self.environment.default_hostname(true)
64 end 71 end
65 72
66 - class Mailer < ActionMailer::Base  
67 - def activation_email_notify(user)  
68 - user_email = "#{user.login}@#{user.email_domain}"  
69 - recipients user_email  
70 - from "#{user.environment.name} <#{user.environment.noreply_email}>"  
71 - subject _("[%{environment}] Welcome to %{environment} mail!") % { :environment => user.environment.name }  
72 - body :name => user.name,  
73 - :email => user_email,  
74 - :webmail => MailConf.webmail_url(user.login, user.email_domain),  
75 - :environment => user.environment.name,  
76 - :url => url_for(:host => user.environment.default_hostname, :controller => 'home')  
77 - end  
78 -  
79 - def activation_code(user)  
80 - recipients user.email  
81 -  
82 - from "#{user.environment.name} <#{user.environment.noreply_email}>"  
83 - subject _("[%s] Activate your account") % [user.environment.name]  
84 - body :recipient => user.name,  
85 - :activation_code => user.activation_code,  
86 - :environment => user.environment.name,  
87 - :url => user.environment.top_url,  
88 - :redirection => (true if user.return_to)  
89 - end  
90 -  
91 - def signup_welcome_email(user)  
92 - email_body = user.environment.signup_welcome_text_body.gsub('{user_name}', user.name)  
93 - email_subject = user.environment.signup_welcome_text_subject  
94 -  
95 - content_type 'text/html'  
96 - recipients user.email  
97 -  
98 - from "#{user.environment.name} <#{user.environment.noreply_email}>"  
99 - subject email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject  
100 - body email_body  
101 - end  
102 - end 73 + # virtual attribute used to stash which community to join on signup or login
  74 + attr_accessor :community_to_join
103 75
104 def signup! 76 def signup!
105 User.transaction do 77 User.transaction do
@@ -172,6 +144,15 @@ class User &lt; ActiveRecord::Base @@ -172,6 +144,15 @@ class User &lt; ActiveRecord::Base
172 end 144 end
173 end 145 end
174 146
  147 + def create_moderate_task
  148 + @task = ModerateUserRegistration.new
  149 + @task.user_id = self.id
  150 + @task.name = self.name
  151 + @task.email = self.email
  152 + @task.target = self.environment
  153 + @task.save
  154 + end
  155 +
175 def activated? 156 def activated?
176 self.activation_code.nil? && !self.activated_at.nil? 157 self.activation_code.nil? && !self.activated_at.nil?
177 end 158 end
app/presenters/image.rb
@@ -11,4 +11,9 @@ class FilePresenter::Image &lt; FilePresenter @@ -11,4 +11,9 @@ class FilePresenter::Image &lt; FilePresenter
11 def short_description 11 def short_description
12 _('Image (%s)') % content_type.split('/')[1].upcase 12 _('Image (%s)') % content_type.split('/')[1].upcase
13 end 13 end
  14 +
  15 + #Overwriting method from FilePresenter to allow download of images
  16 + def download?(view = nil)
  17 + view.blank? || view == 'false'
  18 + end
14 end 19 end
app/sweepers/friendship_sweeper.rb
@@ -34,8 +34,7 @@ protected @@ -34,8 +34,7 @@ protected
34 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s)) 34 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s))
35 end 35 end
36 36
37 - blocks = profile.blocks.select{|b| b.kind_of?(FriendsBlock)}  
38 - BlockSweeper.expire_blocks(blocks) 37 + expire_blocks_cache(profile, [:profile])
39 end 38 end
40 39
41 end 40 end
app/sweepers/profile_sweeper.rb
@@ -8,9 +8,6 @@ class ProfileSweeper # &lt; ActiveRecord::Observer @@ -8,9 +8,6 @@ class ProfileSweeper # &lt; ActiveRecord::Observer
8 end 8 end
9 9
10 def after_create(profile) 10 def after_create(profile)
11 - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
12 - # the Noosfero core soon, see ActionItem3045  
13 - expire_statistics_block_cache(profile)  
14 end 11 end
15 12
16 protected 13 protected
@@ -31,13 +28,6 @@ protected @@ -31,13 +28,6 @@ protected
31 expire_blogs(profile) if profile.organization? 28 expire_blogs(profile) if profile.organization?
32 end 29 end
33 30
34 - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from  
35 - # the Noosfero core soon, see ActionItem3045  
36 - def expire_statistics_block_cache(profile)  
37 - blocks = profile.environment.blocks.select { |b| b.kind_of?(EnvironmentStatisticsBlock) }  
38 - BlockSweeper.expire_blocks(blocks)  
39 - end  
40 -  
41 def expire_blogs(profile) 31 def expire_blogs(profile)
42 profile.blogs.select{|b| !b.empty?}.each do |blog| 32 profile.blogs.select{|b| !b.empty?}.each do |blog|
43 pages = blog.posts.count / blog.posts_per_page + 1 33 pages = blog.posts.count / blog.posts_per_page + 1
app/sweepers/role_assignment_sweeper.rb
@@ -14,19 +14,21 @@ protected @@ -14,19 +14,21 @@ protected
14 14
15 def expire_caches(role_assignment) 15 def expire_caches(role_assignment)
16 expire_cache(role_assignment.accessor) 16 expire_cache(role_assignment.accessor)
17 - expire_cache(role_assignment.resource) if role_assignment.resource.respond_to?(:cache_keys) 17 + expire_cache(role_assignment.resource) if role_assignment.resource.kind_of?(Profile)
18 end 18 end
19 19
20 def expire_cache(profile) 20 def expire_cache(profile)
21 per_page = Noosfero::Constants::PROFILE_PER_PAGE 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 profile.blocks_to_expire_cache.each { |block| 26 profile.blocks_to_expire_cache.each { |block|
27 blocks = profile.blocks.select{|b| b.kind_of?(block)} 27 blocks = profile.blocks.select{|b| b.kind_of?(block)}
28 BlockSweeper.expire_blocks(blocks) 28 BlockSweeper.expire_blocks(blocks)
29 } 29 }
  30 +
  31 + expire_blocks_cache(profile, [:role_assignment])
30 end 32 end
31 33
32 end 34 end
app/views/account/_signup_form.html.erb
@@ -136,8 +136,6 @@ @@ -136,8 +136,6 @@
136 <script type="text/javascript"> 136 <script type="text/javascript">
137 jQuery(function($) { 137 jQuery(function($) {
138 138
139 - $('#signup-form #user_login').css('width', 335 - $('#signup-domain').outerWidth());  
140 -  
141 $('#signup-form input[type=text], #signup-form textarea').each(function() { 139 $('#signup-form input[type=text], #signup-form textarea').each(function() {
142 $(this).bind('blur', function() { 140 $(this).bind('blur', function() {
143 if ($(this).val() == '') { 141 if ($(this).val() == '') {
app/views/account/accept_terms.html.erb
@@ -19,10 +19,18 @@ @@ -19,10 +19,18 @@
19 <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %> 19 <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %>
20 <%= hidden_field_tag :answer, params[:answer] %> 20 <%= hidden_field_tag :answer, params[:answer] %>
21 21
22 - <%= labelled_check_box(environment.terms_of_use_acceptance_text.blank? ? _('I read the terms of use and accepted them') : environment.terms_of_use_acceptance_text, :terms_accepted, '1', false, :onclick => 'toggle_submit_button("submit-accept-terms", this.checked)') %> 22 + <%= labelled_check_box(environment.terms_of_use_acceptance_text.blank? ? _('I read the terms of use and accepted them') : environment.terms_of_use_acceptance_text, :terms_accepted, '1', false, :id => 'accept-terms') %>
23 <% button_bar do %> 23 <% button_bar do %>
24 <%= button 'cancel', _('Cancel'), :controller => 'home', :action => 'index' %> 24 <%= button 'cancel', _('Cancel'), :controller => 'home', :action => 'index' %>
25 <%= submit_button 'forward', _('Continue'), {:disabled => true, :class => 'disabled', :id => 'submit-accept-terms'} %> 25 <%= submit_button 'forward', _('Continue'), {:disabled => true, :class => 'disabled', :id => 'submit-accept-terms'} %>
26 <% end %> 26 <% end %>
27 <% end %> 27 <% end %>
28 </div> 28 </div>
  29 +
  30 +<script type="text/javascript">
  31 + jQuery('#accept-terms').change(function(){
  32 + jQuery("#submit-accept-terms").toggleClass("disabled");
  33 + jQuery("#submit-accept-terms").prop("disabled", !jQuery("#submit-accept-terms").prop("disabled"));
  34 + });
  35 +</script>
  36 +
app/views/account/signup.html.erb
1 <% if @register_pending %> 1 <% if @register_pending %>
2 -<div id='thanks-for-signing'>  
3 - <h1><%= _("Welcome to %s!") % environment.name %></h1>  
4 - <h3><%= _("Thanks for signing up, we're thrilled to have you on our social network!") %></h3>  
5 - <p><%= _("Firstly, some tips for getting started:") %></p>  
6 - <h4><%= _("Confirm your account!") %></h4>  
7 - <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p>  
8 - <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p>  
9 - <h4><%= _("What to do next?") %></h4>  
10 - <p><%= _("%s. Upload an avatar and let your friends find you easily :)") % link_to(_('Customize your profile'), {:controller => 'doc', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank') %></p>  
11 - <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p>  
12 - <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p>  
13 - <p><%= _("Start exploring and have fun!") %></p>  
14 -</div> 2 + <div id='thanks-for-signing'>
  3 + <% if environment.has_custom_welcome_screen? %>
  4 + <%= environment.settings[:signup_welcome_screen_body].html_safe %>
  5 + <% elsif environment.enabled?('admin_must_approve_new_users')%>
  6 + <h1><%= _("Welcome to %s!") % environment.name %></h1>
  7 + <h3><%= _("Thanks for signing up, we're thrilled to have you on our social network!") %></h3>
  8 + <p><%= _("Firstly, some tips for getting started:") %></p>
  9 + <% unless environment.enabled?('skip_new_user_email_confirmation') %>
  10 + <h4><%= _("Confirm your account and wait for admin approvement!") %></h4>
  11 + <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p>
  12 + <p><%= _("You won't appear as %s until your account is confirmed and approved.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p>
  13 + <% else %>
  14 + <h4><%= _("Wait for admin approvement!") %></h4>
  15 + <p><%= _("The administrators will evaluate your signup request for approvement.") %></p>
  16 + <p><%= _("You won't appear as %s until your account is approved.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p>
  17 + <% end %>
  18 + <h4><%= _("What to do next?") %></h4>
  19 + <p><%= _("%s. Upload an avatar and let your friends find you easily :)") % link_to(_('Customize your profile'), {:controller => 'doc', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank') %></p>
  20 + <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p>
  21 + <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p>
  22 + <p><%= _("Start exploring and have fun!") %></p>
  23 + <% else %>
  24 + <h1><%= _("Welcome to %s!") % environment.name %></h1>
  25 + <h3><%= _("Thanks for signing up, we're thrilled to have you on our social network!") %></h3>
  26 + <p><%= _("Firstly, some tips for getting started:") %></p>
  27 + <h4><%= _("Confirm your account!") %></h4>
  28 + <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p>
  29 + <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p>
  30 + <h4><%= _("What to do next?") %></h4>
  31 + <p><%= _("%s. Upload an avatar and let your friends find you easily :)") % link_to(_('Customize your profile'), {:controller => 'doc', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank') %></p>
  32 + <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p>
  33 + <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p>
  34 + <p><%= _("Start exploring and have fun!") %></p>
  35 + <% end %>
  36 + </div>
15 <% else %> 37 <% else %>
16 <h1><%= _('Sign up for %s!') % environment.name %></h1> 38 <h1><%= _('Sign up for %s!') % environment.name %></h1>
17 <%= render :partial => 'signup_form' %> 39 <%= render :partial => 'signup_form' %>
app/views/admin_panel/_signup_welcome_screen.html.erb 0 → 100644
@@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
  1 +<div class='description'>
  2 + <%= _('This text will be showed as a welcome message to users after signup') %><br/><br/>
  3 +</div>
  4 +
  5 +<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_screen_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %>
app/views/admin_panel/site_info.html.erb
@@ -12,6 +12,8 @@ @@ -12,6 +12,8 @@
12 :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %> 12 :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %>
13 <% tabs << {:title => _('Signup welcome text'), :id => 'signup-welcome-text', 13 <% tabs << {:title => _('Signup welcome text'), :id => 'signup-welcome-text',
14 :content => (render :partial => 'signup_welcome_text', :locals => {:f => f})} %> 14 :content => (render :partial => 'signup_welcome_text', :locals => {:f => f})} %>
  15 + <% tabs << {:title => _('Signup welcome message'), :id => 'signup-welcome-message',
  16 + :content => (render :partial => 'signup_welcome_screen', :locals => {:f => f}) }%>
15 <%= render_tabs(tabs) %> 17 <%= render_tabs(tabs) %>
16 <% button_bar do %> 18 <% button_bar do %>
17 <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %> 19 <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
app/views/blocks/login_block.html.erb
1 -<div class="logged-user-info" style='display: none;'>  
2 - <h2><%= _('Logged in as %s') % '{login}' %></h2>  
3 - <ul>  
4 - <li><%= _('User since {year}/{month}') %></li>  
5 - <li><%= link_to _('Homepage'), '/{login}' %></li>  
6 - </ul>  
7 - <div class="user-actions">  
8 - <%= link_to content_tag('span', _('Logout')), { :controller => 'account', :action => 'logout' }, :class => 'button with-text icon-menu-logout' %> 1 +<% if user.present? %>
  2 + <div class="logged-user-info">
  3 + <h2><%= _('Logged in as %s') % user.identifier %></h2>
  4 + <ul>
  5 + <li><%= _('User since %s/%s') % [user.created_at.month, user.created_at.year] %></li>
  6 + <li><%= link_to _('Homepage'), user.public_profile_url %></li>
  7 + </ul>
  8 + <div class="user-actions">
  9 + <%= link_to content_tag('span', _('Logout')), { :controller => 'account', :action => 'logout' }, :class => 'button with-text icon-menu-logout' %>
  10 + </div>
9 </div> 11 </div>
10 -</div>  
11 -<div class='not-logged-user' style='display: none;'>  
12 - <%= render :file => 'account/login_block' %>  
13 -</div> 12 +<% else %>
  13 + <div class='not-logged-user'>
  14 + <%= render :file => 'account/login_block' %>
  15 + </div>
  16 +<% end%>
app/views/blocks/members.html.erb
@@ -1,5 +0,0 @@ @@ -1,5 +0,0 @@
1 -<%= link_to _('View all'), :profile => profile.identifier, :controller => 'profile', :action => 'members' %>  
2 -  
3 -<% if show_join_leave_button %>  
4 - <%= render :partial => 'blocks/profile_info_actions/join_leave_community' %>  
5 -<% end %>  
app/views/blocks/my_network.html.erb
1 <%= block_title(title) %> 1 <%= block_title(title) %>
2 2
3 -<%= render :file => 'blocks/my_network/' + owner.class.name.underscore, :locals => { :owner => owner } %> 3 +<%= render_profile_actions owner.class %>
4 4
5 <ul> 5 <ul>
6 <li><%= link_to(_('Homepage'), owner.url, :class => 'url') %></li> 6 <li><%= link_to(_('Homepage'), owner.url, :class => 'url') %></li>
@@ -11,5 +11,5 @@ @@ -11,5 +11,5 @@
11 </ul> 11 </ul>
12 12
13 <div class="my-network-actions"> 13 <div class="my-network-actions">
14 - <%= render :file => 'blocks/profile_info_actions/' + owner.class.name.underscore %> 14 + <%= render 'blocks/profile_info_actions/' + owner.class.name.underscore %>
15 </div> 15 </div>
app/views/blocks/profile_image.html.erb
@@ -23,6 +23,6 @@ @@ -23,6 +23,6 @@
23 <% end %> 23 <% end %>
24 24
25 <div class="profile-info-options"> 25 <div class="profile-info-options">
26 - <%= render :file => view_for_profile_actions(block.owner.class) %> 26 + <%= render_profile_actions block.owner.class %>
27 </div> 27 </div>
28 </div><!-- end class="vcard" --> 28 </div><!-- end class="vcard" -->
app/views/blocks/profile_info.html.erb
@@ -40,7 +40,7 @@ @@ -40,7 +40,7 @@
40 <% end %> 40 <% end %>
41 41
42 <div class="profile-info-options"> 42 <div class="profile-info-options">
43 - <%= render :file => view_for_profile_actions(block.owner.class) %> 43 + <%= render_profile_actions block.owner.class %>
44 </div> 44 </div>
45 45
46 </div><!-- end class="vcard" --> 46 </div><!-- end class="vcard" -->
app/views/blocks/profile_info_actions/_community.html.erb 0 → 100644
@@ -0,0 +1,20 @@ @@ -0,0 +1,20 @@
  1 +<ul>
  2 + <li>
  3 + <%= render "blocks/profile_info_actions/join_leave_community" %>
  4 + </li>
  5 + <% if logged_in? %>
  6 + <% if profile.enable_contact? %>
  7 + <li>
  8 + <%= link_to content_tag('span', _('Send an e-mail')),
  9 + { :profile => profile.identifier,
  10 + :controller => 'contact',
  11 + :action => 'new' },
  12 + {:class => 'button with-text icon-menu-mail', :title => _('Send an e-mail to the administrators')} %>
  13 + </li>
  14 + <% end %>
  15 +
  16 + <li><%= report_abuse(profile, :button) %></li>
  17 +
  18 + <%= render_environment_features(:profile_actions) %>
  19 + <% end %>
  20 +</ul>