Commit d9c13a6557d41133eb9551bac17242899620139d

Authored by Victor Costa
2 parents cbc96f12 f323c51d

Merge branch 'master' into api

Conflicts:
	Gemfile
Showing 671 changed files with 90386 additions and 95088 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 671 files displayed.

.ackrc 0 → 100644
... ... @@ -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   -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>
AUTHORS.md
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 6 Developers
4 7 ==========
5 8  
  9 +Ábner Silva de Oliveira <abner.oliveira@serpro.gov.br>
6 10 Alan Freihof Tygel <alantygel@gmail.com>
  11 +alcampelo <alcampelo@alcampelo.(none)>
7 12 Alessandro Palmeira <alessandro.palmeira@gmail.com>
8 13 Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>
9 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 40 Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
36 41 Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
37 42 Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
  43 +Ana Losnak <analosnak@gmail.com>
  44 +Andre Bernardes <andrebsguedes@gmail.com>
38 45 Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
39 46 Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
40 47 Antonio Terceiro <terceiro@colivre.coop.br>
  48 +Arthur Del Esposte <arthurmde@gmail.com>
  49 +Arthur Del Esposte <arthurmde@yahoo.com.br>
41 50 Aurelio A. Heckert <aurelio@colivre.coop.br>
42 51 Braulio Bhavamitra <brauliobo@gmail.com>
43 52 Bráulio Bhavamitra <brauliobo@gmail.com>
... ... @@ -65,11 +74,14 @@ Caio Salgado + Renan Teruo &lt;caio.salgado@gmail.com&gt;
65 74 Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
66 75 Caio Salgado + Renan Teruo <renanteruoc@gmail.com>
67 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 79 Carlos Morais <carlos88morais@gmail.com>
69 80 Carlos Morais + Diego Araújo <diegoamc90@gmail.com>
70 81 Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
71 82 Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
72 83 Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
  84 +Daniela Feitosa <dani@dohko.(none)>
73 85 Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
74 86 Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
75 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 90 Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>
79 91 Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
80 92 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
  93 +Daniel Bucher <daniel.bucher88@gmail.com>
81 94 Daniel Cunha <daniel@colivre.coop.br>
  95 +David Carlos <ddavidcarlos1392@gmail.com>
82 96 diegoamc <diegoamc90@gmail.com>
83 97 Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
84 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 121 Diego Martinez <diegoamc90@gmail.com>
108 122 Diego Martinez <diego@diego-K55A.(none)>
109 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 128 Fernanda Lopes <nanda.listas+psl@gmail.com>
111 129 Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>
112 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 134 Grazieno Pellegrino <grazieno@gmail.com>
  135 +Gust <darksshades@hotmail.com>
  136 +Hebert Douglas <hebertdougl@gmail.com>
  137 +Hugo Melo <hugo@riseup.net>
114 138 Isaac Canan <isaac@intelletto.com.br>
115 139 Italo Valcy <italo@dcc.ufba.br>
116 140 Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
117 141 Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
118 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 144 João da Silva <jaodsilv@linux.ime.usp.br>
120 145 João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
121 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 171 João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
147 172 Joenio Costa <joenio@colivre.coop.br>
148 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 177 Junior Silva <juniorsilva1001@gmail.com>
150 178 Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>
  179 +Junior Silva <juniorsilva@colivre.coop.br>
  180 +juniorsilva <juniorsilva@QonoS.localhost.localdomain>
151 181 Keilla Menezes <keilla@colivre.coop.br>
152 182 Larissa Reis <larissa@colivre.coop.br>
153 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 187 Leandro Nunes dos Santos <leandronunes@gmail.com>
155 188 Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>
156 189 LinguÁgil 2010 <linguagil.bahia@gmail.com>
157 190 Lucas Melo <lucas@colivre.coop.br>
158 191 Lucas Melo <lucaspradomelo@gmail.com>
  192 +Luciano <lucianopcbr@gmail.com>
  193 +Luciano Prestes Cavalcanti <lucianopcbr@gmail.com>
159 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 197 Martín Olivera <molivera@solar.org.ar>
161 198 Moises Machado <moises@colivre.coop.br>
162 199 Naíla Alves <naila@colivre.coop.br>
... ... @@ -189,14 +226,21 @@ Renan Teruo + Diego Araujo &lt;renanteruoc@gmail.com&gt;
189 226 Renan Teruo + Diego Araújo <renanteruoc@gmail.com>
190 227 Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
191 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 230 Rodrigo Souto <diguliu@gmail.com>
193 231 Rodrigo Souto <rodrigo@colivre.coop.br>
194 232 Ronny Kursawe <kursawe.ronny@googlemail.com>
195 233 root <root@debian.sdr.serpro>
196 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 239 Valessio Brito <valessio@gmail.com>
198 240 vfcosta <vfcosta@gmail.com>
  241 +Victor Carvalho <victorhugodf.ac@gmail.com>
199 242 Victor Costa <vfcosta@gmail.com>
  243 +Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com>
200 244 Vinicius Cubas Brand <viniciuscb@gmail.com>
201 245 Visita <visita@debian.(none)>
202 246 Yann Lugrin <yann.lugrin@liquid-concept.ch>
... ...
Gemfile
1 1 source "https://rubygems.org"
2   -gem 'rails'
3   -gem 'fast_gettext'
4   -gem 'acts-as-taggable-on'
5   -gem 'prototype-rails'
6   -gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
7   -gem 'rails_autolink'
8   -gem 'pg'
9   -gem 'rmagick'
10   -gem 'RedCloth'
11   -gem 'will_paginate'
12   -gem 'ruby-feedparser'
13   -gem 'daemons'
14   -gem 'thin'
15   -gem 'hpricot'
16   -gem 'nokogiri'
  2 +gem 'rails', '~> 3.2.19'
  3 +gem 'fast_gettext', '~> 0.6.8'
  4 +gem 'acts-as-taggable-on', '~> 3.0.2'
  5 +gem 'prototype-rails', '~> 3.2.1'
  6 +gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
  7 +gem 'rails_autolink', '~> 1.1.5'
  8 +gem 'pg', '~> 0.13.2'
  9 +gem 'rmagick', '~> 2.13.1'
  10 +gem 'RedCloth', '~> 4.2.9'
  11 +gem 'will_paginate', '~> 3.0.3'
  12 +gem 'ruby-feedparser', '~> 0.7'
  13 +gem 'daemons', '~> 1.1.5'
  14 +gem 'thin', '~> 1.3.1'
  15 +gem 'hpricot', '~> 0.8.6'
  16 +gem 'nokogiri', '~> 1.5.5'
17 17 gem 'rake', :require => false
  18 +gem 'rest-client', '~> 1.6.7'
  19 +gem 'exception_notification', '~> 4.0.1'
  20 +gem 'gettext', '~> 2.2.1', :require => false, :group => :development
18 21 gem 'grape', '0.2.1'
19 22  
20 23 # FIXME list here all actual dependencies (i.e. the ones in debian/control),
21 24 # with their GEM names (not the Debian package names)
22 25  
23 26 group :production do
24   - gem 'dalli'
  27 + gem 'dalli', '~> 2.7.0'
25 28 end
26 29  
27 30 group :test do
28   - gem 'rspec'
29   - gem 'rspec-rails'
  31 + gem 'rspec', '~> 2.10.0'
  32 + gem 'rspec-rails', '~> 2.10.1'
  33 + gem 'mocha', '~> 1.1.0', :require => false
30 34 end
31 35  
32 36 group :cucumber do
33   - gem 'rake'
34   - gem 'cucumber-rails', :require => false
35   - gem 'capybara'
36   - gem 'cucumber'
37   - gem 'database_cleaner'
38   - 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'
39 42 end
40 43  
41 44 # include plugin gemfiles
... ...
Gemfile.lock
... ... @@ -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 13 This is a step-by-step guide to get a XMPP service working, in a Debian system.
21 14  
22 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 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 75 ## 4.1 testing all:
157 76  
... ... @@ -159,7 +78,6 @@ The following files must be created:
159 78  
160 79 If the configuration was done right, the message "Connected!" will be displayed.
161 80  
162   -
163 81 ## 5. Enabling kernel polling and SMP in `/etc/default/ejabberd`
164 82  
165 83 POLL=true
... ... @@ -205,32 +123,45 @@ Note: module proxy_http must be enabled:
205 123  
206 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 @@
  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
... ...
INSTALL.varnish.md
... ... @@ -24,10 +24,6 @@ Install the RPAF apache module (or skip this step if not using apache):
24 24  
25 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 27 4) Varnish configuration
32 28  
33 29 4a) Edit `/etc/default/varnish`
... ... @@ -44,10 +40,6 @@ On manual installations, change `/etc/noosfero/*` to `{Rails.root}/etc/noosfero/
44 40  
45 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 43 5) Enable varnish logging:
52 44  
53 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 48  
57 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
... ...
Rakefile
1 1 #!/usr/bin/env rake
  2 +
2 3 # Add your own tasks in files placed in lib/tasks ending in .rake,
3 4 # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
4 5  
5 6 require File.expand_path('../config/application', __FILE__)
6 7  
7 8 Noosfero::Application.load_tasks
  9 +
  10 +[
  11 + "baseplugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  12 + "config/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  13 + "config/plugins/*/vendor/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake",
  14 +].map do |pattern|
  15 + Dir.glob(pattern).sort
  16 +end.flatten.each do |taskfile|
  17 + load taskfile
  18 +end
... ...
Vagrantfile
... ... @@ -3,7 +3,7 @@
3 3  
4 4 VAGRANTFILE_API_VERSION = "2"
5 5 Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
6   - config.vm.box = "debian-wheezy"
  6 + config.vm.box = ENV.fetch('VAGRANT_BOX', "debian-wheezy")
7 7 config.vm.network :forwarded_port, host: 3000, guest: 3000
8 8 config.vm.provision :shell do |shell|
9 9 shell.inline = 'su vagrant -c /vagrant/script/vagrant'
... ...
app/controllers/admin/admin_panel_controller.rb
... ... @@ -7,6 +7,7 @@ class AdminPanelController &lt; AdminController
7 7 end
8 8  
9 9 def site_info
  10 + @no_design_blocks = true
10 11 if request.post?
11 12 if params[:environment][:languages]
12 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 45 if request.post?
46 46 @category.update_attributes!(params[:category])
47 47 @saved = true
  48 + session[:notice] = _("Category %s saved." % @category.name)
48 49 redirect_to :action => 'index'
49 50 end
50 51 rescue Exception => e
  52 + session[:notice] = _('Could not save category.')
51 53 render :action => 'edit'
52 54 end
53 55 end
... ...
app/controllers/admin/environment_design_controller.rb
... ... @@ -3,9 +3,7 @@ class EnvironmentDesignController &lt; BoxOrganizerController
3 3 protect 'edit_environment_design', :environment
4 4  
5 5 def available_blocks
6   - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
7   - # the Noosfero core soon, see ActionItem3045
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 7 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
10 8 end
11 9  
... ...
app/controllers/admin/features_controller.rb
... ... @@ -51,4 +51,10 @@ class FeaturesController &lt; AdminController
51 51 redirect_to :action => 'manage_fields'
52 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 60 end
... ...
app/controllers/application_controller.rb
... ... @@ -7,6 +7,12 @@ class ApplicationController &lt; ActionController::Base
7 7 before_filter :detect_stuff_by_domain
8 8 before_filter :init_noosfero_plugins
9 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 17 after_filter :set_csrf_cookie
12 18  
... ... @@ -34,7 +40,7 @@ class ApplicationController &lt; ActionController::Base
34 40  
35 41 theme_layout = theme_option(:layout)
36 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 44 else
39 45 'application'
40 46 end
... ... @@ -187,4 +193,8 @@ class ApplicationController &lt; ActionController::Base
187 193 {:results => scope.paginate(paginate_options)}
188 194 end
189 195  
  196 + def private_environment?
  197 + @environment.enabled?(:restrict_to_members)
  198 + end
  199 +
190 200 end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -4,6 +4,12 @@ class CmsController &lt; MyProfileController
4 4  
5 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 13 def self.protect_if(*args)
8 14 before_filter(*args) do |c|
9 15 user, profile = c.send(:user), c.send(:profile)
... ... @@ -143,7 +149,9 @@ class CmsController &lt; MyProfileController
143 149 end
144 150  
145 151 @article.profile = profile
  152 + @article.author = user
146 153 @article.last_changed_by = user
  154 + @article.created_by = user
147 155  
148 156 translations if @article.translatable?
149 157  
... ... @@ -187,7 +195,18 @@ class CmsController &lt; MyProfileController
187 195 end
188 196 if request.post? && params[:uploaded_files]
189 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 210 end
192 211 @errors = @uploaded_files.select { |f| f.errors.any? }
193 212 if @errors.any?
... ... @@ -208,7 +227,7 @@ class CmsController &lt; MyProfileController
208 227 @article = profile.articles.find(params[:id])
209 228 if request.post?
210 229 @article.destroy
211   - session[:notice] = _("\"#{@article.name}\" was removed.")
  230 + session[:notice] = _("\"%s\" was removed." % @article.name)
212 231 referer = Rails.application.routes.recognize_path URI.parse(request.referer).path rescue nil
213 232 if referer and referer[:controller] == 'cms' and referer[:action] != 'edit'
214 233 redirect_to referer
... ... @@ -231,7 +250,7 @@ class CmsController &lt; MyProfileController
231 250 @current_category = Category.find(params[:category_id])
232 251 @categories = @current_category.children
233 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 254 end
236 255  
237 256 def publish
... ... @@ -247,12 +266,15 @@ class CmsController &lt; MyProfileController
247 266 end.compact unless params[:marked_groups].nil?
248 267 if request.post?
249 268 @failed = {}
  269 + if @marked_groups.empty?
  270 + return session[:notice] = _("Select some group to publish your article")
  271 + end
250 272 @marked_groups.each do |item|
251 273 task = ApproveArticle.create!(:article => @article, :name => item[:name], :target => item[:group], :requestor => profile)
252 274 begin
253 275 task.finish unless item[:group].moderated_articles?
254 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 278 end
257 279 end
258 280 if @failed.blank?
... ...
app/controllers/my_profile/friends_controller.rb 100644 → 100755
... ... @@ -11,7 +11,7 @@ class FriendsController &lt; MyProfileController
11 11 def remove
12 12 @friend = profile.friends.find(params[:id])
13 13 if request.post? && params[:confirmation]
14   - profile.remove_friend(@friend)
  14 + Friendship.remove_friendship(profile, @friend)
15 15 redirect_to :action => 'index'
16 16 end
17 17 end
... ... @@ -20,7 +20,7 @@ class FriendsController &lt; MyProfileController
20 20  
21 21 class << self
22 22 def per_page
23   - 10
  23 + 12
24 24 end
25 25 end
26 26 def per_page
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -7,9 +7,9 @@ class MembershipsController &lt; MyProfileController
7 7 ra = profile.role_assignments.find_by_role_id(role.id)
8 8 ra.present? && ra.resource_type == 'Profile'
9 9 end
10   - @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  10 + @filter = params[:filter_type].to_i
11 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 13 rescue ActiveRecord::RecordNotFound
14 14 @memberships = []
15 15 end
... ... @@ -21,6 +21,9 @@ class MembershipsController &lt; MyProfileController
21 21 @back_to = params[:back_to] || url_for(:action => 'index')
22 22 if request.post? && @community.valid?
23 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 27 redirect_to @back_to
25 28 return
26 29 end
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -9,14 +9,8 @@ class ProfileDesignController &lt; BoxOrganizerController
9 9  
10 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 12 # blocks exclusive to people
18 13 if profile.person?
19   - blocks << FriendsBlock
20 14 blocks << FavoriteEnterprisesBlock
21 15 blocks << CommunitiesBlock
22 16 blocks << EnterprisesBlock
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -54,7 +54,7 @@ class ProfileEditorController &lt; MyProfileController
54 54 @current_category = Category.find(params[:category_id])
55 55 @categories = @current_category.children
56 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 58 end
59 59  
60 60 def header_footer
... ...
app/controllers/my_profile/tasks_controller.rb
... ... @@ -4,6 +4,7 @@ class TasksController &lt; MyProfileController
4 4  
5 5 def index
6 6 @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  7 + @task_types = Task.pending_types_for(profile)
7 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 9 @failed = params ? params[:failed] : {}
9 10 end
... ...
app/controllers/public/account_controller.rb
... ... @@ -2,7 +2,7 @@ class AccountController &lt; ApplicationController
2 2  
3 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 6 before_filter :redirect_if_logged_in, :only => [:login, :signup]
7 7 before_filter :protect_from_bots, :only => :signup
8 8  
... ... @@ -15,9 +15,23 @@ class AccountController &lt; ApplicationController
15 15  
16 16 def activate
17 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 35 else
22 36 session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
23 37 redirect_to :controller => :home
... ... @@ -35,6 +49,7 @@ class AccountController &lt; ApplicationController
35 49 self.current_user ||= User.authenticate(params[:user][:login], params[:user][:password], environment) if params[:user]
36 50  
37 51 if logged_in?
  52 + check_join_in_community(self.current_user)
38 53 if params[:remember_me] == "1"
39 54 self.current_user.remember_me
40 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 97 @user.return_to = session[:return_to]
83 98 @person = Person.new(params[:profile_data])
84 99 @person.environment = @user.environment
  100 +
85 101 if request.post?
86 102 if may_be_a_bot
87 103 set_signup_start_time_for_now
... ... @@ -91,6 +107,7 @@ class AccountController &lt; ApplicationController
91 107 if session[:may_be_a_bot]
92 108 return false unless verify_recaptcha :model=>@user, :message=>_('Captcha (the human test)')
93 109 end
  110 + @user.community_to_join = session[:join]
94 111 @user.signup!
95 112 owner_role = Role.find_by_name('owner')
96 113 @user.person.affiliate(@user.person, [owner_role]) if owner_role
... ... @@ -99,10 +116,20 @@ class AccountController &lt; ApplicationController
99 116 invitation.update_attributes!({:friend => @user.person})
100 117 invitation.finish
101 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 127 if @user.activated?
103 128 self.current_user = @user
  129 + check_join_in_community(@user)
104 130 go_to_signup_initial_page
105 131 else
  132 + session[:notice] = _('Thanks for registering!')
106 133 @register_pending = true
107 134 end
108 135 end
... ... @@ -388,12 +415,6 @@ class AccountController &lt; ApplicationController
388 415 end
389 416  
390 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 418 if params[:return_to]
398 419 redirect_to params[:return_to]
399 420 elsif environment.enabled?('allow_change_of_redirection_after_login')
... ... @@ -444,4 +465,19 @@ class AccountController &lt; ApplicationController
444 465 redirect_back_or_default(default)
445 466 end
446 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 483 end
... ...
app/controllers/public/catalog_controller.rb
... ... @@ -11,7 +11,7 @@ class CatalogController &lt; PublicController
11 11 protected
12 12  
13 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 15 redirect_to :controller => 'profile', :profile => profile.identifier, :action => 'index'
16 16 end
17 17 end
... ...
app/controllers/public/chat_controller.rb
... ... @@ -19,9 +19,13 @@ class ChatController &lt; PublicController
19 19 def avatar
20 20 profile = environment.profiles.find_by_identifier(params[:id])
21 21 filename, mimetype = profile_icon(profile, :minor, true)
22   - data = File.read(File.join(Rails.root, 'public', filename))
23   - render :text => data, :layout => false, :content_type => mimetype
24   - expires_in 24.hours
  22 + if filename =~ /^https?:/
  23 + redirect_to filename
  24 + else
  25 + data = File.read(File.join(Rails.root, 'public', filename))
  26 + render :text => data, :layout => false, :content_type => mimetype
  27 + expires_in 24.hours
  28 + end
25 29 end
26 30  
27 31 def index
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -8,49 +8,32 @@ class ContentViewerController &lt; ApplicationController
8 8 helper TagsHelper
9 9  
10 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 13 @version = params[:version].to_i
15 14  
16 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 18 else
23 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 21 end
32 22  
33 23 return unless allow_access_to_page(path)
34 24  
35 25 if @version > 0
36 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 28 end
43 29  
44 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 37 end
55 38  
56 39 # At this point the page will be showed
... ... @@ -58,64 +41,22 @@ class ContentViewerController &lt; ApplicationController
58 41  
59 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 46 @form_div = params[:form]
76 47  
77 48 #FIXME see a better way to do this. It's not need to pass this variable anymore
78 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 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 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 61 if request.xhr? and params[:comment_order]
121 62 if @comment_order == 'newest'
... ... @@ -133,7 +74,7 @@ class ContentViewerController &lt; ApplicationController
133 74 end
134 75  
135 76 def versions_diff
136   - path = params[:page].join('/')
  77 + path = params[:page]
137 78 @page = profile.articles.find_by_path(path)
138 79 @v1, @v2 = @page.versions.find_by_version(params[:v1]), @page.versions.find_by_version(params[:v2])
139 80 end
... ... @@ -203,4 +144,127 @@ class ContentViewerController &lt; ApplicationController
203 144 user_agent.match(/crawler/) ||
204 145 user_agent.match(/\(.*https?:\/\/.*\)/)
205 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 270 end
... ...
app/controllers/public/profile_controller.rb
... ... @@ -3,7 +3,7 @@ class ProfileController &lt; PublicController
3 3 needs_profile
4 4 before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add]
5 5 before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail]
6   - before_filter :login_required, :only => [:add, :join, :join_not_logged, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
  6 + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
7 7  
8 8 helper TagsHelper
9 9  
... ... @@ -51,7 +51,7 @@ class ProfileController &lt; PublicController
51 51  
52 52 def communities
53 53 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])
  54 + @communities = profile.communities.includes(relations_to_include).paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.communities.count)
55 55 end
56 56 end
57 57  
... ... @@ -97,21 +97,12 @@ class ProfileController &lt; PublicController
97 97 end
98 98  
99 99 def join_not_logged
100   - if request.post?
101   - profile.add_member(user)
102   - session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name if profile.closed?
103   - redirect_to_previous_location
  100 + session[:join] = profile.identifier
  101 +
  102 + if user
  103 + redirect_to :controller => 'profile', :action => 'join'
104 104 else
105   - if user.memberships.include?(profile)
106   - session[:notice] = _('You are already a member of %s.') % profile.name
107   - redirect_to profile.url
108   - return
109   - end
110   - if request.xhr?
111   - render :layout => false
112   - else
113   - redirect_to profile.url
114   - end
  105 + redirect_to :controller => '/account', :action => 'login'
115 106 end
116 107 end
117 108  
... ... @@ -211,7 +202,8 @@ class ProfileController &lt; PublicController
211 202 end
212 203  
213 204 def more_comments
214   - activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity], :user_id => @profile})
  205 + profile_filter = @profile.person? ? {:user_id => @profile} : {:target_id => @profile}
  206 + activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity]}.merge(profile_filter))
215 207 comments_count = activity.comments.count
216 208 comment_page = (params[:comment_page] || 1).to_i
217 209 comments_per_page = 5
... ...
app/helpers/application_helper.rb
... ... @@ -312,13 +312,13 @@ module ApplicationHelper
312 312 raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?'
313 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 322 end
323 323  
324 324 def user
... ... @@ -482,7 +482,12 @@ module ApplicationHelper
482 482 '/images/icons-app/enterprise-'+ size.to_s() +'.png'
483 483 end
484 484 else
485   - '/images/icons-app/person-'+ size.to_s() +'.png'
  485 + pixels = Image.attachment_options[:thumbnails][size].split('x').first
  486 + gravatar_profile_image_url(
  487 + profile.email,
  488 + :size => pixels,
  489 + :d => gravatar_default
  490 + )
486 491 end
487 492 filename = default_or_themed_icon(icon)
488 493 end
... ... @@ -602,7 +607,7 @@ module ApplicationHelper
602 607 end
603 608  
604 609 def gravatar_default
605   - (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar']
  610 + (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar'] || 'mm'
606 611 end
607 612  
608 613 attr_reader :environment
... ... @@ -671,7 +676,7 @@ module ApplicationHelper
671 676  
672 677 def theme_javascript_ng
673 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 680 javascript_include_tag script
676 681 else
677 682 nil
... ... @@ -1002,17 +1007,26 @@ module ApplicationHelper
1002 1007 def display_category_menu(block, categories, root = true)
1003 1008 categories = categories.sort{|x,y| x.name <=> y.name}
1004 1009 return "" if categories.blank?
1005   - content_tag(:ul,
  1010 + content_tag(:ul) do
1006 1011 categories.map do |category|
1007 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 1030 content_tag(:p) +
1017 1031 (root ? javascript_tag("
1018 1032 jQuery('.child-category').hide();
... ... @@ -1034,7 +1048,7 @@ module ApplicationHelper
1034 1048 end
1035 1049  
1036 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 1052 end
1039 1053 alias :browse_contents_menu :search_contents_menu
1040 1054  
... ... @@ -1050,7 +1064,7 @@ module ApplicationHelper
1050 1064 end
1051 1065  
1052 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 1068 end
1055 1069 alias :browse_people_menu :search_people_menu
1056 1070  
... ... @@ -1066,7 +1080,7 @@ module ApplicationHelper
1066 1080 end
1067 1081  
1068 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 1084 end
1071 1085 alias :browse_communities_menu :search_communities_menu
1072 1086  
... ... @@ -1086,7 +1100,7 @@ module ApplicationHelper
1086 1100 result
1087 1101 end
1088 1102  
1089   - def manage_link(list, kind)
  1103 + def manage_link(list, kind, title)
1090 1104 if list.present?
1091 1105 link_to_all = nil
1092 1106 if list.count > 5
... ... @@ -1099,19 +1113,23 @@ module ApplicationHelper
1099 1113 if link_to_all
1100 1114 link << link_to_all
1101 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 1117 end
1104 1118 end
1105 1119  
1106 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 1123 end
1110 1124  
1111 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 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 1133 end
1116 1134  
1117 1135 def usermenu_logged_in
... ... @@ -1123,9 +1141,9 @@ module ApplicationHelper
1123 1141  
1124 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 1143 render_environment_features(:usermenu) +
1126   - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') +
1127   - manage_enterprises.to_s +
1128   - manage_communities.to_s +
  1144 + admin_link +
  1145 + manage_enterprises +
  1146 + manage_communities +
1129 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 1148 pending_tasks_count +
1131 1149 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
... ... @@ -1210,22 +1228,9 @@ module ApplicationHelper
1210 1228 end
1211 1229  
1212 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 1234 end
1230 1235  
1231 1236 def render_dialog_error_messages(instance_name)
... ... @@ -1281,9 +1286,9 @@ module ApplicationHelper
1281 1286  
1282 1287 def delete_article_message(article)
1283 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 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 1292 end
1288 1293 end
1289 1294  
... ... @@ -1360,7 +1365,7 @@ module ApplicationHelper
1360 1365 @message = _("The content here is available to %s's friends only.") % profile.short_name
1361 1366 else
1362 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 1369 end
1365 1370 @no_design_blocks = true
1366 1371 end
... ... @@ -1402,4 +1407,14 @@ module ApplicationHelper
1402 1407 content_tag('ul', article.versions.map {|v| link_to("r#{v.version}", @page.url.merge(:version => v.version))})
1403 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 1420 end
... ...
app/helpers/article_helper.rb
... ... @@ -83,6 +83,10 @@ module ArticleHelper
83 83 array.map { |object| {:id => object.id, :name => object.name} }
84 84 end
85 85  
  86 + def prepare_to_token_input_by_label(array)
  87 + array.map { |object| {:label => object.name, :value => object.name} }
  88 + end
  89 +
86 90 def cms_label_for_new_children
87 91 _('New article')
88 92 end
... ...
app/helpers/block_helper.rb
... ... @@ -6,19 +6,20 @@ module BlockHelper
6 6 content_tag 'h3', content_tag('span', h(title)), :class => tag_class
7 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 12 <td>
13 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 14 </td>
15 15 <td>#{text_field_tag 'block[images][][address]', image[:address], :class => 'highlight-address', :size => 20}</td>
16 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 18 <td colspan=\"3\"><label>#{
19 19 content_tag('span', _('Title')) +
20 20 text_field_tag('block[images][][title]', image[:title], :class => 'highlight-title', :size => 45)
21 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 23 </tr>
23 24 "
24 25 end
... ...
app/helpers/blog_helper.rb
... ... @@ -17,13 +17,13 @@ module BlogHelper
17 17 _('Configure blog')
18 18 end
19 19  
20   - def list_posts(articles, format = 'full')
  20 + def list_posts(articles, format = 'full', paginate = true)
21 21 pagination = will_paginate(articles, {
22 22 :param_name => 'npage',
23 23 :previous_label => _('&laquo; Newer posts'),
24 24 :next_label => _('Older posts &raquo;'),
25 25 :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
26   - }) if articles.present?
  26 + }) if articles.present? && paginate
27 27 content = []
28 28 artic_len = articles.length
29 29 articles.each_with_index{ |art,i|
... ... @@ -45,9 +45,9 @@ module BlogHelper
45 45  
46 46 def display_post(article, format = 'full')
47 47 no_comments = (format == 'full') ? false : true
  48 + title = article_title(article, :no_comments => no_comments)
48 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 51 end
52 52  
53 53 def display_full_format(article)
... ...
app/helpers/categories_helper.rb
1 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 3 TYPES = [
24 4 [ _('General Category'), Category.to_s ],
25 5 [ _('Product Category'), ProductCategory.to_s ],
26 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 9 def select_category_type(field)
47 10 value = params[field]
48 11 labelled_form_field(_('Type of category'), select_tag('type', options_for_select(TYPES, value)))
49 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 19 #FIXME make this test
52 20 def selected_category_link(cat)
53 21 js_remove = "jQuery('#selected-category-#{cat.id}').remove();"
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -10,7 +10,7 @@ module ContentViewerHelper
10 10 end
11 11  
12 12 def number_of_comments(article)
13   - display_number_of_comments(article.comments.without_spam.count)
  13 + display_number_of_comments(article.comments_count - article.spam_comments_count)
14 14 end
15 15  
16 16 def article_title(article, args = {})
... ... @@ -26,7 +26,7 @@ module ContentViewerHelper
26 26 end
27 27 title << content_tag('span',
28 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 30 content_tag('span', comments, :class => 'comments'),
31 31 :class => 'created-at'
32 32 )
... ...
app/helpers/folder_helper.rb
... ... @@ -5,15 +5,17 @@ module FolderHelper
5 5 include ShortFilename
6 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 13 :order => "updated_at DESC",
12 14 :per_page => 10,
13 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 19 else
18 20 content_tag('em', _('(empty folder)'))
19 21 end
... ... @@ -23,21 +25,33 @@ module FolderHelper
23 25 articles.select {|article| article.display_to?(user)}
24 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 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 43 end
33 44 result = content_tag(
34 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 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 55 else
42 56 result
43 57 end
... ...
app/helpers/layout_helper.rb
... ... @@ -27,6 +27,7 @@ module LayoutHelper
27 27 'thickbox',
28 28 'lightbox',
29 29 'colorbox',
  30 + 'inputosaurus',
30 31 pngfix_stylesheet_path,
31 32 ] + tokeninput_stylesheets
32 33 plugins_stylesheets = @plugins.select(&:stylesheet?).map { |plugin| plugin.class.public_path('style.css') }
... ...
app/helpers/sweeper_helper.rb
... ... @@ -18,9 +18,7 @@ module SweeperHelper
18 18 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s))
19 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 22 end
25 23  
26 24 def expire_communities(profile)
... ...
app/helpers/token_helper.rb
... ... @@ -18,6 +18,7 @@ module TokenHelper
18 18 options[:on_add] ||= 'null'
19 19 options[:on_delete] ||= 'null'
20 20 options[:on_ready] ||= 'null'
  21 + options[:query_param] ||= 'q'
21 22  
22 23 result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id})))
23 24 result += javascript_tag("jQuery('##{element_id}')
... ... @@ -30,7 +31,7 @@ module TokenHelper
30 31 searchDelay: #{options[:search_delay].to_json},
31 32 preventDuplicates: #{options[:prevent_duplicates].to_json},
32 33 backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
33   - queryParam: #{name.to_json},
  34 + queryParam: #{options[:query_param].to_json},
34 35 tokenLimit: #{options[:token_limit].to_json},
35 36 onResult: #{options[:on_result]},
36 37 onAdd: #{options[:on_add]},
... ... @@ -48,4 +49,4 @@ module TokenHelper
48 49 result
49 50 end
50 51  
51   -end
52 52 \ No newline at end of file
  53 +end
... ...
app/mailers/user_mailer.rb
... ... @@ -15,10 +15,12 @@ class UserMailer &lt; ActionMailer::Base
15 15 end
16 16  
17 17 def activation_code(user)
18   - @recipient = user.name,
  18 + @recipient = user.name
19 19 @activation_code = user.activation_code
20 20 @environment = user.environment.name
21 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 25 mail(
24 26 from: "#{user.environment.name} <#{user.environment.contact_email}>",
... ...
app/models/approve_article.rb
... ... @@ -48,7 +48,7 @@ class ApproveArticle &lt; Task
48 48 end
49 49  
50 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 52 end
53 53  
54 54 def title
... ...
app/models/article.rb
... ... @@ -2,7 +2,7 @@ require &#39;hpricot&#39;
2 2  
3 3 class Article < ActiveRecord::Base
4 4  
5   - attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, :allow_members_to_edit, :translation_of_id, :language, :license_id, :parent_id, :display_posts_in_current_language, :category_ids, :posts_per_page, :moderate_comments, :accept_comments, :feed, :published, :source, :highlighted, :notify_comments, :display_hits, :slug, :external_feed_builder, :display_versions
  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 7 acts_as_having_image
8 8  
... ... @@ -41,8 +41,8 @@ class Article &lt; ActiveRecord::Base
41 41 before_save :sanitize_tag_list
42 42  
43 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 46 end
47 47 end
48 48  
... ... @@ -54,7 +54,9 @@ class Article &lt; ActiveRecord::Base
54 54  
55 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 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 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 91 article.parent = article.profile.blog
90 92 end
91 93 end
  94 +
  95 + if article.created_by
  96 + article.author_name = article.created_by.name
  97 + end
  98 +
92 99 end
93 100  
94 101 after_destroy :destroy_activity
... ... @@ -160,14 +167,17 @@ class Article &lt; ActiveRecord::Base
160 167 self.profile
161 168 end
162 169  
163   - def self.human_attribute_name(attrib, options = {})
  170 + def self.human_attribute_name_with_customization(attrib, options={})
164 171 case attrib.to_sym
165 172 when :name
166 173 _('Title')
167 174 else
168   - _(self.superclass.human_attribute_name(attrib))
  175 + _(self.human_attribute_name_without_customization(attrib))
169 176 end
170 177 end
  178 + class << self
  179 + alias_method_chain :human_attribute_name, :customization
  180 + end
171 181  
172 182 def css_class_list
173 183 [self.class.name.to_css_class]
... ... @@ -215,6 +225,10 @@ class Article &lt; ActiveRecord::Base
215 225 acts_as_versioned
216 226 self.non_versioned_columns << 'setting'
217 227  
  228 + def version_condition_met?
  229 + (['name', 'body', 'abstract', 'filename', 'start_date', 'end_date', 'image_id', 'license_id'] & changed).length > 0
  230 + end
  231 +
218 232 def comment_data
219 233 comments.map {|item| [item.title, item.body].join(' ') }.join(' ')
220 234 end
... ... @@ -462,10 +476,10 @@ class Article &lt; ActiveRecord::Base
462 476 ['TextArticle', 'TextileArticle', 'TinyMceArticle']
463 477 end
464 478  
465   - scope :published, :conditions => { :published => true }
466   - scope :folders, lambda {|profile|{:conditions => { :type => profile.folder_types} }}
467   - scope :no_folders, lambda {|profile|{:conditions => ['type NOT IN (?)', profile.folder_types]}}
468   - scope :galleries, :conditions => { :type => 'Gallery' }
  479 + scope :published, :conditions => ['articles.published = ?', true]
  480 + scope :folders, lambda {|profile|{:conditions => ['articles.type IN (?)', profile.folder_types] }}
  481 + scope :no_folders, lambda {|profile|{:conditions => ['articles.type NOT IN (?)', profile.folder_types]}}
  482 + scope :galleries, :conditions => [ "articles.type IN ('Gallery')" ]
469 483 scope :images, :conditions => { :is_image => true }
470 484 scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
471 485 scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } }
... ... @@ -475,7 +489,7 @@ class Article &lt; ActiveRecord::Base
475 489 scope :more_recent, :order => "created_at DESC"
476 490  
477 491 def self.display_filter(user, profile)
478   - return {:conditions => ['published = ?', true]} if !user
  492 + return {:conditions => ['articles.published = ?', true]} if !user
479 493 {:conditions => [" articles.published = ? OR
480 494 articles.last_changed_by_id = ? OR
481 495 articles.profile_id = ? OR
... ... @@ -502,6 +516,7 @@ class Article &lt; ActiveRecord::Base
502 516 end
503 517  
504 518 def allow_post_content?(user = nil)
  519 + return true if allow_edit_topic?(user)
505 520 user && (user.has_permission?('post_content', profile) || allow_publish_content?(user) && (user == author))
506 521 end
507 522  
... ... @@ -521,9 +536,14 @@ class Article &lt; ActiveRecord::Base
521 536 end
522 537  
523 538 def allow_edit?(user)
  539 + return true if allow_edit_topic?(user)
524 540 allow_post_content?(user) || user && allow_members_to_edit && user.is_member_of?(profile)
525 541 end
526 542  
  543 + def allow_edit_topic?(user)
  544 + self.belongs_to_forum? && (user == author) && user.present? && user.is_member_of?(profile)
  545 + end
  546 +
527 547 def moderate_comments?
528 548 moderate_comments == true
529 549 end
... ... @@ -638,33 +658,30 @@ class Article &lt; ActiveRecord::Base
638 658 can_display_versions? && display_versions
639 659 end
640 660  
641   - def author(version_number = nil)
642   - if version_number
643   - version = versions.find_by_version(version_number)
644   - author_id = version.last_changed_by_id if version
645   - Person.exists?(author_id) ? Person.find(author_id) : nil
646   - else
647   - if versions.empty?
648   - last_changed_by
649   - else
650   - author_id = versions.first.last_changed_by_id
651   - Person.exists?(author_id) ? Person.find(author_id) : nil
652   - end
653   - end
  661 + def get_version(version_number = nil)
  662 + version_number ? versions.find(:first, :order => 'version', :offset => version_number - 1) : versions.earliest
  663 + end
  664 +
  665 + def author_by_version(version_number = nil)
  666 + version_number ? profile.environment.people.find_by_id(get_version(version_number).author_id) : author
654 667 end
655 668  
656 669 def author_name(version_number = nil)
657   - person = author(version_number)
658   - person ? person.name : (setting[:author_name] || _('Unknown'))
  670 + person = author_by_version(version_number)
  671 + if version_number
  672 + person ? person.name : _('Unknown')
  673 + else
  674 + person ? person.name : (setting[:author_name] || _('Unknown'))
  675 + end
659 676 end
660 677  
661 678 def author_url(version_number = nil)
662   - person = author(version_number)
  679 + person = author_by_version(version_number)
663 680 person ? person.url : nil
664 681 end
665 682  
666 683 def author_id(version_number = nil)
667   - person = author(version_number)
  684 + person = author_by_version(version_number)
668 685 person ? person.id : nil
669 686 end
670 687  
... ... @@ -675,7 +692,7 @@ class Article &lt; ActiveRecord::Base
675 692  
676 693 def version_license(version_number = nil)
677 694 return license if version_number.nil?
678   - profile.environment.licenses.find_by_id(versions.find_by_version(version_number).license_id)
  695 + profile.environment.licenses.find_by_id(get_version(version_number).license_id)
679 696 end
680 697  
681 698 alias :active_record_cache_key :cache_key
... ...
app/models/block.rb
... ... @@ -22,6 +22,10 @@ class Block &lt; ActiveRecord::Base
22 22 false
23 23 end
24 24  
  25 + def get_limit
  26 + [0,limit].max
  27 + end
  28 +
25 29 def embed_code
26 30 me = self
27 31 proc do
... ...
app/models/box.rb
... ... @@ -28,20 +28,14 @@ class Box &lt; ActiveRecord::Base
28 28 CategoriesBlock,
29 29 CommunitiesBlock,
30 30 EnterprisesBlock,
31   - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
32   - # the Noosfero core soon, see ActionItem3045
33   - EnvironmentStatisticsBlock,
34 31 FansBlock,
35 32 FavoriteEnterprisesBlock,
36 33 FeedReaderBlock,
37   - FriendsBlock,
38 34 HighlightsBlock,
39 35 LinkListBlock,
40 36 LoginBlock,
41 37 MainBlock,
42   - MembersBlock,
43 38 MyNetworkBlock,
44   - PeopleBlock,
45 39 ProfileImageBlock,
46 40 RawHTMLBlock,
47 41 RecentDocumentsBlock,
... ... @@ -56,21 +50,15 @@ class Box &lt; ActiveRecord::Base
56 50 CommunitiesBlock,
57 51 DisabledEnterpriseMessageBlock,
58 52 EnterprisesBlock,
59   - # TODO EnvironmentStatisticsBlock is DEPRECATED and will be removed from
60   - # the Noosfero core soon, see ActionItem3045
61   - EnvironmentStatisticsBlock,
62 53 FansBlock,
63 54 FavoriteEnterprisesBlock,
64 55 FeaturedProductsBlock,
65 56 FeedReaderBlock,
66   - FriendsBlock,
67 57 HighlightsBlock,
68 58 LinkListBlock,
69 59 LocationBlock,
70 60 LoginBlock,
71   - MembersBlock,
72 61 MyNetworkBlock,
73   - PeopleBlock,
74 62 ProductsBlock,
75 63 ProductCategoriesBlock,
76 64 ProfileImageBlock,
... ...
app/models/categories_block.rb
... ... @@ -8,6 +8,8 @@ class CategoriesBlock &lt; Block
8 8  
9 9 settings_items :category_types, :type => Array, :default => []
10 10  
  11 + attr_accessible :category_types
  12 +
11 13 def self.description
12 14 _("Categories Menu")
13 15 end
... ...
app/models/category.rb
... ... @@ -14,9 +14,6 @@ class Category &lt; ActiveRecord::Base
14 14 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('{fn} is already being used by another category.').fix_i18n
15 15 belongs_to :environment
16 16  
17   - validates_inclusion_of :display_color, :in => 1..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 17 # Finds all top level categories for a given environment.
21 18 scope :top_level_for, lambda { |environment|
22 19 {:conditions => ['parent_id is null and environment_id = ?', environment.id ]}
... ... @@ -42,6 +39,13 @@ class Category &lt; ActiveRecord::Base
42 39  
43 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 49 scope :from_types, lambda { |types|
46 50 types.select{ |t| t.blank? }.empty? ?
47 51 { :conditions => { :type => types } } :
... ... @@ -101,4 +105,12 @@ class Category &lt; ActiveRecord::Base
101 105 self.children.find(:all, :conditions => {:display_in_menu => true}).empty?
102 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 116 end
... ...
app/models/change_password.rb
... ... @@ -2,16 +2,19 @@ class ChangePassword &lt; Task
2 2  
3 3 attr_accessor :password, :password_confirmation
4 4  
5   - def self.human_attribute_name(attrib, options = {})
  5 + def self.human_attribute_name_with_customization(attrib, options={})
6 6 case attrib.to_sym
7 7 when :password
8 8 _('Password')
9 9 when :password_confirmation
10 10 _('Password Confirmation')
11 11 else
12   - _(self.superclass.human_attribute_name(attrib))
  12 + _(self.human_attribute_name_without_customization(attrib))
13 13 end
14 14 end
  15 + class << self
  16 + alias_method_chain :human_attribute_name, :customization
  17 + end
15 18  
16 19 validates_presence_of :requestor
17 20  
... ...
app/models/comment.rb
... ... @@ -125,14 +125,17 @@ class Comment &lt; ActiveRecord::Base
125 125 include Noosfero::Plugin::HotSpot
126 126  
127 127 include Spammable
  128 + include CacheCounterHelper
128 129  
129 130 def after_spam!
130 131 SpammerLogger.log(ip_address, self)
131 132 Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_spam))
  133 + update_cache_counter(:spam_comments_count, source, 1) if source.kind_of?(Article)
132 134 end
133 135  
134 136 def after_ham!
135 137 Delayed::Job.enqueue(CommentHandler.new(self.id, :marked_as_ham))
  138 + update_cache_counter(:spam_comments_count, source, -1) if source.kind_of?(Article)
136 139 end
137 140  
138 141 def verify_and_notify
... ...
app/models/community.rb
1 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 4 after_destroy :check_invite_member_for_destroy
5 5  
6 6 def self.type_name
... ... @@ -85,10 +85,6 @@ class Community &lt; Organization
85 85 recent_documents(limit, ["articles.type != ? AND articles.highlighted = ?", 'Folder', highlight])
86 86 end
87 87  
88   - def blocks_to_expire_cache
89   - [MembersBlock]
90   - end
91   -
92 88 def each_member(offset=0)
93 89 while member = self.members.first(:order => :id, :offset => offset)
94 90 yield member
... ...
app/models/domain.rb
... ... @@ -2,7 +2,7 @@ require &#39;noosfero/multi_tenancy&#39;
2 2  
3 3 class Domain < ActiveRecord::Base
4 4  
5   - attr_accessible :name, :owner
  5 + attr_accessible :name, :owner, :is_default
6 6  
7 7 # relationships
8 8 ###############
... ...
app/models/enterprise.rb
... ... @@ -2,6 +2,8 @@
2 2 # only enterprises can offer products and services.
3 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 7 SEARCH_DISPLAYS += %w[map full]
6 8  
7 9 def self.type_name
... ... @@ -23,7 +25,10 @@ class Enterprise &lt; Organization
23 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 27 settings_items :organization_website, :historic_and_current_context, :activities_short_description
  28 +
26 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 33 extend SetProfileRegionFromCityState::ClassMethods
29 34 set_profile_region_from_city_state
... ...
app/models/environment.rb
... ... @@ -3,7 +3,7 @@
3 3 # domains.
4 4 class Environment < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound
  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 8 has_many :users
9 9  
... ... @@ -124,6 +124,7 @@ class Environment &lt; ActiveRecord::Base
124 124 'organizations_are_moderated_by_default' => _("Organizations have moderated publication by default"),
125 125 'enable_organization_url_change' => _("Allow organizations to change their URL"),
126 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 128 'show_balloon_with_profile_links_when_clicked' => _('Show a balloon with profile links when a profile image is clicked'),
128 129 'xmpp_chat' => _('XMPP/Jabber based chat'),
129 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 133 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'),
133 134 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'),
134 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 139 end
138 140  
... ... @@ -175,14 +177,10 @@ class Environment &lt; ActiveRecord::Base
175 177  
176 178 # "left" area
177 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 180 env.boxes[1].blocks << RecentDocumentsBlock.new
182 181  
183 182 # "right" area
184 183 env.boxes[2].blocks << CommunitiesBlock.new(:limit => 6)
185   - env.boxes[2].blocks << PeopleBlock.new(:limit => 6)
186 184 end
187 185  
188 186 # One Environment can be reached by many domains
... ... @@ -287,7 +285,7 @@ class Environment &lt; ActiveRecord::Base
287 285 www.youtube.com
288 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 290 settings_items :search_hints, :type => Hash, :default => {}
293 291  
... ... @@ -298,6 +296,23 @@ class Environment &lt; ActiveRecord::Base
298 296 settings_items :access_control_allow_origin, :type => Array, :default => []
299 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 316 def news_amount_by_folder=(amount)
302 317 settings[:news_amount_by_folder] = amount.to_i
303 318 end
... ... @@ -789,7 +804,7 @@ class Environment &lt; ActiveRecord::Base
789 804 end
790 805  
791 806 def notification_emails
792   - [noreply_email.blank? ? nil : noreply_email].compact + admins.map(&:email)
  807 + [contact_email].select(&:present?) + admins.map(&:email)
793 808 end
794 809  
795 810 after_create :create_templates
... ...
app/models/environment_statistics_block.rb
... ... @@ -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
... ... @@ -30,6 +30,7 @@ class ExternalFeed &lt; ActiveRecord::Base
30 30 article.source = link
31 31 article.profile = blog.profile
32 32 article.parent = blog
  33 + article.author_name = self.feed_title
33 34 unless blog.children.exists?(:slug => article.slug)
34 35 article.save!
35 36 article.delay.create_activity
... ...
app/models/featured_products_block.rb
1 1 class FeaturedProductsBlock < Block
2 2  
  3 + attr_accessible :product_ids, :groups_of, :speed, :reflect
  4 +
3 5 settings_items :product_ids, :type => Array, :default => []
4 6 settings_items :groups_of, :type => :integer, :default => 3
5 7 settings_items :speed, :type => :integer, :default => 1000
... ...
app/models/feed_reader_block.rb
... ... @@ -85,8 +85,4 @@ class FeedReaderBlock &lt; Block
85 85 block_title(title) + formatted_feed_content
86 86 end
87 87  
88   - def editable?
89   - true
90   - end
91   -
92 88 end
... ...
app/models/forum.rb
... ... @@ -3,7 +3,7 @@ class Forum &lt; Folder
3 3 acts_as_having_posts :order => 'updated_at DESC'
4 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 8 settings_items :terms_of_use, :type => :string, :default => ""
9 9 settings_items :has_terms_of_use, :type => :boolean, :default => false
... ...
app/models/friends_block.rb
... ... @@ -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 15 Friendship.update_cache_counter(:friends_count, friendship.person, -1)
16 16 Friendship.update_cache_counter(:friends_count, friendship.friend, -1)
17 17 end
  18 +
  19 + def self.remove_friendship(person1, person2)
  20 + person1.remove_friend(person2)
  21 + person2.remove_friend(person1)
  22 + end
18 23 end
... ...
app/models/highlights_block.rb
1 1 class HighlightsBlock < Block
2 2  
3   - attr_accessible :images
  3 + attr_accessible :images, :interval, :shuffle, :navigation
4 4  
5 5 settings_items :images, :type => Array, :default => []
6 6 settings_items :interval, :type => 'integer', :default => 4
... ...
app/models/image.rb
... ... @@ -25,4 +25,7 @@ class Image &lt; ActiveRecord::Base
25 25  
26 26 attr_accessible :uploaded_data
27 27  
  28 + def current_data
  29 + File.file?(full_filename) ? File.read(full_filename) : nil
  30 + end
28 31 end
... ...
app/models/input.rb
1 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 5 belongs_to :product
6 6 belongs_to :product_category
... ...
app/models/link_list_block.rb
... ... @@ -84,10 +84,6 @@ class LinkListBlock &lt; Block
84 84 end
85 85 end
86 86  
87   - def editable?
88   - true
89   - end
90   -
91 87 def icons_options
92 88 ICONS.map do |i|
93 89 "<span title=\"#{i[1]}\" class=\"icon-#{i[0]}\" onclick=\"changeIcon(this, '#{i[0]}')\"></span>".html_safe
... ...
app/models/location_block.rb
1 1 class LocationBlock < Block
2 2  
  3 + attr_accessible :zoom, :map_type
  4 +
3 5 settings_items :zoom, :type => :integer, :default => 4
4 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 16 true
17 17 end
18 18  
19   - def editable?
20   - true
21   - end
22   -
23 19 def cacheable?
24 20 false
25 21 end
... ...
app/models/members_block.rb
... ... @@ -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 @@
  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 60 \ No newline at end of file
... ...
app/models/organization.rb
... ... @@ -123,7 +123,7 @@ class Organization &lt; Profile
123 123 [
124 124 [MainBlock.new],
125 125 [ProfileImageBlock.new, LinkListBlock.new(:links => links)],
126   - [MembersBlock.new, RecentDocumentsBlock.new]
  126 + [RecentDocumentsBlock.new]
127 127 ]
128 128 end
129 129  
... ... @@ -135,7 +135,11 @@ class Organization &lt; Profile
135 135 end
136 136  
137 137 def notification_emails
138   - [contact_email.blank? ? nil : contact_email].compact + admins.map(&:email)
  138 + emails = [contact_email].select(&:present?) + admins.map(&:email)
  139 + if emails.empty?
  140 + emails << environment.contact_email
  141 + end
  142 + emails
139 143 end
140 144  
141 145 def already_request_membership?(person)
... ...
app/models/people_block.rb
... ... @@ -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 1 # A person is the profile of an user holding all relationships with the rest of the system
2 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 6 SEARCH_FILTERS += %w[
7 7 more_popular
... ... @@ -269,7 +269,7 @@ class Person &lt; Profile
269 269 [
270 270 [MainBlock.new],
271 271 [ProfileImageBlock.new(:show_name => true), LinkListBlock.new(:links => links), RecentDocumentsBlock.new],
272   - [FriendsBlock.new, CommunitiesBlock.new]
  272 + [CommunitiesBlock.new]
273 273 ]
274 274 end
275 275  
... ...
app/models/person_notifier.rb
... ... @@ -82,7 +82,7 @@ class PersonNotifier
82 82 @url = @profile.environment.top_url
83 83 mail(
84 84 content_type: "text/html",
85   - from: "#{@profile.environment.name} <#{@profile.environment.contact_email}>",
  85 + from: "#{@profile.environment.name} <#{@profile.environment.noreply_email}>",
86 86 to: @profile.email,
87 87 subject: _("[%s] Network Activity") % [@profile.environment.name]
88 88 )
... ...
app/models/product.rb
... ... @@ -11,7 +11,7 @@ class Product &lt; ActiveRecord::Base
11 11  
12 12 SEARCH_DISPLAYS = %w[map full]
13 13  
14   - attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers
  14 + attr_accessible :name, :product_category, :highlighted, :price, :enterprise, :image_builder, :description, :available, :qualifiers, :unit_id, :discount, :inputs
15 15  
16 16 def self.default_search_display
17 17 'full'
... ...
app/models/product_categories_block.rb
... ... @@ -17,7 +17,7 @@ class ProductCategoriesBlock &lt; Block
17 17 profile = owner
18 18 proc do
19 19 if @categories.nil? or @categories.length == 0
20   - categories = ProductCategory.on_level().order(:name)
  20 + categories = ProductCategory.on_level(nil).order(:name)
21 21 if @categories and @categories.length == 0
22 22 notice = _('There are no sub-categories for %s') % @category.name
23 23 end
... ... @@ -33,7 +33,7 @@ class ProductCategoriesBlock &lt; Block
33 33 end
34 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 38 def display
39 39 settings[:display].nil? ? 'catalog_only' : super
... ...
app/models/products_block.rb
... ... @@ -49,17 +49,10 @@ class ProductsBlock &lt; Block
49 49  
50 50 def products(reload = false)
51 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 53 else
61   - product_ids.map {|item| owner.products.find(item) }
62   - end
  54 + owner.products.where(:id => product_ids)
  55 + end.compact
63 56 end
64 57  
65 58 end
... ...
app/models/profile.rb
... ... @@ -3,7 +3,7 @@
3 3 # which by default is the one returned by Environment:default.
4 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 8 # use for internationalizable human type names in search facets
9 9 # reimplement on subclasses
... ...
app/models/profile_image_block.rb
... ... @@ -23,10 +23,6 @@ class ProfileImageBlock &lt; Block
23 23 end
24 24 end
25 25  
26   - def editable?
27   - true
28   - end
29   -
30 26 def cacheable?
31 27 false
32 28 end
... ...
app/models/profile_info_block.rb
... ... @@ -15,10 +15,6 @@ class ProfileInfoBlock &lt; Block
15 15 end
16 16 end
17 17  
18   - def editable?
19   - false
20   - end
21   -
22 18 def cacheable?
23 19 false
24 20 end
... ...
app/models/profile_list_block.rb
1 1 class ProfileListBlock < Block
2 2  
3   - attr_accessible :limit, :prioritize_profiles_with_image
  3 + attr_accessible :prioritize_profiles_with_image
4 4  
5 5 settings_items :limit, :type => :integer, :default => 6
6 6 settings_items :prioritize_profiles_with_image, :type => :boolean, :default => true
... ... @@ -18,13 +18,13 @@ class ProfileListBlock &lt; Block
18 18 result = nil
19 19 visible_profiles = profiles.visible.includes([:image,:domains,:preferred_domain,:environment])
20 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 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 26 end
27   - result.slice(0..limit-1)
  27 + result.slice(0..get_limit-1)
28 28 end
29 29  
30 30 def profile_count
... ...
app/models/profile_search_block.rb
... ... @@ -11,8 +11,4 @@ class ProfileSearchBlock &lt; Block
11 11 end
12 12 end
13 13  
14   - def editable?
15   - true
16   - end
17   -
18 14 end
... ...
app/models/recent_documents_block.rb
... ... @@ -33,7 +33,7 @@ class RecentDocumentsBlock &lt; Block
33 33 end
34 34  
35 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 37 end
38 38  
39 39 def self.expire_on
... ...
app/models/rss_feed.rb
1 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 5 def self.type_name
6 6 _('RssFeed')
... ...
app/models/slideshow_block.rb
... ... @@ -6,6 +6,8 @@ class SlideshowBlock &lt; Block
6 6 settings_items :navigation, :type => 'boolean', :default => false
7 7 settings_items :image_size, :type => 'string', :default => 'thumb'
8 8  
  9 + attr_accessible :gallery_id, :image_size, :interval, :shuffle, :navigation
  10 +
9 11 def self.description
10 12 _('Slideshow')
11 13 end
... ...
app/models/task.rb
... ... @@ -73,10 +73,6 @@ class Task &lt; ActiveRecord::Base
73 73 end
74 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 76 # this method finished the task. It calls #perform, which must be overriden
81 77 # by subclasses. At the end a message (as returned by #finish_message) is
82 78 # sent to the requestor with #notify_requestor.
... ... @@ -254,6 +250,10 @@ class Task &lt; ActiveRecord::Base
254 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 257 def opened?
258 258 status == Task::Status::ACTIVE || status == Task::Status::HIDDEN
259 259 end
... ...
app/models/user.rb
... ... @@ -6,7 +6,7 @@ require &#39;securerandom&#39;
6 6 # Rails generator.
7 7 class User < ActiveRecord::Base
8 8  
9   - attr_accessible :login, :email, :password, :password_confirmation
  9 + attr_accessible :login, :email, :password, :password_confirmation, :activated_at
10 10  
11 11 N_('Password')
12 12 N_('Password confirmation')
... ... @@ -17,15 +17,18 @@ class User &lt; ActiveRecord::Base
17 17 end
18 18  
19 19 # FIXME ugly workaround
20   - def self.human_attribute_name(attrib, options={})
  20 + def self.human_attribute_name_with_customization(attrib, options={})
21 21 case attrib.to_sym
22 22 when :login
23 23 return [_('Username'), _('Email')].join(' / ')
24 24 when :email
25 25 return _('e-Mail')
26   - else _(self.superclass.human_attribute_name(attrib))
  26 + else _(self.human_attribute_name_without_customization(attrib))
27 27 end
28 28 end
  29 + class << self
  30 + alias_method_chain :human_attribute_name, :customization
  31 + end
29 32  
30 33 before_create do |user|
31 34 if user.environment.nil?
... ... @@ -48,8 +51,12 @@ class User &lt; ActiveRecord::Base
48 51  
49 52 user.person = p
50 53 end
51   - if user.environment.enabled?('skip_new_user_email_confirmation')
52   - user.activate
  54 + if user.environment.enabled?('skip_new_user_email_confirmation')
  55 + if user.environment.enabled?('admin_must_approve_new_users')
  56 + create_moderate_task
  57 + else
  58 + user.activate
  59 + end
53 60 end
54 61 end
55 62 after_create :deliver_activation_code
... ... @@ -64,43 +71,8 @@ class User &lt; ActiveRecord::Base
64 71 self.person.preferred_domain && self.person.preferred_domain.name || self.environment.default_hostname(true)
65 72 end
66 73  
67   - class Mailer < ActionMailer::Base
68   - def activation_email_notify(user)
69   - user_email = "#{user.login}@#{user.email_domain}"
70   - recipients user_email
71   - from "#{user.environment.name} <#{user.environment.noreply_email}>"
72   - subject _("[%{environment}] Welcome to %{environment} mail!") % { :environment => user.environment.name }
73   - body :name => user.name,
74   - :email => user_email,
75   - :webmail => MailConf.webmail_url(user.login, user.email_domain),
76   - :environment => user.environment.name,
77   - :url => url_for(:host => user.environment.default_hostname, :controller => 'home')
78   - end
79   -
80   - def activation_code(user)
81   - recipients user.email
82   -
83   - from "#{user.environment.name} <#{user.environment.noreply_email}>"
84   - subject _("[%s] Activate your account") % [user.environment.name]
85   - body :recipient => user.name,
86   - :activation_code => user.activation_code,
87   - :environment => user.environment.name,
88   - :url => user.environment.top_url,
89   - :redirection => (true if user.return_to)
90   - end
91   -
92   - def signup_welcome_email(user)
93   - email_body = user.environment.signup_welcome_text_body.gsub('{user_name}', user.name)
94   - email_subject = user.environment.signup_welcome_text_subject
95   -
96   - content_type 'text/html'
97   - recipients user.email
98   -
99   - from "#{user.environment.name} <#{user.environment.noreply_email}>"
100   - subject email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject
101   - body email_body
102   - end
103   - end
  74 + # virtual attribute used to stash which community to join on signup or login
  75 + attr_accessor :community_to_join
104 76  
105 77 def signup!
106 78 User.transaction do
... ... @@ -185,6 +157,15 @@ class User &lt; ActiveRecord::Base
185 157 end
186 158 end
187 159  
  160 + def create_moderate_task
  161 + @task = ModerateUserRegistration.new
  162 + @task.user_id = self.id
  163 + @task.name = self.name
  164 + @task.email = self.email
  165 + @task.target = self.environment
  166 + @task.save
  167 + end
  168 +
188 169 def activated?
189 170 self.activation_code.nil? && !self.activated_at.nil?
190 171 end
... ...
app/presenters/image.rb
... ... @@ -11,4 +11,9 @@ class FilePresenter::Image &lt; FilePresenter
11 11 def short_description
12 12 _('Image (%s)') % content_type.split('/')[1].upcase
13 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 19 end
... ...
app/sweepers/friendship_sweeper.rb
... ... @@ -34,8 +34,7 @@ protected
34 34 expire_timeout_fragment(profile.manage_friends_cache_key(:npage => i.to_s))
35 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 38 end
40 39  
41 40 end
... ...
app/sweepers/profile_sweeper.rb
... ... @@ -8,9 +8,6 @@ class ProfileSweeper # &lt; ActiveRecord::Observer
8 8 end
9 9  
10 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 11 end
15 12  
16 13 protected
... ... @@ -31,13 +28,6 @@ protected
31 28 expire_blogs(profile) if profile.organization?
32 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 31 def expire_blogs(profile)
42 32 profile.blogs.select{|b| !b.empty?}.each do |blog|
43 33 pages = blog.posts.count / blog.posts_per_page + 1
... ...
app/views/account/_signup_form.html.erb
... ... @@ -136,8 +136,6 @@
136 136 <script type="text/javascript">
137 137 jQuery(function($) {
138 138  
139   - $('#signup-form #user_login').css('width', 335 - $('#signup-domain').outerWidth());
140   -
141 139 $('#signup-form input[type=text], #signup-form textarea').each(function() {
142 140 $(this).bind('blur', function() {
143 141 if ($(this).val() == '') {
... ...
app/views/account/signup.html.erb
1 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 37 <% else %>
16 38 <h1><%= _('Sign up for %s!') % environment.name %></h1>
17 39 <%= render :partial => 'signup_form' %>
... ...
app/views/admin_panel/_signup_welcome_screen.html.erb 0 → 100644
... ... @@ -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 12 :content => (render :partial => 'terms_of_use', :locals => {:f => f})} %>
13 13 <% tabs << {:title => _('Signup welcome text'), :id => 'signup-welcome-text',
14 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 17 <%= render_tabs(tabs) %>
16 18 <% button_bar do %>
17 19 <%= submit_button(:save, _('Save'), :cancel => {:action => 'index'}) %>
... ...
app/views/blocks/members.html.erb
... ... @@ -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 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 5 <ul>
6 6 <li><%= link_to(_('Homepage'), owner.url, :class => 'url') %></li>
... ... @@ -11,5 +11,5 @@
11 11 </ul>
12 12  
13 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 15 </div>
... ...
app/views/blocks/profile_image.html.erb
... ... @@ -23,6 +23,6 @@
23 23 <% end %>
24 24  
25 25 <div class="profile-info-options">
26   - <%= render :file => view_for_profile_actions(block.owner.class) %>
  26 + <%= render_profile_actions block.owner.class %>
27 27 </div>
28 28 </div><!-- end class="vcard" -->
... ...
app/views/blocks/profile_info.html.erb
... ... @@ -40,7 +40,7 @@
40 40 <% end %>
41 41  
42 42 <div class="profile-info-options">
43   - <%= render :file => view_for_profile_actions(block.owner.class) %>
  43 + <%= render_profile_actions block.owner.class %>
44 44 </div>
45 45  
46 46 </div><!-- end class="vcard" -->
... ...
app/views/blocks/profile_info_actions/_community.html.erb 0 → 100644
... ... @@ -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>
... ...
app/views/blocks/profile_info_actions/_enterprise.html.erb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +<ul>
  2 + <%if logged_in? %>
  3 + <%if !user.favorite_enterprises.include?(profile) %>
  4 + <li><%= link_to content_tag('span', _('Add as favorite')), { :profile => user.identifier, :controller => 'favorite_enterprises', :action => 'add', :id => profile.id }, :class => 'button with-text icon-add', :title => _('Add enterprise as favorite') %></li>
  5 + <% end %>
  6 + <% end %>
  7 + <% if profile.enable_contact? %>
  8 + <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button', :class => 'button with-text icon-menu-mail'} %> </li>
  9 + <% end %>
  10 +
  11 + <li><%= report_abuse(profile, :button) %></li>
  12 +</ul>
... ...
app/views/blocks/profile_info_actions/_organization.html.erb 0 → 100644
app/views/blocks/profile_info_actions/_person.html.erb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +<ul>
  2 + <%if logged_in? && (user != profile) %>
  3 +
  4 + <% if !user.already_request_friendship?(profile) and !user.is_a_friend?(profile) %>
  5 + <li>
  6 + <%= button(:add, content_tag('span', _('Add friend')), profile.add_url, :class => 'add-friend', :title => _("Add friend"), :style => 'position: relative;') %>
  7 + </li>
  8 + <% end %>
  9 +
  10 + <% if user.is_a_friend?(profile) && profile.enable_contact? %>
  11 + <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> </li>
  12 + <% end %>
  13 +
  14 + <li><%= report_abuse(profile, :button) %></li>
  15 + <% end %>
  16 +</ul>
... ...
app/views/blocks/profile_info_actions/community.html.erb
... ... @@ -1,20 +0,0 @@
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>
app/views/blocks/profile_info_actions/enterprise.html.erb
... ... @@ -1,12 +0,0 @@
1   -<ul>
2   - <%if logged_in? %>
3   - <%if !user.favorite_enterprises.include?(profile) %>
4   - <li><%= link_to content_tag('span', _('Add as favorite')), { :profile => user.identifier, :controller => 'favorite_enterprises', :action => 'add', :id => profile.id }, :class => 'button with-text icon-add', :title => _('Add enterprise as favorite') %></li>
5   - <% end %>
6   - <% end %>
7   - <% if profile.enable_contact? %>
8   - <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, {:id => 'enterprise-contact-button', :class => 'button with-text icon-menu-mail'} %> </li>
9   - <% end %>
10   -
11   - <li><%= report_abuse(profile, :button) %></li>
12   -</ul>
app/views/blocks/profile_info_actions/organization.html.erb
app/views/blocks/profile_info_actions/person.html.erb
... ... @@ -1,16 +0,0 @@
1   -<ul>
2   - <%if logged_in? && (user != profile) %>
3   -
4   - <% if !user.already_request_friendship?(profile) and !user.is_a_friend?(profile) %>
5   - <li>
6   - <%= button(:add, content_tag('span', _('Add friend')), profile.add_url, :class => 'add-friend', :title => _("Add friend"), :style => 'position: relative;') %>
7   - </li>
8   - <% end %>
9   -
10   - <% if user.is_a_friend?(profile) && profile.enable_contact? %>
11   - <li> <%= link_to content_tag('span', _('Send an e-mail')), {:profile => profile.identifier, :controller => 'contact', :action => 'new'}, :class => 'button with-text icon-menu-mail' %> </li>
12   - <% end %>
13   -
14   - <li><%= report_abuse(profile, :button) %></li>
15   - <% end %>
16   -</ul>