Commit 0597ba647dea607c57995d35704733985e0716c9

Authored by Junior Silva
2 parents 79890fca 35d7a6af

Merge remote-tracking branch 'danifeitosa/AI2822-fixes' into article-version

Conflicts:
	app/controllers/public/content_viewer_controller.rb
	db/schema.rb
Showing 394 changed files with 129835 additions and 114635 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 394 files displayed.

... ... @@ -1,214 +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   -Alessandro Palmeira <alessandro.palmeira@gmail.com>
11   -Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>
12   -Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>
13   -Alessandro Palmeira + Caio Salgado <caio.csalgado@gmail.com>
14   -Alessandro Palmeira + Caio Salgado + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
15   -Alessandro Palmeira + Carlos Morais <alessandro.palmeira@gmail.com>
16   -Alessandro Palmeira + Daniel Alves <alessandro.palmeira@gmail.com>
17   -Alessandro Palmeira + Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
18   -Alessandro Palmeira + Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
19   -Alessandro Palmeira + Diego Araujo <alessandro.palmeira@gmail.com>
20   -Alessandro Palmeira + Diego Araújo <alessandro.palmeira@gmail.com>
21   -Alessandro Palmeira + Diego Araujo + Daniela Feitosa <alessandro.palmeira@gmail.com>
22   -Alessandro Palmeira + Diego Araujo <diegoamc90@gmail.com>
23   -Alessandro Palmeira + Diego Araújo <diegoamc90@gmail.com>
24   -Alessandro Palmeira + Diego Araujo + Eduardo Morais <alessandro.palmeira@gmail.com>
25   -Alessandro Palmeira + Diego Araújo + João M. M. da Silva <alessandro.palmeira@gmail.com>
26   -Alessandro Palmeira + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
27   -Alessandro Palmeira + Diego Araujo + João M. M. da Silva + Paulo Meirelles <alessandro.palmeira@gmail.com>
28   -Alessandro Palmeira + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
29   -Alessandro Palmeira + Diego Araújo + Pedro Leal + João M. M. da Silva <diegoamc90@gmail.com>
30   -Alessandro Palmeira + Diego Araujo + Rafael Manzo <alessandro.palmeira@gmail.com>
31   -Alessandro Palmeira + Eduardo Morais <alessandro.palmeira@gmail.com>
32   -Alessandro Palmeira + Guilherme Rojas <alessandro.palmeira@gmail.com>
33   -Alessandro Palmeira + Jefferson Fernandes <alessandro.palmeira@gmail.com>
34   -Alessandro Palmeira + João M. M. da Silva <alessandro.palmeira@gmail.com>
35   -Alessandro Palmeira + Joao M. M. da Silva + Diego Araujo <alessandro.palmeira@gmail.com>
36   -Alessandro Palmeira + João M. M. da Silva + Renan Teruo <alessandro.palmeira@gmail.com>
37   -Alessandro Palmeira + João M. M. Silva <alessandro.palmeira@gmail.com>
38   -Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
39   -Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
40   -Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
41   -Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
42   -Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
43   -Antonio Terceiro <terceiro@colivre.coop.br>
44   -Aurelio A. Heckert <aurelio@colivre.coop.br>
45   -Braulio Bhavamitra <brauliobo@gmail.com>
46   -Bráulio Bhavamitra <brauliobo@gmail.com>
47   -Braulio Bhavamitra <braulio@eita.org.br>
48   -Caio <caio.csalgado@gmail.com>
49   -Caio + Diego + Pedro + João <caio.csalgado@gmail.com>
50   -Caio Formiga <caio.formiga@gmail.com>
51   -Caio, Pedro <caio.csalgado@gmail.com>
52   -Caio Salgado + Alessandro Palmeira <caio.csalgado@gmail.com>
53   -Caio Salgado <caio.csalgado@gmail.com>
54   -Caio Salgado + Carlos Morais + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
55   -Caio Salgado + Diego Araujo <caio.csalgado@gmail.com>
56   -Caio Salgado + Diego Araújo <caio.csalgado@gmail.com>
57   -Caio Salgado + Diego Araújo <diegoamc90@gmail.com>
58   -Caio Salgado + Diego Araújo + Jefferson Fernandes <caio.csalgado@gmail.com>
59   -Caio Salgado + Diego Araújo + João M. M. da Silva <caio.csalgado@gmail.com>
60   -Caio Salgado + Diego Araújo + Pedro Leal <caio.csalgado@gmail.com>
61   -Caio Salgado + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
62   -Caio Salgado + Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
63   -Caio Salgado + Jefferson Fernandes <caio.csalgado@gmail.com>
64   -Caio Salgado + Jefferson Fernandes <jeffs.fernandes@gmail.com>
65   -Caio Salgado + Rafael Manzo <caio.csalgado@gmail.com>
66   -Caio Salgado + Renan Teruo <caio.csalgado@gmail.com>
67   -Caio Salgado + Renan Teruo <caio.salgado@gmail.com>
68   -Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
69   -Caio Salgado + Renan Teruo <renanteruoc@gmail.com>
70   -Caio SBA <caio@colivre.coop.br>
71   -Carlos Morais <carlos88morais@gmail.com>
72   -Carlos Morais + Diego Araújo <diegoamc90@gmail.com>
73   -Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
74   -Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
75   -Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
76   -Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
77   -Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
78   -Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
79   -Daniel Alves + Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
80   -Daniel Alves + Diego Araújo + Guilherme Rojas <guilhermehrojas@gmail.com>
81   -Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>
82   -Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
83   -Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
84   -Daniel Cunha <daniel@colivre.coop.br>
85   -diegoamc <diegoamc90@gmail.com>
86   -Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
87   -Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>
88   -Diego Araújo + Alessandro Palmeira + Rafael Manzo <rr.manzo@gmail.com>
89   -Diego Araujo + Caio Salgado <diegoamc90@gmail.com>
90   -Diego Araújo + Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
91   -Diego Araújo <diegoamc90@gmail.com>
92   -Diego Araújo + Eduardo Morais + Paulo Meirelles <diegoamc90@gmail.com>
93   -Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
94   -Diego Araújo + Jefferson Fernandes <diegoamc90@gmail.com>
95   -Diego Araujo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
96   -Diego Araújo + João Machini <diegoamc90@gmail.com>
97   -Diego Araújo + João Machini <digoamc90@gmail.com>
98   -Diego Araújo + João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
99   -Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
100   -Diego Araújo + João M. M. da Silva + João Machini <diegoamc90@gmail.com>
101   -Diego Araújo + João M. M. da Silva + Pedro Leal <diegoamc90@gmail.com>
102   -Diego Araújo + Paulo Meirelles <diegoamc90@gmail.com>
103   -Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
104   -Diego Araujo + Rafael Manzo <diegoamc90@gmail.com>
105   -Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
106   -Diego Araújo + Renan Teruo + Alessandro Palmeira <diegoamc90@gmail.com>
107   -Diego Araújo + Renan Teruo <diegoamc90@gmail.com>
108   -Diego Araujo + Rodrigo Souto + Rafael Manzo <rr.manzo@gmail.com>
109   -Diego + Jefferson <diegoamc90@gmail.com>
110   -Diego Martinez <diegoamc90@gmail.com>
111   -Diego Martinez <diego@diego-K55A.(none)>
112   -Diego + Renan <renanteruoc@gmail.com>
113   -Fernanda Lopes <nanda.listas+psl@gmail.com>
114   -Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>
115   -Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)>
116   -Grazieno Pellegrino <grazieno@gmail.com>
117   -Isaac Canan <isaac@intelletto.com.br>
118   -Italo Valcy <italo@dcc.ufba.br>
119   -Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
120   -Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
121   -Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>
122   -João da Silva <jaodsilv@linux.ime.usp.br>
123   -João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
124   -João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br>
125   -João M. M. da Silva + Alessandro Palmeira + Diego Araújo <jaodsilv@linux.ime.usp.br>
126   -Joao M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
127   -João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
128   -João M. M. da Silva + Alessandro Palmeira + João Machini <jaodsilv@linux.ime.usp.br>
129   -João M. M. da Silva + Caio Salgado + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
130   -João M. M. da Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>
131   -João M. M. da Silva + Carlos Morais <jaodsilv@linux.ime.usp.br>
132   -João M. M. da Silva + Diego Araújo <diegoamc90@gmail.com>
133   -João M. M. da Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>
134   -João M. M. da Silva + Diego Araújo + Pedro Leal <jaodsilv@linux.ime.usp.br>
135   -João M. M. da Silva <jaodsilv@linux.ime.usp.br>
136   -Joao M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
137   -João M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
138   -João M. M. da Silva + João M. Miranda <jaodsilv@linux.ime.usp.br>
139   -João M. M. da Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>
140   -João M. M. da Silva + Pedro Leal <jaodsilv@linux.ime.usp.br>
141   -João M. M. da Silva + Rafael Manzo + Diego Araújo <jaodsilv@linux.ime.usp.br>
142   -João M. M. da Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>
143   -João M. M. da Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
144   -João M. M. Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>
145   -João M. M. Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>
146   -Joao M. M. Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
147   -João M. M. Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>
148   -João M. M. Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>
149   -João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
150   -Joenio Costa <joenio@colivre.coop.br>
151   -Josef Spillner <josef.spillner@tu-dresden.de>
152   -Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>
153   -Keilla Menezes <keilla@colivre.coop.br>
154   -Larissa Reis <larissa@colivre.coop.br>
155   -Larissa Reis <reiss.larissa@gmail.com>
156   -Leandro Nunes dos Santos <leandronunes@gmail.com>
157   -Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>
158   -LinguÁgil 2010 <linguagil.bahia@gmail.com>
159   -Lucas Melo <lucas@colivre.coop.br>
160   -Lucas Melo <lucaspradomelo@gmail.com>
161   -Luis David Aguilar Carlos <ludwig9003@gmail.com>
162   -Martín Olivera <molivera@solar.org.ar>
163   -Moises Machado <moises@colivre.coop.br>
164   -Nanda Lopes <nanda.listas+psl@gmail.com>
165   -Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>
166   -Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>
167   -Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>
168   -Paulo Meirelles + Diego Araújo <paulo@softwarelivre.org>
169   -Paulo Meirelles + João M. M. da Silva <paulo@softwarelivre.org>
170   -Paulo Meirelles <paulo@softwarelivre.org>
171   -Paulo Meirelles + Rafael Manzo <paulo@softwarelivre.org>
172   -Rafael Gomes <rafaelgomes@techfree.com.br>
173   -Rafael Manzo + Alessandro Palmeira <rr.manzo@gmail.com>
174   -Rafael Manzo + Daniel Alves <danpaulalves@gmail.com>
175   -Rafael Manzo + Diego Araújo <rr.manzo@gmail.com>
176   -Rafael Manzo + João M. M. Silva <rr.manzo@gmail.com>
177   -Rafael Manzo + Paulo Meirelles <rr.manzo@gmail.com>
178   -Rafael Martins <rmmartins@gmail.com>
179   -Rafael Reggiani Manzo + Caio Salgado + Jefferson Fernandes <rr.manzo@gmail.com>
180   -Rafael Reggiani Manzo + Diego Araujo <diegoamc90@gmail.com>
181   -Rafael Reggiani Manzo + Diego Araujo <rr.manzo@gmail.com>
182   -Rafael Reggiani Manzo + Diego Araújo <rr.manzo@gmail.com>
183   -Rafael Reggiani Manzo + João M. M. da Silva <rr.manzo@gmail.com>
184   -Rafael Reggiani Manzo <rr.manzo@gmail.com>
185   -Raphaël Rousseau <raph@r4f.org>
186   -Raquel Lira <raquel.lira@gmail.com>
187   -Renan Teruo + Caio Salgado <renanteruoc@gmail.com>
188   -Renan Teruoc + Diego Araujo <renanteruoc@gmail.com>
189   -Renan Teruo + Diego Araujo <renanteruoc@gmail.com>
190   -Renan Teruo + Diego Araújo <renanteruoc@gmail.com>
191   -Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
192   -Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
193   -Rodrigo Souto <diguliu@gmail.com>
194   -Rodrigo Souto <rodrigo@colivre.coop.br>
195   -Ronny Kursawe <kursawe.ronny@googlemail.com>
196   -root <root@debian.sdr.serpro>
197   -Samuel R. C. Vale <srcvale@holoscopio.com>
198   -Valessio Brito <valessio@gmail.com>
199   -vfcosta <vfcosta@gmail.com>
200   -Vinicius Cubas Brand <viniciuscb@gmail.com>
201   -Visita <visita@debian.(none)>
202   -Yann Lugrin <yann.lugrin@liquid-concept.ch>
203   -
204   -Ideas, specifications and incentive
205   -===================================
206   -Daniel Tygel <dtygel@fbes.org.br>
207   -Guilherme Rocha <guilherme@gf7.com.br>
208   -Raphael Rousseau <raph@r4f.org>
209   -Théo Bondolfi <move@cooperation.net>
210   -Vicente Aguiar <vicenteaguiar@colivre.coop.br>
211   -
212   -Arts
213   -===================================
214   -Nara Oliveira <narananet@gmail.com>
AUTHORS.md 0 → 100644
... ... @@ -0,0 +1,214 @@
  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).
  2 +
  3 +Developers
  4 +==========
  5 +
  6 +Alan Freihof Tygel <alantygel@gmail.com>
  7 +Alessandro Palmeira <alessandro.palmeira@gmail.com>
  8 +Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>
  9 +Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>
  10 +Alessandro Palmeira + Caio Salgado <caio.csalgado@gmail.com>
  11 +Alessandro Palmeira + Caio Salgado + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
  12 +Alessandro Palmeira + Carlos Morais <alessandro.palmeira@gmail.com>
  13 +Alessandro Palmeira + Daniel Alves <alessandro.palmeira@gmail.com>
  14 +Alessandro Palmeira + Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
  15 +Alessandro Palmeira + Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
  16 +Alessandro Palmeira + Diego Araujo <alessandro.palmeira@gmail.com>
  17 +Alessandro Palmeira + Diego Araújo <alessandro.palmeira@gmail.com>
  18 +Alessandro Palmeira + Diego Araujo + Daniela Feitosa <alessandro.palmeira@gmail.com>
  19 +Alessandro Palmeira + Diego Araujo <diegoamc90@gmail.com>
  20 +Alessandro Palmeira + Diego Araújo <diegoamc90@gmail.com>
  21 +Alessandro Palmeira + Diego Araujo + Eduardo Morais <alessandro.palmeira@gmail.com>
  22 +Alessandro Palmeira + Diego Araújo + João M. M. da Silva <alessandro.palmeira@gmail.com>
  23 +Alessandro Palmeira + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
  24 +Alessandro Palmeira + Diego Araujo + João M. M. da Silva + Paulo Meirelles <alessandro.palmeira@gmail.com>
  25 +Alessandro Palmeira + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
  26 +Alessandro Palmeira + Diego Araújo + Pedro Leal + João M. M. da Silva <diegoamc90@gmail.com>
  27 +Alessandro Palmeira + Diego Araujo + Rafael Manzo <alessandro.palmeira@gmail.com>
  28 +Alessandro Palmeira + Eduardo Morais <alessandro.palmeira@gmail.com>
  29 +Alessandro Palmeira + Guilherme Rojas <alessandro.palmeira@gmail.com>
  30 +Alessandro Palmeira + Jefferson Fernandes <alessandro.palmeira@gmail.com>
  31 +Alessandro Palmeira + João M. M. da Silva <alessandro.palmeira@gmail.com>
  32 +Alessandro Palmeira + Joao M. M. da Silva + Diego Araujo <alessandro.palmeira@gmail.com>
  33 +Alessandro Palmeira + João M. M. da Silva + Renan Teruo <alessandro.palmeira@gmail.com>
  34 +Alessandro Palmeira + João M. M. Silva <alessandro.palmeira@gmail.com>
  35 +Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
  36 +Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
  37 +Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
  38 +Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
  39 +Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
  40 +Antonio Terceiro <terceiro@colivre.coop.br>
  41 +Aurelio A. Heckert <aurelio@colivre.coop.br>
  42 +Braulio Bhavamitra <brauliobo@gmail.com>
  43 +Bráulio Bhavamitra <brauliobo@gmail.com>
  44 +Braulio Bhavamitra <braulio@eita.org.br>
  45 +Caio <caio.csalgado@gmail.com>
  46 +Caio + Diego + Pedro + João <caio.csalgado@gmail.com>
  47 +Caio Formiga <caio.formiga@gmail.com>
  48 +Caio, Pedro <caio.csalgado@gmail.com>
  49 +Caio Salgado + Alessandro Palmeira <caio.csalgado@gmail.com>
  50 +Caio Salgado <caio.csalgado@gmail.com>
  51 +Caio Salgado + Carlos Morais + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
  52 +Caio Salgado + Diego Araujo <caio.csalgado@gmail.com>
  53 +Caio Salgado + Diego Araújo <caio.csalgado@gmail.com>
  54 +Caio Salgado + Diego Araújo <diegoamc90@gmail.com>
  55 +Caio Salgado + Diego Araújo + Jefferson Fernandes <caio.csalgado@gmail.com>
  56 +Caio Salgado + Diego Araújo + João M. M. da Silva <caio.csalgado@gmail.com>
  57 +Caio Salgado + Diego Araújo + Pedro Leal <caio.csalgado@gmail.com>
  58 +Caio Salgado + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
  59 +Caio Salgado + Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
  60 +Caio Salgado + Jefferson Fernandes <caio.csalgado@gmail.com>
  61 +Caio Salgado + Jefferson Fernandes <jeffs.fernandes@gmail.com>
  62 +Caio Salgado + Rafael Manzo <caio.csalgado@gmail.com>
  63 +Caio Salgado + Renan Teruo <caio.csalgado@gmail.com>
  64 +Caio Salgado + Renan Teruo <caio.salgado@gmail.com>
  65 +Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
  66 +Caio Salgado + Renan Teruo <renanteruoc@gmail.com>
  67 +Caio SBA <caio@colivre.coop.br>
  68 +Carlos Morais <carlos88morais@gmail.com>
  69 +Carlos Morais + Diego Araújo <diegoamc90@gmail.com>
  70 +Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
  71 +Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
  72 +Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
  73 +Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
  74 +Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
  75 +Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
  76 +Daniel Alves + Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
  77 +Daniel Alves + Diego Araújo + Guilherme Rojas <guilhermehrojas@gmail.com>
  78 +Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>
  79 +Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
  80 +Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
  81 +Daniel Cunha <daniel@colivre.coop.br>
  82 +diegoamc <diegoamc90@gmail.com>
  83 +Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
  84 +Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>
  85 +Diego Araújo + Alessandro Palmeira + Rafael Manzo <rr.manzo@gmail.com>
  86 +Diego Araujo + Caio Salgado <diegoamc90@gmail.com>
  87 +Diego Araújo + Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
  88 +Diego Araújo <diegoamc90@gmail.com>
  89 +Diego Araújo + Eduardo Morais + Paulo Meirelles <diegoamc90@gmail.com>
  90 +Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
  91 +Diego Araújo + Jefferson Fernandes <diegoamc90@gmail.com>
  92 +Diego Araujo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
  93 +Diego Araújo + João Machini <diegoamc90@gmail.com>
  94 +Diego Araújo + João Machini <digoamc90@gmail.com>
  95 +Diego Araújo + João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
  96 +Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
  97 +Diego Araújo + João M. M. da Silva + João Machini <diegoamc90@gmail.com>
  98 +Diego Araújo + João M. M. da Silva + Pedro Leal <diegoamc90@gmail.com>
  99 +Diego Araújo + Paulo Meirelles <diegoamc90@gmail.com>
  100 +Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
  101 +Diego Araujo + Rafael Manzo <diegoamc90@gmail.com>
  102 +Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
  103 +Diego Araújo + Renan Teruo + Alessandro Palmeira <diegoamc90@gmail.com>
  104 +Diego Araújo + Renan Teruo <diegoamc90@gmail.com>
  105 +Diego Araujo + Rodrigo Souto + Rafael Manzo <rr.manzo@gmail.com>
  106 +Diego + Jefferson <diegoamc90@gmail.com>
  107 +Diego Martinez <diegoamc90@gmail.com>
  108 +Diego Martinez <diego@diego-K55A.(none)>
  109 +Diego + Renan <renanteruoc@gmail.com>
  110 +Fernanda Lopes <nanda.listas+psl@gmail.com>
  111 +Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>
  112 +Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)>
  113 +Grazieno Pellegrino <grazieno@gmail.com>
  114 +Isaac Canan <isaac@intelletto.com.br>
  115 +Italo Valcy <italo@dcc.ufba.br>
  116 +Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
  117 +Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
  118 +Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>
  119 +João da Silva <jaodsilv@linux.ime.usp.br>
  120 +João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
  121 +João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br>
  122 +João M. M. da Silva + Alessandro Palmeira + Diego Araújo <jaodsilv@linux.ime.usp.br>
  123 +Joao M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
  124 +João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
  125 +João M. M. da Silva + Alessandro Palmeira + João Machini <jaodsilv@linux.ime.usp.br>
  126 +João M. M. da Silva + Caio Salgado + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
  127 +João M. M. da Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>
  128 +João M. M. da Silva + Carlos Morais <jaodsilv@linux.ime.usp.br>
  129 +João M. M. da Silva + Diego Araújo <diegoamc90@gmail.com>
  130 +João M. M. da Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>
  131 +João M. M. da Silva + Diego Araújo + Pedro Leal <jaodsilv@linux.ime.usp.br>
  132 +João M. M. da Silva <jaodsilv@linux.ime.usp.br>
  133 +Joao M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
  134 +João M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
  135 +João M. M. da Silva + João M. Miranda <jaodsilv@linux.ime.usp.br>
  136 +João M. M. da Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>
  137 +João M. M. da Silva + Pedro Leal <jaodsilv@linux.ime.usp.br>
  138 +João M. M. da Silva + Rafael Manzo + Diego Araújo <jaodsilv@linux.ime.usp.br>
  139 +João M. M. da Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>
  140 +João M. M. da Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
  141 +João M. M. Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>
  142 +João M. M. Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>
  143 +Joao M. M. Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
  144 +João M. M. Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>
  145 +João M. M. Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>
  146 +João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
  147 +Joenio Costa <joenio@colivre.coop.br>
  148 +Josef Spillner <josef.spillner@tu-dresden.de>
  149 +Junior Silva <juniorsilva1001@gmail.com>
  150 +Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>
  151 +Keilla Menezes <keilla@colivre.coop.br>
  152 +Larissa Reis <larissa@colivre.coop.br>
  153 +Larissa Reis <reiss.larissa@gmail.com>
  154 +Leandro Nunes dos Santos <leandronunes@gmail.com>
  155 +Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>
  156 +LinguÁgil 2010 <linguagil.bahia@gmail.com>
  157 +Lucas Melo <lucas@colivre.coop.br>
  158 +Lucas Melo <lucaspradomelo@gmail.com>
  159 +Luis David Aguilar Carlos <ludwig9003@gmail.com>
  160 +Martín Olivera <molivera@solar.org.ar>
  161 +Moises Machado <moises@colivre.coop.br>
  162 +Naíla Alves <naila@colivre.coop.br>
  163 +Nanda Lopes <nanda.listas+psl@gmail.com>
  164 +Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>
  165 +Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>
  166 +Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>
  167 +Paulo Meirelles + Diego Araújo <paulo@softwarelivre.org>
  168 +Paulo Meirelles + João M. M. da Silva <paulo@softwarelivre.org>
  169 +Paulo Meirelles <paulo@softwarelivre.org>
  170 +Paulo Meirelles + Rafael Manzo <paulo@softwarelivre.org>
  171 +Rafael Gomes <rafaelgomes@techfree.com.br>
  172 +Rafael Manzo + Alessandro Palmeira <rr.manzo@gmail.com>
  173 +Rafael Manzo + Daniel Alves <danpaulalves@gmail.com>
  174 +Rafael Manzo + Diego Araújo <rr.manzo@gmail.com>
  175 +Rafael Manzo + João M. M. Silva <rr.manzo@gmail.com>
  176 +Rafael Manzo + Paulo Meirelles <rr.manzo@gmail.com>
  177 +Rafael Martins <rmmartins@gmail.com>
  178 +Rafael Reggiani Manzo + Caio Salgado + Jefferson Fernandes <rr.manzo@gmail.com>
  179 +Rafael Reggiani Manzo + Diego Araujo <diegoamc90@gmail.com>
  180 +Rafael Reggiani Manzo + Diego Araujo <rr.manzo@gmail.com>
  181 +Rafael Reggiani Manzo + Diego Araújo <rr.manzo@gmail.com>
  182 +Rafael Reggiani Manzo + João M. M. da Silva <rr.manzo@gmail.com>
  183 +Rafael Reggiani Manzo <rr.manzo@gmail.com>
  184 +Raphaël Rousseau <raph@r4f.org>
  185 +Raquel Lira <raquel.lira@gmail.com>
  186 +Renan Teruo + Caio Salgado <renanteruoc@gmail.com>
  187 +Renan Teruoc + Diego Araujo <renanteruoc@gmail.com>
  188 +Renan Teruo + Diego Araujo <renanteruoc@gmail.com>
  189 +Renan Teruo + Diego Araújo <renanteruoc@gmail.com>
  190 +Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
  191 +Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
  192 +Rodrigo Souto <diguliu@gmail.com>
  193 +Rodrigo Souto <rodrigo@colivre.coop.br>
  194 +Ronny Kursawe <kursawe.ronny@googlemail.com>
  195 +root <root@debian.sdr.serpro>
  196 +Samuel R. C. Vale <srcvale@holoscopio.com>
  197 +Valessio Brito <valessio@gmail.com>
  198 +vfcosta <vfcosta@gmail.com>
  199 +Victor Costa <vfcosta@gmail.com>
  200 +Vinicius Cubas Brand <viniciuscb@gmail.com>
  201 +Visita <visita@debian.(none)>
  202 +Yann Lugrin <yann.lugrin@liquid-concept.ch>
  203 +
  204 +Ideas, specifications and incentive
  205 +===================================
  206 +Daniel Tygel <dtygel@fbes.org.br>
  207 +Guilherme Rocha <guilherme@gf7.com.br>
  208 +Raphael Rousseau <raph@r4f.org>
  209 +Théo Bondolfi <move@cooperation.net>
  210 +Vicente Aguiar <vicenteaguiar@colivre.coop.br>
  211 +
  212 +Arts
  213 +===================================
  214 +Nara Oliveira <narananet@gmail.com>
... ...
... ... @@ -1,63 +0,0 @@
1   -= Noosfero instructions for developers
2   -
3   -== A work about your the development platform
4   -
5   -These instructions are tested and known to work on Debian stable, which is the
6   -system that the Noosfero core developers use to work on Noosfero.
7   -
8   -If you want to use another OS, read "Instructions for other systems" below.
9   -
10   -== Instructions for Debian stable
11   -
12   -Download the source code:
13   -
14   - $ git clone git://gitorious.org/noosfero/noosfero.git
15   - $ cd noosfero
16   -
17   -Run the quick start script:
18   -
19   - $ ./script/quick-start
20   -
21   -Now you can execute the development server with:
22   -
23   - $ ./script/development
24   -
25   -You will be able to access Noosfero at http://localhost:3000/
26   -
27   -If you want to use a different port than 3000, pass `-p <PORT>` to
28   -./script/development
29   -
30   -== Instructions for other systems
31   -
32   -On other OS, you have 2 options:
33   -
34   -1) using a chroot or a VM with Debian stable (easier)
35   -
36   -Use a chroot (http://wiki.debian.org/Schroot) or a Virtual Machine (e.g. with
37   -VirtualBox) with a Debian stable system and follow the instructions above for
38   -Debian stable.
39   -
40   -2) Installing dependencies on other OS (harder)
41   -
42   -If you want to setup a development environment in another OS, you can create a
43   -file under script/install-dependencies/, called <OS>-<CODENAME>.sh, which
44   -installed the dependencies for your system. With this script in place,
45   -./script/quick-start will call it at the point of installing the required
46   -packages for Noosfero development.
47   -
48   -You can check script/install-dependencies/debian-squeeze.sh to have an idea of
49   -what kind of stuff that script has to do.
50   -
51   -If you write such script for your own OS, *please* share it with us at the
52   -development mailing list so that we can include it in the official repository.
53   -This way other people using the same OS will have to put less effort to develop
54   -Noosfero.
55   -
56   -== Submitting your changes back
57   -
58   -For now please read:
59   -
60   -- Coding conventions
61   - http://noosfero.org/Development/CodingConventions
62   -- Patch guidelines
63   - http://noosfero.org/Development/PatchGuidelines
HACKING.md 0 → 100644
... ... @@ -0,0 +1,56 @@
  1 +Noosfero instructions for developers
  2 +====================================
  3 +
  4 +A work about your the development platform
  5 +------------------------------------------
  6 +
  7 +These instructions are tested and known to work on Debian stable, which is the system that the Noosfero core developers use to work on Noosfero.
  8 +
  9 +If you want to use another OS, read "Instructions for other systems" below.
  10 +
  11 +Instructions for Debian stable
  12 +------------------------------
  13 +
  14 +Download the source code:
  15 +
  16 + $ git clone https://gitlab.com/noosfero/noosfero.git
  17 + $ cd noosfero
  18 +
  19 +Run the quick start script:
  20 +
  21 + $ ./script/quick-start
  22 +
  23 +Now you can execute the development server with:
  24 +
  25 + $ ./script/development
  26 +
  27 +You will be able to access Noosfero at http://localhost:3000/
  28 +
  29 +If you want to use a different port than 3000, pass `-p <PORT>` to `./script/development`
  30 +
  31 +Instructions for other systems
  32 +------------------------------
  33 +
  34 +On other OS, you have 2 options:
  35 +
  36 +### 1) using a chroot or a VM with Debian stable (easier)
  37 +
  38 +Use a chroot (http://wiki.debian.org/Schroot) or a Virtual Machine (e.g. with VirtualBox) with a Debian stable system and follow the instructions above for Debian stable.
  39 +
  40 +### 2) Installing dependencies on other OS (harder)
  41 +
  42 +If you want to setup a development environment in another OS, you can create a file under `./script/install-dependencies/`, called `<OS>-<CODENAME>.sh`, which installed the dependencies for your system. With this script in place, `./script/quick-start` will call it at the point of installing the required packages for Noosfero development.
  43 +
  44 +You can check `./script/install-dependencies/debian-squeeze.sh` to have an idea of what kind of stuff that script has to do.
  45 +
  46 +If you write such script for your own OS, *please* share it with us at the development mailing list so that we can include it in the official repository. This way other people using the same OS will have to put less effort to develop Noosfero.
  47 +
  48 +Submitting your changes back
  49 +----------------------------
  50 +
  51 +For now please read:
  52 +
  53 +- Coding conventions
  54 + http://noosfero.org/Development/CodingConventions
  55 +- Patch guidelines
  56 + http://noosfero.org/Development/PatchGuidelines
... ...
... ... @@ -1,417 +0,0 @@
1   -= Noosfero installation instructions from source for production environments
2   -
3   -The instructions below can be used for setting up a Noosfero production
4   -environment from the Noosfero sources.
5   -
6   -Before you start installing Noosfero manually, see the information about the
7   -Noosfero Debian package at http://noosfero.org/Development/DebianPackage. Using
8   -the Debian packages on a Debian stable system is the recommended method for
9   -installing production environments.
10   -
11   -If you want to setup a development environment instead of a production one,
12   -stop reading this file right now and read the file HACKING instead.
13   -
14   -For a complete installation guide, please see the following web page:
15   -http://noosfero.org/Development/HowToInstall
16   -
17   -If you have problems with the setup, please feel free to ask questions in the
18   -development mailing list.
19   -
20   -== Requirements
21   -
22   -DISCLAIMER: this installation procedure is tested with Debian stable, which is
23   -currently the only recommended operating system for production usage. It is
24   -possible that you can install it on other systems, and if you do so, please
25   -report it on one of the Noosfero mailing lists, and please send a patch
26   -updating these instructions.
27   -
28   -Noosfero is written in Ruby with the "Rails
29   -framework":http://www.rubyonrails.org, so the process of setting it up is
30   -pretty similar to other Rails applications.
31   -
32   -You need to install some packages Noosfero depends on. On Debian GNU/Linux or
33   -Debian-based systems, all of these packages are available through the Debian
34   -archive. You can install them with the following command:
35   -
36   - # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin tango-icon-theme libhpricot-ruby
37   -
38   -On other systems, they may or may not be available through your regular package
39   -management system. Below are the links to their homepages.
40   -
41   -* Ruby: http://www.ruby-lang.org/
42   -* Rake: http://rake.rubyforge.org/
43   -* po4a: http://po4a.alioth.debian.org/
44   -* Ruby-sqlite3: http://rubyforge.org/projects/sqlite-ruby
45   -* rcov: http://eigenclass.org/hiki/rcov
46   -* RMagick: http://rmagick.rubyforge.org/
47   -* RedCloth: http://redcloth.org/
48   -* will_paginate: http://github.com/mislav/will_paginate/wikis
49   -* iso-codes: http://pkg-isocodes.alioth.debian.org/
50   -* feedparser: http://packages.debian.org/sid/libfeedparser-ruby
51   -* Daemons - http://daemons.rubyforge.org/
52   -* Thin: http://code.macournoyer.com/thin/
53   -* tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library
54   -* Hpricot: http://hpricot.com/
55   -
56   -If you manage to install Noosfero successfully on other systems than Debian,
57   -please feel free to contact the Noosfero development mailing with the
58   -instructions for doing so, and we'll include it here.
59   -
60   -As root user
61   -============
62   -
63   -Install memcached. On Debian:
64   -
65   -# apt-get install memcached
66   -
67   -Study whether you need to raise the ammount of memory it uses for caching,
68   -depending on the demand you expect for your site. If you are going to run a
69   -high-traffic site, you will want to raise the ammount of memory reserved for
70   -caching.
71   -
72   -It is recommended that you run noosfero with its own user account. To create
73   -such an account, please do the following:
74   -
75   -# adduser --system --group noosfero --shell /bin/sh --home /var/lib/noosfero
76   -
77   -(note that you can change the $HOME directory of the user if you wish, here we
78   -are using /var/lib/noosfero)
79   -
80   -The --system option will tell adduser to create a system user, i.e. this user
81   -will not have a password and cannot login to the system directly. To become
82   -this user, you have to use sudo:
83   -
84   -# sudo -u noosfero -i
85   -
86   -or
87   -
88   -# su - noosfero
89   -
90   -As noosfero user
91   -================
92   -
93   -downloading from git
94   ---------------------
95   -
96   -Here we are cloning the noosfero repository from git. Note: you will need to
97   -install git before.
98   -
99   -$ git clone git://gitorious.org/noosfero/noosfero.git current
100   -$ cd current
101   -$ git checkout -b stable origin/stable
102   -
103   -downloading tarball
104   --------------------
105   -
106   -Note: replace 0.39.0 below from the latest stable version.
107   -
108   -$ wget http://noosfero.org/pub/Development/NoosferoVersion00x39x00/noosfero-0.39.0.tar.gz
109   -$ tar -zxvf noosfero-0.39.0.tar.gz
110   -$ ln -s noosfero-0.39.0 current
111   -$ cd current
112   -
113   -Create the thin configuration file:
114   -
115   -$ thin -C config/thin.yml -e production config
116   -
117   -Edit config/thin.yml to suit your needs. Make sure your apache
118   -configuration matches the thin cluster configuration, specially in respect
119   -to the ports and numbers of thin instances.
120   -
121   -Note: currently Noosfero only supports Rails 2.3.5, which is the version in
122   -Debian Squeeze. If you have a Rails version newer than that, Noosfero will
123   -probably not work. You can install Rails 2.3.5 into your Noosfero installation
124   -with the following procedure:
125   -
126   -$ cd /var/lib/noosfero/current/vendor
127   -$ wget http://ftp.de.debian.org/debian/pool/main/r/rails/rails_2.3.5.orig.tar.gz
128   -$ tar xzf rails_2.3.5.orig.tar.gz
129   -$ ln -s rails-2.3.5 rails
130   -
131   -As root user
132   -============
133   -
134   -Setup Noosfero log and tmp directories:
135   -
136   -# cd /var/lib/noosfero/current
137   -# ./etc/init.d/noosfero setup
138   -
139   -Now it's time to setup the database. In this example we are using PostgreSQL,
140   -so if you are planning to use a different database this steps won't apply.
141   -
142   -# apt-get install postgresql libpgsql-ruby
143   -# su postgres -c 'createuser noosfero -S -d -R'
144   -
145   -By default Rails will try to connect on postgresql through 5432 port,
146   -you can check it on /etc/postgresql/8.4/main/postgresql.conf file.
147   -
148   -Restart postgresql:
149   -
150   -# invoke-rc.d postgresql restart
151   -
152   -Noosfero needs a functional e-mail setup to work: the local mail system should
153   -be able to deliver e-mail to the internet, either directly or through an
154   -external SMTP server. Please check the documentation at the INSTALL.email file.
155   -
156   -As noosfero user
157   -================
158   -
159   -Now create the databases:
160   -
161   -$ cd /var/lib/noosfero/current
162   -$ createdb noosfero_production
163   -$ createdb noosfero_development
164   -$ createdb noosfero_test
165   -
166   -The development and test databases are actually optional. If you are creating a
167   -stricly production server, you will probably not need them.
168   -
169   -Now we want to configure Noosfero for accessing the database we just created.
170   -To do that, you can 1) copy config/database.yml.pgsql to config/database.yml,
171   -or create config/database.yml from scratch with the following content:
172   -
173   - production:
174   - adapter: postgresql
175   - encoding: unicode
176   - database: noosfero_production
177   - username: noosfero
178   -
179   -Now, to test the database access, you can fire the Rails database console:
180   -
181   -$ ./script/dbconsole production
182   -
183   -If it connects to your database, then everything is fine. If you got an error
184   -message, then you have to check your database configuration.
185   -
186   -Create the database structure:
187   -
188   -$ RAILS_ENV=production rake db:schema:load
189   -
190   -Compile the translations:
191   -
192   -$ RAILS_ENV=production rake noosfero:translations:compile
193   -
194   -Now we must create some initial data. To create your default environment
195   -(the first one), run the command below:
196   -
197   -$ RAILS_ENV=production ./script/runner 'Environment.create!(:name => "My environment", :is_default => true)'
198   -
199   -(of course, replace "My environment" with your environment's name!)
200   -
201   -And now you have to add the domain name you will be using for your noosfero
202   -site to the list of domains of that default environment you just created:
203   -
204   -$ RAILS_ENV=production ./script/runner "Environment.default.domains << Domain.new(:name => 'your.domain.com')"
205   -
206   -(replace "your.domain.com" with your actual domain name)
207   -
208   -Add at least one user as admin of environment:
209   -
210   -$ RAILS_ENV=production ./script/runner "User.create(:login => 'adminuser', :email => 'admin@example.com', :password => 'admin', :password_confirmation => 'admin', :environment => Environment.default, :activated_at => Time.new)"
211   -
212   -(replace "adminuser", "admin@example.com", "admin" with the login, email
213   -and password of your environment administrator)
214   -
215   -To start the Noosfero application servers:
216   -
217   -$ ./script/production start
218   -
219   -At this point you have a functional Noosfero installation running, the only
220   -thing left is to configure your webserver as a reverse proxy to pass requests
221   -to them.
222   -
223   -
224   -==================
225   -Apache instalation
226   -==================
227   -
228   -# apt-get install apache2
229   -
230   -Apache configuration
231   ---------------------
232   -
233   -First you have to enable the following some apache modules:
234   -
235   - deflate
236   - expires
237   - proxy
238   - proxy_balancer
239   - proxy_http
240   - rewrite
241   -
242   -On Debian GNU/Linux system, these modules can be enabled with the following
243   -command line, as root:
244   -
245   -# a2enmod deflate expires proxy proxy_balancer proxy_http rewrite
246   -
247   -In other systems the way by which you enable apache modules may be different.
248   -
249   -Now with the Apache configuration. You can use the template below, replacing
250   -/var/lib/noosfero/current with the directory in which your noosfero
251   -installation is, your.domain.com with the domain name of your noosfero site.
252   -We are assuming that you are running two thin instances on ports 3000 and
253   -3001. If your setup is different you'll need to adjust <Proxy> section. If you
254   -don't understand something in the configuration, please refer to the apache
255   -documentation.
256   -
257   -Add a file called "mysite" (or whatever name you want to give to your noosfero
258   -site) to /etc/apache2/sites-available with the following content, and customize
259   -as needed (as usual, make sure you replace "your.domain.com" with you actual
260   -domain name, and "/var/lib/noosfero/current" with the directory where Noosfero
261   -is installed):
262   -
263   - <VirtualHost *:80>
264   - ServerName your.domain.com
265   -
266   - DocumentRoot "/var/lib/noosfero/current/public"
267   - <Directory "/var/lib/noosfero/current/public">
268   - Options FollowSymLinks
269   - AllowOverride None
270   - Order Allow,Deny
271   - Allow from all
272   - </Directory>
273   -
274   - RewriteEngine On
275   -
276   - # Rewrite index to check for static index.html
277   - RewriteRule ^/$ /index.html [QSA]
278   -
279   - # Rewrite to check for Rails cached page
280   - RewriteRule ^([^.]+)$ $1.html [QSA]
281   -
282   - RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
283   - RewriteRule ^.*$ balancer://noosfero%{REQUEST_URI} [P,QSA,L]
284   -
285   - ErrorDocument 503 /503.html
286   -
287   - ErrorLog /var/log/apache2/noosfero.log
288   - LogLevel warn
289   - CustomLog /var/log/apache2/noosfero.access.log combined
290   -
291   - Include /var/lib/noosfero/current/etc/noosfero/apache/cache.conf
292   -
293   - </VirtualHost>
294   -
295   - <Proxy balancer://noosfero>
296   - BalancerMember http://127.0.0.1:3000
297   - BalancerMember http://127.0.0.1:3001
298   - Order Allow,Deny
299   - Allow from All
300   - </Proxy>
301   -
302   -The cache.conf file included in the end of the <VirtualHost> section is
303   -important, since it will tell apache to pass expiration and cache headers to
304   -clients so that the site feels faster for users. Do we need to say that using
305   -that configuration is strongly recommended?
306   -
307   -Enable that site with (as root, replace "mysite" with the actual name you gave
308   -to your site configuration):
309   -
310   -# a2ensite mysite
311   -
312   -Now restart your apache server (as root):
313   -
314   -# invoke-rc.d apache2 restart
315   -
316   -
317   -Enabling exception notifications
318   -================================
319   -
320   -This is an optional step. You will need it only if you want to receive e-mail
321   -notifications when some exception occurs on Noosfero.
322   -
323   -First, install this version of the gem.
324   -Others versions may not be compatible with Noosfero:
325   -
326   -# gem install exception_notification -v 1.0.20090728
327   -
328   -You can configure the e-mails that will receive the notifications.
329   -Change the file config/noosfero.yml as the following example, replacing the
330   -e-mails by real ones:
331   -
332   - production:
333   - exception_recipients: [admin@example.com, you@example.com]
334   -
335   -
336   -============
337   -Maintainance
338   -============
339   -
340   -To ease the maintainance, install a symbolic link for the Noosfero startup
341   -script in your server and add it to the system initialization and shutdown
342   -sequences (as root):
343   -
344   -# ln -s /var/lib/noosfero/current/etc/init.d/noosfero /etc/init.d/noosfero
345   -# update-rc.d noosfero defaults
346   - Adding system startup for /etc/init.d/noosfero ...
347   - /etc/rc0.d/K20noosfero -> ../init.d/noosfero
348   - /etc/rc1.d/K20noosfero -> ../init.d/noosfero
349   - /etc/rc6.d/K20noosfero -> ../init.d/noosfero
350   - /etc/rc2.d/S20noosfero -> ../init.d/noosfero
351   - /etc/rc3.d/S20noosfero -> ../init.d/noosfero
352   - /etc/rc4.d/S20noosfero -> ../init.d/noosfero
353   - /etc/rc5.d/S20noosfero -> ../init.d/noosfero
354   -
355   -Now to start Noosfero, you do as root:
356   -
357   -# invoke-rc.d noosfero start
358   -
359   -To stop Noosfero:
360   -
361   -# invoke-rc.d noosfero start
362   -
363   -To restart Noosfero:
364   -
365   -# invoke-rc.d noosfero restart
366   -
367   -Noosfero will be automatically started during system boot, and automatically
368   -stopped if the system shuts down for some reason (or during the shutdown part
369   -of a reboot).
370   -
371   -=============
372   -Rotating logs
373   -=============
374   -
375   -Noosfero provides an example logrotate configuation to rotate its logs. To use
376   -it, create a symbolic link in /etc/logrotate.d/:
377   -
378   -# cd /etc/logrotate.d/
379   -# ln -s /var/lib/noosfero/current/etc/logrotate.d/noosfero
380   -
381   -Note that the provided file assumes Noosfero logging is being done in
382   -/var/log/noosfero (which is the case if you followed the instructions above
383   -correctly). If the logs are stored elsewhere, it's recommended that you copy
384   -the file over to /etc/logrotate.d/ and modify it to point to your local log
385   -directly.
386   -
387   -=========
388   -Upgrading
389   -=========
390   -
391   -If you followed the steps in this document and installed Noosfero from the git
392   -repository, then upgrading is easy. First, you need to allow the noosfero user
393   -to restart the memcached server with sudo, by adding the following line in
394   -/etc/sudoers:
395   -
396   -noosfero ALL=NOPASSWD: /etc/init.d/memcached
397   -
398   -Then, to perform an upgrade, do the following as the noosfero user:
399   -
400   -$ cd /var/lib/noosfero/current
401   -$ ./script/git-upgrade
402   -
403   -The git-upgrade script will take care of everything for you. It will first stop
404   -the service, then fetch the current source code, upgrade database, compile
405   -translations, and then start the service again.
406   -
407   -Note 1: make sure your local git repository is following the "stable" branch,
408   -just like the instructions above. The "master" branch is not recommended for
409   -use in production environments.
410   -
411   -Note 2: always read the release notes before upgrading. Sometimes there will be
412   -steps that must be performed manually. If that is the case, you can invoke the
413   -git-upgrade script with the special parameter "--shell" that will give you a
414   -shell after the upgrade, which you can use to perform any manual steps
415   -required:
416   -
417   -$ ./script/git-upgrade --shell
INSTALL.awstats
... ... @@ -1,78 +0,0 @@
1   -= AWStats setup for Noosfero
2   -
3   -AWStats is a free powerful and featureful tool that generates advanced web,
4   -streaming, ftp or mail server statistics, graphically.
5   -
6   -See http://awstats.sourceforge.net/
7   -
8   -This guide supposes that the Noosfero server is running GNU/Linux Debian Squeeze.
9   -
10   -1. Install AWStats
11   -
12   -# apt-get install awstats libgeo-ip-perl geoip-database
13   -
14   -2. Basic setup
15   -
16   -Create AWStats config file:
17   -
18   - * /etc/awstats/awstats.<domain>.conf
19   -
20   -Include "/etc/awstats/awstats.conf"
21   -Include "/etc/noosfero/awstats-noosfero.conf"
22   -SiteDomain="<domain>"
23   -HostAliases="<domain-aliases>"
24   -
25   -<domain> should be the domain used in your Noosfero server (eg.:
26   -softwarelivre.org) and the <domain-aliases> should be a list with all aliases
27   -that you configured in apache (eg.: www.softwarelivre.org
28   -www2.softwarelivre.org etc).
29   -
30   -This setup is considering that the Noosfero server is running varnish (see
31   -INSTALL.varnish) and varnishncsa-vhost [1].
32   -
33   -[1] http://gitorious.org/varnisnncsa-vhost
34   -
35   -3. Running AWStats for the first time
36   -
37   -Run awstats by hand via command line:
38   -
39   -# /usr/lib/cgi-bin/awstats.pl -config=<domain>
40   -
41   -You should see something as below as output of this command:
42   -
43   -# /usr/lib/cgi-bin/awstats.pl -config=softwarelivre.org
44   -Create/Update database for config "/etc/awstats/awstats.softwarelivre.org.conf" by AWStats version 6.7 (build 1.892)
45   -From data in log file "/var/log/varnish/varnishncsa-vhost.log"...
46   -Phase 1 : First bypass old records, searching new record...
47   -Searching new records from beginning of log file...
48   -Phase 2 : Now process new records (Flush history on disk after 20000 hosts)...
49   -Jumped lines in file: 0
50   -Parsed lines in file: 452
51   - Found 0 dropped records,
52   - Found 0 corrupted records,
53   - Found 0 old records,
54   - Found 452 new qualified records.
55   -
56   -4. Setup frontend
57   -
58   -You should create a new subdomain to have access to the AWStats, usually
59   -something like tools.<domain> (eg.: tools.softwarelivre.org). Don't include
60   -this subdomain in HostAliases in the AWStats neither in SiteAlias in the
61   -Apache.
62   -
63   -# cp /usr/share/doc/awstats/examples/apache.conf /etc/apache2/conf.d/awstats.conf
64   -# invoke-rc.d apache2 restart
65   -
66   -ps.: Don't forget to change the port /etc/apache/sites-enabled/000-default to
67   -8080.
68   -
69   -Try: http://tools.<domain>/cgi-bin/awstats.pl?config=<domain>
70   -(eg.: http://tools.softwarelivre.org/cgi-bin/awstats.pl?config=softwarelivre.org).
71   -
72   -5. Schedule AWStats in crontab
73   -
74   - * /etc/cron.d/awstats
75   -
76   -0,10,20,30,40,50 * * * * www-data [ -x /usr/lib/cgi-bin/awstats.pl -a -f /etc/awstats/awstats.<domain>.conf -a -r /var/log/apache/access.log ] && /usr/lib/cgi-bin/awstats.pl -config=<domain> -update >/dev/null
77   -
78   -Done, check the AWStats frontend after one or two days to see if everything is working properly.
INSTALL.awstats.md 0 → 100644
... ... @@ -0,0 +1,67 @@
  1 +AWStats setup for Noosfero
  2 +==========================
  3 +
  4 +AWStats is a free powerful and featureful tool that generates advanced web, streaming, ftp or mail server statistics, graphically.
  5 +
  6 +See http://awstats.sourceforge.net
  7 +
  8 +This guide supposes that the Noosfero server is running GNU/Linux Debian Squeeze.
  9 +
  10 +### 1. Install AWStats
  11 +
  12 + # apt-get install awstats libgeo-ip-perl geoip-database
  13 +
  14 +### 2. Basic setup
  15 +
  16 +Create AWStats config file:
  17 +`/etc/awstats/awstats.<domain>.conf`
  18 +
  19 + Include "/etc/awstats/awstats.conf"
  20 + Include "/etc/noosfero/awstats-noosfero.conf"
  21 + SiteDomain="<domain>"
  22 + HostAliases="<domain-aliases>"
  23 +
  24 +`<domain>` should be the domain used in your Noosfero server (eg.: `softwarelivre.org`) and the `<domain-aliases>` should be a list with all aliases that you configured in apache (eg.: `www.softwarelivre.org`, `www2.softwarelivre.org`, etc).
  25 +
  26 +This setup is considering that the Noosfero server is running varnish (see `INSTALL.varnish`) and [varnishncsa-vhost](http://gitorious.org/varnisnncsa-vhost).
  27 +
  28 +### 3. Running AWStats for the first time
  29 +
  30 +Run awstats by hand via command line:
  31 +
  32 + # /usr/lib/cgi-bin/awstats.pl -config=<domain>
  33 +
  34 +You should see something as below as output of this command:
  35 +
  36 + # /usr/lib/cgi-bin/awstats.pl -config=softwarelivre.org
  37 + Create/Update database for config "/etc/awstats/awstats.softwarelivre.org.conf" by AWStats version 6.7 (build 1.892)
  38 + From data in log file "/var/log/varnish/varnishncsa-vhost.log"...
  39 + Phase 1 : First bypass old records, searching new record...
  40 + Searching new records from beginning of log file...
  41 + Phase 2 : Now process new records (Flush history on disk after 20000 hosts)...
  42 + Jumped lines in file: 0
  43 + Parsed lines in file: 452
  44 + Found 0 dropped records,
  45 + Found 0 corrupted records,
  46 + Found 0 old records,
  47 + Found 452 new qualified records.
  48 +
  49 +### 4. Setup frontend
  50 +
  51 +You should create a new subdomain to have access to the AWStats, usually something like tools.<domain> (eg.: tools.softwarelivre.org). Don't include this subdomain in HostAliases in the AWStats neither in SiteAlias in the Apache.
  52 +
  53 + # cp /usr/share/doc/awstats/examples/apache.conf /etc/apache2/conf.d/awstats.conf
  54 + # invoke-rc.d apache2 restart
  55 +
  56 +ps.: Don't forget to change the port `/etc/apache/sites-enabled/000-default` to `8080`.
  57 +
  58 +Try: `http://tools.<domain>/cgi-bin/awstats.pl?config=<domain>`
  59 +(eg.: `http://tools.softwarelivre.org/cgi-bin/awstats.pl?config=softwarelivre.org`).
  60 +
  61 +### 5. Schedule AWStats in crontab
  62 +
  63 +`/etc/cron.d/awstats`
  64 +
  65 + 0,10,20,30,40,50 * * * * www-data [ -x /usr/lib/cgi-bin/awstats.pl -a -f /etc/awstats/awstats.<domain>.conf -a -r /var/log/apache/access.log ] && /usr/lib/cgi-bin/awstats.pl -config=<domain> -update >/dev/null
  66 +
  67 +Done, check the AWStats frontend after one or two days to see if everything is working properly.
... ...
INSTALL.chat
... ... @@ -1,258 +0,0 @@
1   -== XMPP/Chat Client Setup
2   -
3   -To configure XMPP/BOSH in Noosfero you need:
4   -
5   -* REST Client - http://github.com/archiloque/rest-client
6   -* SystemTimer - http://ph7spot.com/musings/system-timer
7   -* Pidgin data files - http://www.pidgin.im/
8   -
9   -If you use Debian 6.0 (squeeze):
10   -
11   -# apt-get install librestclient-ruby pidgin-data ruby1.8-dev
12   -# gem install SystemTimer
13   -
14   -The samples of config file to configure a XMPP/BOSH server with
15   -ejabberd, postgresql and apache2 can be found at util/chat directory.
16   -
17   -== XMPP/Chat Server Setup
18   -
19   -This is a step-by-step guide to get a XMPP service working, in a Debian system.
20   -
21   -1. Install the required packages
22   -
23   -# apt-get install ejabberd odbc-postgresql
24   -
25   -2. Ejabberd configuration
26   -
27   -All the following changes must be done in config file:
28   -
29   - /etc/ejabberd/ejabberd.cfg
30   -
31   - 2.1. Set the default admin user
32   -
33   -{ acl, admin, { user, "john", "www.example.com" } }.
34   -{ acl, admin, { user, "bart", "www.example.com" } }.
35   -
36   - 2.2. Set the default host
37   -
38   -{ hosts, [ "www.example.com" ] }.
39   -
40   - 2.3. Http-Bind activation
41   -
42   -{ 5280, ejabberd_http, [
43   - http_bind,
44   - web_admin
45   - ]
46   -}
47   -
48   -(...)
49   -
50   -{ modules, [
51   - {mod_http_bind, []},
52   - ...
53   -] }.
54   -
55   -Ejabberd creates semi-anonymous rooms by default, but Noosfero's Jabber client
56   -needs non-anonymous room, then we need to change default params of creation
57   -rooms in ejabberd to create non-anonymous rooms.
58   -
59   -In non-anonymous rooms the jabber service sends the new occupant's full JID to
60   -all occupants in the room[1].
61   -
62   -Add option "{default_room_options, [{anonymous, false}]}" to
63   -/etc/ejabberd/ejabberd.cfg in mod_muc session. See below:
64   -
65   -{ mod_muc, [
66   - %%{host, "conference.@HOST@"},
67   - {access, muc},
68   - {access_create, muc},
69   - {access_persistent, muc},
70   - {access_admin, muc_admin},
71   - {max_users, 500},
72   - {default_room_options, [{anonymous, false}]}
73   -]},
74   -
75   -[1] - http://xmpp.org/extensions/xep-0045.html#enter-nonanon
76   -
77   -
78   - 2.4. Authentication method
79   -
80   -To use Postgresql through ODBC, the following modifications must be done:
81   -
82   - * Disable the default method:
83   -
84   -{auth_method, internal}.
85   -
86   - * Enable autheticantion through ODBC:
87   -
88   -{auth_method, odbc}.
89   -
90   - * Set database server name
91   -
92   -{odbc_server, "DSN=PostgreSQLEjabberdNoosfero"}.
93   -
94   -
95   - 2.5. Increase the shaper traffic limit
96   -
97   -{ shaper, normal, { maxrate, 10000000 } }.
98   -
99   -
100   - 2.6. Disable unused modules
101   -
102   -Unused modules can be disabled, for example:
103   -
104   - * s2s
105   - * web_admin
106   - * mod_pubsub
107   - * mod_irc
108   - * mod_offline
109   - * mod_admin_extra
110   - * mod_register
111   -
112   -
113   - 2.7. Enable ODBC modules
114   -
115   - * mod_privacy -> mod_privacy_odbc
116   - * mod_private -> mod_private_odbc
117   - * mod_roster -> mod_roster_odbc
118   -
119   -3. Configuring Postgresql
120   -
121   -Login as noosfero user, and execute:
122   -
123   - $ psql noosfero < /path/to/noosfero/util/chat/postgresql/ejabberd.sql
124   -
125   -Where 'noosfero' may need to be replace by the name of the database used for
126   -Noosfero.
127   -
128   -This will create a new schema inside the noosfero database, called 'ejabberd'.
129   -
130   -Note 'noosfero' user should have permission to create Postgresql schemas. Also,
131   -there should be at least one domain with 'is_default = true' in 'domains'
132   -table, otherwise people won't be able to see their friends online.
133   -
134   -
135   -4. ODBC configuration
136   -
137   -The following files must be created:
138   -
139   - * /etc/odbc.ini
140   -
141   -[PostgreSQLEjabberdNoosfero]
142   -Description = PostgreSQL Noosfero ejabberd database
143   -Driver = PostgreSQL Unicode
144   -Trace = No
145   -TraceFile = /tmp/psqlodbc.log
146   -Database = noosfero
147   -Servername = localhost
148   -UserName = <DBUSER>
149   -Password = <DBPASS>
150   -Port =
151   -ReadOnly = No
152   -RowVersioning = No
153   -ShowSystemTables = No
154   -ShowOidColumn = No
155   -FakeOidIndex = No
156   -ConnSettings = SET search_path TO ejabberd
157   -
158   - * /etc/odbcinst.ini
159   -
160   -[PostgreSQL Unicode]
161   -Description = PostgreSQL ODBC driver (Unicode version)
162   -Driver = /usr/lib/odbc/psqlodbcw.so
163   -Setup = /usr/lib/odbc/libodbcpsqlS.so
164   -Debug = 0
165   -CommLog = 1
166   -UsageCount = 3
167   -
168   - 4.1 testing all:
169   -
170   -# isql 'PostgreSQLEjabberdNoosfero'
171   -
172   -If the configuration was done right, the message "Connected!"
173   -will be displayed.
174   -
175   -
176   -5. Enabling kernel polling and SMP in /etc/default/ejabberd
177   -
178   -POLL=true
179   -SMP=auto
180   -
181   -
182   -6. Increase the file descriptors limit for user ejabberd
183   -
184   - 6.1. Uncomment this line in file /etc/pam.d/su:
185   -
186   -session required pam_limits.so
187   -
188   -
189   - 6.2. Add this lines to file /etc/security/limits.conf:
190   -
191   -ejabberd hard nofile 65536
192   -ejabberd soft nofile 65536
193   -
194   -Now, test the configuration:
195   -
196   -# cat /proc/<EJABBERD_BEAM_PROCESS_PID>/limits
197   -
198   -
199   -7. Apache Configuration
200   -
201   -Apache server must be configurated as follow:
202   -
203   - * /etc/apache2/sites-enabled/noosfero
204   -
205   -RewriteEngine On
206   -Include /usr/share/noosfero/util/chat/apache/xmpp.conf
207   -
208   - * /etc/apache2/apache2.conf:
209   -
210   -<IfModule mpm_worker_module>
211   - StartServers 8
212   - MinSpareThreads 25
213   - MaxSpareThreads 75
214   - ThreadLimit 128
215   - ThreadsPerChild 128
216   - MaxClients 2048
217   - MaxRequestsPerChild 0
218   -</IfModule>
219   -
220   -Note: module proxy_http must be enabled:
221   -
222   -# a2enmod proxy_http
223   -
224   -8. DNS configuration
225   -
226   -For this point, we assume you are using BIND as your DNS server. You need to
227   -add the following entries to the DNS zone file corresponding to the domain
228   -of your noosfero site:
229   -
230   -_xmpp-client._tcp SRV 5 100 5222 master
231   -conference CNAME master
232   -_xmpp-client._tcp.conference SRV 5 100 5222 master
233   -
234   -If you are running a DNS server other than BIND, you will have to figure out
235   -how to create equivalente rules for your zone file. Patches to this
236   -documentation are welcome.
237   -
238   -9. Testing this Setup
239   -
240   -Adjust shell limits to proceed with some benchmarks and load tests:
241   -
242   -# ulimit −s 256
243   -# ulimit −n 8192
244   -# echo 10 > /proc/sys/net/ipv4/tcp_syn_retries
245   -
246   -To measure the bandwidth between server and client:
247   -
248   - * at server side:
249   -
250   -# iperf −s
251   -
252   - * at client side:
253   -
254   -# iperf −c server_ip
255   -
256   -For heavy load tests, clone and use this software:
257   -
258   -git clone http://git.holoscopio.com/git/metal/tester.git
INSTALL.chat.md 0 → 100644
... ... @@ -0,0 +1,236 @@
  1 +XMPP/Chat Client Setup
  2 +======================
  3 +
  4 +To configure XMPP/BOSH in Noosfero you need:
  5 +
  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/
  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 +======================
  19 +
  20 +This is a step-by-step guide to get a XMPP service working, in a Debian system.
  21 +
  22 +## 1. Install the required packages
  23 +
  24 + # apt-get install ejabberd odbc-postgresql
  25 +
  26 +## 2. Ejabberd configuration
  27 +
  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]].
  57 +
  58 +Add option "`{default_room_options, [{anonymous, false}]}`" to `/etc/ejabberd/ejabberd.cfg` in mod_muc session. See below:
  59 +
  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}.`
  82 +
  83 + * Set database server name
  84 + `{odbc_server, "DSN=PostgreSQLEjabberdNoosfero"}.`
  85 +
  86 +
  87 +### 2.5. Increase the shaper traffic limit
  88 +
  89 + { shaper, normal, { maxrate, 10000000 } }.
  90 +
  91 +
  92 +### 2.6. Disable unused modules
  93 +
  94 +Unused modules can be disabled, for example:
  95 +
  96 + * s2s
  97 + * web_admin
  98 + * mod_pubsub
  99 + * mod_irc
  100 + * mod_offline
  101 + * mod_admin_extra
  102 + * mod_register
  103 +
  104 +
  105 +### 2.7. Enable ODBC modules
  106 +
  107 + * mod_privacy -> mod_privacy_odbc
  108 + * mod_private -> mod_private_odbc
  109 + * mod_roster -> mod_roster_odbc
  110 +
  111 +## 3. Configuring Postgresql
  112 +
  113 +Login as noosfero user, and execute:
  114 +
  115 + $ psql noosfero < /path/to/noosfero/util/chat/postgresql/ejabberd.sql
  116 +
  117 +Where `noosfero` may need to be replace by the name of the database used for Noosfero.
  118 +
  119 +This will create a new schema inside the noosfero database, called `ejabberd`.
  120 +
  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.
  122 +
  123 +## 4. ODBC configuration
  124 +
  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
  155 +
  156 +## 4.1 testing all:
  157 +
  158 + # isql 'PostgreSQLEjabberdNoosfero'
  159 +
  160 +If the configuration was done right, the message "Connected!" will be displayed.
  161 +
  162 +
  163 +## 5. Enabling kernel polling and SMP in `/etc/default/ejabberd`
  164 +
  165 + POLL=true
  166 + SMP=auto
  167 +
  168 +## 6. Increase the file descriptors limit for user ejabberd
  169 +
  170 +### 6.1. Uncomment this line in file `/etc/pam.d/su`:
  171 +
  172 + session required pam_limits.so
  173 +
  174 +### 6.2. Add this lines to file `/etc/security/limits.conf`:
  175 +
  176 + ejabberd hard nofile 65536
  177 + ejabberd soft nofile 65536
  178 +
  179 +Now, test the configuration:
  180 +
  181 + # cat /proc/<EJABBERD_BEAM_PROCESS_PID>/limits
  182 +
  183 +## 7. Apache Configuration
  184 +
  185 +Apache server must be configurated as follow:
  186 +
  187 +`/etc/apache2/sites-enabled/noosfero`:
  188 +
  189 + RewriteEngine On
  190 + Include /usr/share/noosfero/util/chat/apache/xmpp.conf
  191 +
  192 +`/etc/apache2/apache2.conf`:
  193 +
  194 + <IfModule mpm_worker_module>
  195 + StartServers 8
  196 + MinSpareThreads 25
  197 + MaxSpareThreads 75
  198 + ThreadLimit 128
  199 + ThreadsPerChild 128
  200 + MaxClients 2048
  201 + MaxRequestsPerChild 0
  202 + </IfModule>
  203 +
  204 +Note: module proxy_http must be enabled:
  205 +
  206 + # a2enmod proxy_http
  207 +
  208 +## 8. DNS configuration
  209 +
  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:
  211 +
  212 + _xmpp-client._tcp SRV 5 100 5222 master
  213 + conference CNAME master
  214 + _xmpp-client._tcp.conference SRV 5 100 5222 master
  215 +
  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.
  217 +
  218 +## 9. Testing this Setup
  219 +
  220 +Adjust shell limits to proceed with some benchmarks and load tests:
  221 +
  222 + # ulimit −s 256
  223 + # ulimit −n 8192
  224 + # echo 10 > /proc/sys/net/ipv4/tcp_syn_retries
  225 +
  226 +To measure the bandwidth between server and client:
  227 +
  228 + * at server side:
  229 + `# iperf −s`
  230 +
  231 + * at client side:
  232 + `# iperf −c server_ip`
  233 +
  234 +For heavy load tests, clone and use this software:
  235 +
  236 + $ git clone http://git.holoscopio.com/git/metal/tester.git
... ...
INSTALL.email
... ... @@ -1,43 +0,0 @@
1   -= Noosfero email setup
2   -
3   -If you know mail systems well, you just need to make sure that the local MTA,
4   -listening on localhost:25, is able to deliver e-mails to the internet. Any mail
5   -server will do it. You can stop reading now.
6   -
7   -If you are not an email specialist, then follow the instructions below. We
8   -suggest that you use the Postfix mail server, since it is easy to configure and
9   -very reliable. Just follow the instructions below.
10   -
11   -To install Postfix:
12   -
13   -# apt-get install postfix
14   -
15   -During the installation process, you will be asked a few questions. Your answer
16   -to them will vary in 2 cases:
17   -
18   -Case 1: you can send e-mails directly to the internet. This will be the case
19   -for most commercial private servers. Your answers should be:
20   -
21   - General type of mail configuration: Internet site
22   - System mail name: the name of your domain, e.g. "mysocialnetwork.com"
23   -
24   -Case 2: you cannot, or don't want to, send e-mail directly to the internet.
25   -This happens for example if your server is not allowed to make outbound
26   -connections on port 25, or if you want to concentrate all your outbound mail
27   -through a single SMTP server. Your answers in this case should be:
28   -
29   - General type of mail configuration: Internet with smarthost
30   - System mail name: the name of your domain, e.g. "mysocialnetwork.com"
31   - SMTP relay host: smtp.yourprovider.com
32   -
33   -Note that smtp.yourprovider.com must allow your server to deliver e-mails
34   -through it. You should probably ask your servive provider about this.
35   -
36   -There is another possibility: if you are installing on a shared server, and
37   -don't have permission to configure the local MTA, you can instruct Noosfero to
38   -send e-mails directly through an external server. Please note that this should
39   -be your last option, since contacting an external SMTP server directly may slow
40   -down your Noosfero application server. To configure Noosfero to send e-mails
41   -through an external SMTP server, follow the instructions on
42   -http://noosfero.org/Development/SMTPMailSending
43   -
INSTALL.email.md 0 → 100644
... ... @@ -0,0 +1,28 @@
  1 +Noosfero email setup
  2 +====================
  3 +
  4 +If you know mail systems well, you just need to make sure that the local MTA, listening on localhost:25, is able to deliver e-mails to the internet. Any mail server will do it. You can stop reading now.
  5 +
  6 +If you are not an email specialist, then follow the instructions below. We suggest that you use the Postfix mail server, since it is easy to configure and very reliable. Just follow the instructions below.
  7 +
  8 +To install Postfix:
  9 +
  10 + # apt-get install postfix
  11 +
  12 +During the installation process, you will be asked a few questions. Your answer to them will vary in 2 cases:
  13 +
  14 +**Case 1**: you can send e-mails directly to the internet. This will be the case for most commercial private servers. Your answers should be:
  15 +
  16 + * General type of mail configuration: Internet site
  17 + * System mail name: the name of your domain, e.g. "mysocialnetwork.com"
  18 +
  19 +**Case 2**: you cannot, or don't want to, send e-mail directly to the internet. This happens for example if your server is not allowed to make outbound connections on port 25, or if you want to concentrate all your outbound mail through a single SMTP server. Your answers in this case should be:
  20 +
  21 + * General type of mail configuration: Internet with smarthost
  22 + * System mail name: the name of your domain, e.g. "mysocialnetwork.com"
  23 + * SMTP relay host: smtp.yourprovider.com
  24 +
  25 +Note that smtp.yourprovider.com must allow your server to deliver e-mails through it. You should probably ask your servive provider about this.
  26 +
  27 +There is another possibility: if you are installing on a shared server, and don't have permission to configure the local MTA, you can instruct Noosfero to send e-mails directly through an external server. Please note that this should be your last option, since contacting an external SMTP server directly may slow down your Noosfero application server. To configure Noosfero to send e-mails through an external SMTP server, follow the instructions on http://noosfero.org/Development/SMTPMailSending
  28 +
... ...
INSTALL.md 0 → 100644
... ... @@ -0,0 +1,334 @@
  1 +Noosfero installation instructions from source for production environments
  2 +==========================================================================
  3 +
  4 +The instructions below can be used for setting up a Noosfero production environment from the Noosfero sources.
  5 +
  6 +Before you start installing Noosfero manually, see the information about the Noosfero Debian package at http://noosfero.org/Development/DebianPackage. Using the Debian packages on a Debian stable system is the recommended method for installing production environments.
  7 +
  8 +If you want to setup a development environment instead of a production one, stop reading this file right now and read the file `HACKING.md` instead.
  9 +
  10 +For a complete installation guide, please see the following web page: http://noosfero.org/Development/HowToInstall
  11 +
  12 +If you have problems with the setup, please feel free to ask questions in the development mailing list.
  13 +
  14 +Requirements
  15 +------------
  16 +
  17 +**DISCLAIMER**: this installation procedure is tested with Debian stable, which is currently the only recommended operating system for production usage. It is possible that you can install it on other systems, and if you do so, please report it on one of the Noosfero mailing lists, and please send a patch updating these instructions.
  18 +
  19 +Noosfero is written in Ruby with the "[Rails framework](http://www.rubyonrails.org)", so the process of setting it up is pretty similar to other Rails applications.
  20 +
  21 +You need to install some packages Noosfero depends on. On Debian GNU/Linux or Debian-based systems, all of these packages are available through the Debian archive. You can install them with the following command:
  22 +
  23 + # apt-get install ruby rake po4a libgettext-ruby-util libgettext-ruby1.8 \
  24 + libsqlite3-ruby rcov librmagick-ruby libredcloth-ruby libhpricot-ruby \
  25 + libwill-paginate-ruby iso-codes libfeedparser-ruby libdaemons-ruby thin \
  26 + tango-icon-theme
  27 +
  28 +On other systems, they may or may not be available through your regular package management system. Below are the links to their homepages.
  29 +
  30 +* Ruby: http://www.ruby-lang.org
  31 +* Rake: http://rake.rubyforge.org
  32 +* po4a: http://po4a.alioth.debian.org
  33 +* Ruby-sqlite3: http://rubyforge.org/projects/sqlite-ruby
  34 +* rcov: http://eigenclass.org/hiki/rcov
  35 +* RMagick: http://rmagick.rubyforge.org
  36 +* RedCloth: http://redcloth.org
  37 +* will_paginate: http://github.com/mislav/will_paginate/wikis
  38 +* iso-codes: http://pkg-isocodes.alioth.debian.org
  39 +* feedparser: http://packages.debian.org/sid/libfeedparser-ruby
  40 +* Daemons - http://daemons.rubyforge.org
  41 +* Thin: http://code.macournoyer.com/thin
  42 +* tango-icon-theme: http://tango.freedesktop.org/Tango_Icon_Library
  43 +* Hpricot: http://hpricot.com
  44 +
  45 +If you manage to install Noosfero successfully on other systems than Debian,
  46 +please feel free to contact the Noosfero development mailing with the
  47 +instructions for doing so, and we'll include it here.
  48 +
  49 +As root user
  50 +============
  51 +
  52 +Install memcached. On Debian:
  53 +
  54 + # apt-get install memcached
  55 +
  56 +Study whether you need to raise the ammount of memory it uses for caching, depending on the demand you expect for your site. If you are going to run a high-traffic site, you will want to raise the ammount of memory reserved for caching.
  57 +
  58 +It is recommended that you run noosfero with its own user account. To create such an account, please do the following:
  59 +
  60 + # adduser --system --group noosfero --shell /bin/sh --home /var/lib/noosfero
  61 +
  62 +(note that you can change the `$HOME` directory of the user if you wish, here we are using `/var/lib/noosfero`)
  63 +
  64 +The `--system` option will tell adduser to create a system user, i.e. this user will not have a password and cannot login to the system directly. To become this user, you have to use sudo:
  65 +
  66 + # sudo -u noosfero -i
  67 + or
  68 + # su - noosfero
  69 +
  70 +As noosfero user
  71 +================
  72 +
  73 +downloading from git
  74 +--------------------
  75 +
  76 +Here we are cloning the noosfero repository from git. Note: you will need to install git before.
  77 +
  78 + $ git clone git://gitorious.org/noosfero/noosfero.git current
  79 + $ cd current
  80 + $ git checkout -b stable origin/stable
  81 +
  82 +downloading tarball
  83 +-------------------
  84 +
  85 +Note: replace 0.39.0 below from the latest stable version.
  86 +
  87 + $ wget http://noosfero.org/pub/Development/NoosferoVersion00x39x00/noosfero-0.39.0.tar.gz
  88 + $ tar -zxvf noosfero-0.39.0.tar.gz
  89 + $ ln -s noosfero-0.39.0 current
  90 + $ cd current
  91 +
  92 +Create the thin configuration file:
  93 +
  94 + $ thin -C config/thin.yml -e production config
  95 +
  96 +Edit config/thin.yml to suit your needs. Make sure your apache configuration matches the thin cluster configuration, specially in respect to the ports and numbers of thin instances.
  97 +
  98 +*Note*: currently Noosfero only supports Rails 2.3.5, which is the version in Debian Squeeze. If you have a Rails version newer than that, Noosfero will probably not work. You can install Rails 2.3.5 into your Noosfero installation with the following procedure:
  99 +
  100 + $ cd /var/lib/noosfero/current/vendor
  101 + $ wget http://ftp.de.debian.org/debian/pool/main/r/rails/rails_2.3.5.orig.tar.gz
  102 + $ tar xzf rails_2.3.5.orig.tar.gz
  103 + $ ln -s rails-2.3.5 rails
  104 +
  105 +As root user
  106 +============
  107 +
  108 +Setup Noosfero log and tmp directories:
  109 +
  110 + # cd /var/lib/noosfero/current
  111 + # ./etc/init.d/noosfero setup
  112 +
  113 +Now it's time to setup the database. In this example we are using PostgreSQL, so if you are planning to use a different database this steps won't apply.
  114 +
  115 + # apt-get install postgresql libpgsql-ruby
  116 + # su postgres -c 'createuser noosfero -S -d -R'
  117 +
  118 +By default Rails will try to connect on postgresql through 5432 port, you can check it on `/etc/postgresql/8.4/main/postgresql.conf` file.
  119 +
  120 +Restart postgresql:
  121 + # invoke-rc.d postgresql restart
  122 +
  123 +Noosfero needs a functional e-mail setup to work: the local mail system should be able to deliver e-mail to the internet, either directly or through an external SMTP server. Please check the documentation at the INSTALL.email file.
  124 +
  125 +As noosfero user
  126 +================
  127 +
  128 +Now create the databases:
  129 +
  130 + $ cd /var/lib/noosfero/current
  131 + $ createdb noosfero_production
  132 + $ createdb noosfero_development
  133 + $ createdb noosfero_test
  134 +
  135 +The development and test databases are actually optional. If you are creating a stricly production server, you will probably not need them.
  136 +
  137 +Now we want to configure Noosfero for accessing the database we just created. To do that, you can 1) copy `config/database.yml.pgsql` to `config/database.yml`, or create `config/database.yml` from scratch with the following content:
  138 +
  139 + production:
  140 + adapter: postgresql
  141 + encoding: unicode
  142 + database: noosfero_production
  143 + username: noosfero
  144 +
  145 +Now, to test the database access, you can fire the Rails database console:
  146 +
  147 + $ ./script/dbconsole production
  148 +
  149 +If it connects to your database, then everything is fine. If you got an error message, then you have to check your database configuration.
  150 +
  151 +Create the database structure:
  152 +
  153 + $ RAILS_ENV=production rake db:schema:load
  154 +
  155 +Compile the translations:
  156 +
  157 + $ RAILS_ENV=production rake noosfero:translations:compile
  158 +
  159 +Now we must create some initial data. To create your default environment (the first one), run the command below:
  160 +
  161 + $ RAILS_ENV=production ./script/runner 'Environment.create!(:name => "My environment", :is_default => true)'
  162 +
  163 +(of course, replace "My environment" with your environment's name!)
  164 +
  165 +And now you have to add the domain name you will be using for your noosfero site to the list of domains of that default environment you just created:
  166 +
  167 + $ RAILS_ENV=production ./script/runner "Environment.default.domains << Domain.new(:name => 'your.domain.com')"
  168 +
  169 +(replace "your.domain.com" with your actual domain name)
  170 +
  171 +Add at least one user as admin of environment:
  172 +
  173 + $ RAILS_ENV=production ./script/runner "User.create(:login => 'adminuser', :email => 'admin@example.com', :password => 'admin', :password_confirmation => 'admin', :environment => Environment.default, :activated_at => Time.new)"
  174 +
  175 +(replace "adminuser", "admin@example.com", "admin" with the login, email and password of your environment administrator)
  176 +
  177 +To start the Noosfero application servers:
  178 +
  179 + $ ./script/production start
  180 +
  181 +At this point you have a functional Noosfero installation running, the only thing left is to configure your webserver as a reverse proxy to pass requests to them.
  182 +
  183 +
  184 +Apache instalation
  185 +==================
  186 +
  187 + # apt-get install apache2
  188 +
  189 +Apache configuration
  190 +--------------------
  191 +
  192 +First you have to enable the following some apache modules:
  193 +
  194 + * deflate
  195 + * expires
  196 + * proxy
  197 + * proxy_balancer
  198 + * proxy_http
  199 + * rewrite
  200 +
  201 +On Debian GNU/Linux system, these modules can be enabled with the following command line, as root:
  202 +
  203 + # a2enmod deflate expires proxy proxy_balancer proxy_http rewrite
  204 +
  205 +In other systems the way by which you enable apache modules may be different.
  206 +
  207 +Now with the Apache configuration. You can use the template below, replacing `/var/lib/noosfero/current` with the directory in which your noosfero installation is, your.domain.com with the domain name of your noosfero site. We are assuming that you are running two thin instances on ports 3000 and 3001. If your setup is different you'll need to adjust `<Proxy>` section. If you don't understand something in the configuration, please refer to the apache documentation.
  208 +
  209 +Add a file called "mysite" (or whatever name you want to give to your noosfero site) to `/etc/apache2/sites-available` with the following content, and customize as needed (as usual, make sure you replace "your.domain.com" with you actual domain name, and "`/var/lib/noosfero/current`" with the directory where Noosfero is installed):
  210 +
  211 + <VirtualHost *:80>
  212 + ServerName your.domain.com
  213 +
  214 + DocumentRoot "/var/lib/noosfero/current/public"
  215 + <Directory "/var/lib/noosfero/current/public">
  216 + Options FollowSymLinks
  217 + AllowOverride None
  218 + Order Allow,Deny
  219 + Allow from all
  220 + </Directory>
  221 +
  222 + RewriteEngine On
  223 +
  224 + # Rewrite index to check for static index.html
  225 + RewriteRule ^/$ /index.html [QSA]
  226 +
  227 + # Rewrite to check for Rails cached page
  228 + RewriteRule ^([^.]+)$ $1.html [QSA]
  229 +
  230 + RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
  231 + RewriteRule ^.*$ balancer://noosfero%{REQUEST_URI} [P,QSA,L]
  232 +
  233 + ErrorDocument 503 /503.html
  234 +
  235 + ErrorLog /var/log/apache2/noosfero.log
  236 + LogLevel warn
  237 + CustomLog /var/log/apache2/noosfero.access.log combined
  238 +
  239 + Include /var/lib/noosfero/current/etc/noosfero/apache/cache.conf
  240 +
  241 + </VirtualHost>
  242 +
  243 + <Proxy balancer://noosfero>
  244 + BalancerMember http://127.0.0.1:3000
  245 + BalancerMember http://127.0.0.1:3001
  246 + Order Allow,Deny
  247 + Allow from All
  248 + </Proxy>
  249 +
  250 +The cache.conf file included in the end of the <VirtualHost> section is important, since it will tell apache to pass expiration and cache headers to clients so that the site feels faster for users. Do we need to say that using that configuration is strongly recommended?
  251 +
  252 +Enable that site with (as root, replace "mysite" with the actual name you gave to your site configuration):
  253 +
  254 + # a2ensite mysite
  255 +
  256 +Now restart your apache server (as root):
  257 +
  258 + # invoke-rc.d apache2 restart
  259 +
  260 +
  261 +Enabling exception notifications
  262 +================================
  263 +
  264 +This is an optional step. You will need it only if you want to receive e-mail notifications when some exception occurs on Noosfero.
  265 +
  266 +First, install this version of the gem. Others versions may not be compatible with Noosfero:
  267 +
  268 + # gem install exception_notification -v 1.0.20090728
  269 +
  270 +You can configure the e-mails that will receive the notifications. Change the file config/noosfero.yml as the following example, replacing the e-mails by real ones:
  271 +
  272 + production:
  273 + exception_recipients: [admin@example.com, you@example.com]
  274 +
  275 +
  276 +Maintainance
  277 +============
  278 +
  279 +To ease the maintainance, install a symbolic link for the Noosfero startup script in your server and add it to the system initialization and shutdown sequences (as root):
  280 +
  281 + # ln -s /var/lib/noosfero/current/etc/init.d/noosfero /etc/init.d/noosfero
  282 + # update-rc.d noosfero defaults
  283 + Adding system startup for /etc/init.d/noosfero ...
  284 + /etc/rc0.d/K20noosfero -> ../init.d/noosfero
  285 + /etc/rc1.d/K20noosfero -> ../init.d/noosfero
  286 + /etc/rc6.d/K20noosfero -> ../init.d/noosfero
  287 + /etc/rc2.d/S20noosfero -> ../init.d/noosfero
  288 + /etc/rc3.d/S20noosfero -> ../init.d/noosfero
  289 + /etc/rc4.d/S20noosfero -> ../init.d/noosfero
  290 + /etc/rc5.d/S20noosfero -> ../init.d/noosfero
  291 +
  292 +Now to start Noosfero, you do as root:
  293 +
  294 + # invoke-rc.d noosfero start
  295 +
  296 +To stop Noosfero:
  297 +
  298 + # invoke-rc.d noosfero start
  299 +
  300 +To restart Noosfero:
  301 +
  302 + # invoke-rc.d noosfero restart
  303 +
  304 +Noosfero will be automatically started during system boot, and automatically stopped if the system shuts down for some reason (or during the shutdown part of a reboot).
  305 +
  306 +Rotating logs
  307 +=============
  308 +
  309 +Noosfero provides an example logrotate configuation to rotate its logs. To use it, create a symbolic link in `/etc/logrotate.d/`:
  310 +
  311 + # cd /etc/logrotate.d/
  312 + # ln -s /var/lib/noosfero/current/etc/logrotate.d/noosfero
  313 +
  314 +Note that the provided file assumes Noosfero logging is being done in `/var/log/noosfero` (which is the case if you followed the instructions above correctly). If the logs are stored elsewhere, it's recommended that you copy the file over to `/etc/logrotate.d/` and modify it to point to your local log directly.
  315 +
  316 +Upgrading
  317 +=========
  318 +
  319 +If you followed the steps in this document and installed Noosfero from the git repository, then upgrading is easy. First, you need to allow the noosfero user to restart the memcached server with sudo, by adding the following line in `/etc/sudoers`:
  320 +
  321 + noosfero ALL=NOPASSWD: /etc/init.d/memcached
  322 +
  323 +Then, to perform an upgrade, do the following as the noosfero user:
  324 +
  325 + $ cd /var/lib/noosfero/current
  326 + $ ./script/git-upgrade
  327 +
  328 +The `git-upgrade` script will take care of everything for you. It will first stop the service, then fetch the current source code, upgrade database, compile translations, and then start the service again.
  329 +
  330 +*Note 1*: make sure your local git repository is following the "stable" branch, just like the instructions above. The `master` branch is **not** recommended for use in production environments.
  331 +
  332 +*Note 2*: always read the release notes before upgrading. Sometimes there will be steps that must be performed manually. If that is the case, you can invoke the `git-upgrade` script with the special parameter `--shell` that will give you a shell after the upgrade, which you can use to perform any manual steps required:
  333 +
  334 + $ ./script/git-upgrade --shell
... ...
INSTALL.multitenancy
... ... @@ -1,163 +0,0 @@
1   -== Multitenancy support
2   -
3   -Multitenancy refers to a principle in software architecture where a
4   -single instance of the software runs on a server, serving multiple
5   -client organizations (tenants). Multitenancy is contrasted with a
6   -multi-instance architecture where separate software instances (or
7   -hardware systems) are set up for different client organizations. With
8   -a multitenant architecture, a software application is designed to
9   -virtually partition its data and configuration, and each client
10   -organization works with a customized virtual application instance.
11   -
12   -Today this feature is available only for PostgreSQL databases.
13   -
14   -This document assumes that you have a new fully PostgresSQL default Noosfero
15   -installation as explained at the INSTALL file.
16   -
17   -== Separated data
18   -
19   -The items below are separated for each hosted environment:
20   -
21   -* Uploaded files
22   -* Database
23   -* Solr index
24   -* ActiveRecord#cache_key
25   -* Feed updater
26   -* Delayed Job Workers
27   -
28   -== Database configuration file
29   -
30   -The file config/database.yml must follow a structure in order to
31   -achieve multitenancy support. In this example, we will set 3
32   -different environments: env1, env2 and env3.
33   -
34   -Each "hosted" environment must have an entry like this:
35   -
36   -env1_production:
37   - adapter: postgresql
38   - encoding: unicode
39   - database: noosfero
40   - schema_search_path: public
41   - username: noosfero
42   - domains:
43   - - env1.com
44   - - env1.org
45   -
46   -env2_production:
47   - adapter: postgresql
48   - encoding: unicode
49   - database: noosfero
50   - schema_search_path: env2
51   - username: noosfero
52   - domains:
53   - - env2.com
54   - - env2.org
55   -
56   -env3_production:
57   - adapter: postgresql
58   - encoding: unicode
59   - database: noosfero
60   - schema_search_path: env3
61   - username: noosfero
62   - domains:
63   - - env3.com
64   - - env3.net
65   -
66   -The "hosted" environments define, besides the schema_search_path, a
67   -list of domains that, when accessed, tells which database the
68   -application should use. Also, the environment name must end with
69   -'_hosting', where 'hosting' is the name of the hosting environment.
70   -
71   -You must also tell the application which is the default environment.
72   -
73   -production:
74   - env1_production
75   -
76   -On the example above there are only three hosted environments, but it
77   -can be more than three. The schemas 'env2' and 'env3' must already
78   -exist in the same database of the hosting environment. As postgres
79   -user, you can create them typing:
80   -
81   -$ psql database_name -c "CREATE SCHEMA env2 AUTHORIZATION database_user"
82   -$ psql database_name -c "CREATE SCHEMA env3 AUTHORIZATION database_user"
83   -
84   -Replace database_name and database_user above with your stuff.
85   -
86   -So, yet on this same example, when a user accesses http://env2.com or
87   -http://env2.org, the Noosfero application running on production will
88   -turn the database schema to 'env2'. When the access is from domains
89   -http://env3.com or http://env3.net, the schema to be loaded will be
90   -'env3'.
91   -
92   -There is an example of this file in config/database.yml.multitenancy
93   -
94   -== Preparing the database
95   -
96   -Now create the environments:
97   -
98   -$ RAILS_ENV=production rake multitenancy:create
99   -
100   -This command above will create the hosted environment files equal to
101   -their hosting environment, here called 'production'.
102   -
103   -Run db:schema:load for each other environment:
104   -
105   -$ RAILS_ENV=env2_production rake db:schema:load
106   -$ RAILS_ENV=env3_production rake db:schema:load
107   -
108   -Then run the migrations for the hosting environment, and it will
109   -run for each of its hosted environments:
110   -
111   -RAILS_ENV=production rake db:migrate
112   -
113   -== Start Noosfero
114   -
115   -Run Noosfero init file as root:
116   -
117   -# invoke-rc.d noosfero start
118   -
119   -== Solr
120   -
121   -It's necessary to run only one instance of Solr. Don't worry
122   -about this, Noosfero initializer had already done this for you.
123   -
124   -== Feed updater & Delayed job
125   -
126   -Just for your information, a daemon of feed-updater and delayed_job
127   -must be running for each environment. Noosfero initializer do this,
128   -relax.
129   -
130   -== Uploaded files
131   -
132   -When running with PostgreSQL, Noosfero uploads stuff to a folder named
133   -the same way as the running schema. Inside the upload folder root, for
134   -example, will be public/image_uploads/env2 and public/image_uploads/env3.
135   -
136   -== Adding multitenancy support to an existing Noosfero environment
137   -
138   -If you already have a Noosfero environment, you can turn it multitenant
139   -by following the steps below in addition to the previous steps:
140   -
141   -1. Reindex your database
142   -
143   -Rebuild the Solr index by running the following task just
144   -for your hosting environment, do this as noosfero user:
145   -
146   -$ RAILS_ENV=production rake multitenancy:reindex
147   -
148   -2. Move the uploaded files to the right place
149   -
150   -Add a directory with the same name as your schema name (by default this
151   -name is 'public') in the root of each upload directory, for example,
152   -public/articles/0000 will be moved to public/articles/public/0000. Do this
153   -with the directories public/image_uploads, public/articles and public/thumbnails.
154   -
155   -3. Fix paths on activities
156   -
157   -The profile activities store static paths to the images, so it's necessary to fix
158   -these paths. You can do this easily by setting an alias on your webserver.
159   -On Apache you can add the three rules below, where 'public' is the schema name:
160   -
161   - RewriteRule ^/articles(.+) /articles/public$1
162   - RewriteRule ^/image_uploads(.+) /image_uploads/public$1
163   - RewriteRule ^/thumbnails(.+) /thumbnails/public$1
INSTALL.multitenancy.md 0 → 100644
... ... @@ -0,0 +1,133 @@
  1 +Multitenancy support
  2 +====================
  3 +
  4 +Multitenancy refers to a principle in software architecture where a single instance of the software runs on a server, serving multiple client organizations (tenants). Multitenancy is contrasted with a multi-instance architecture where separate software instances (or hardware systems) are set up for different client organizations. With a multitenant architecture, a software application is designed to virtually partition its data and configuration, and each client organization works with a customized virtual application instance.
  5 +
  6 +Today this feature is available only for PostgreSQL databases.
  7 +
  8 +This document assumes that you have a new fully PostgresSQL default Noosfero installation as explained at the `INSTALL.md` file.
  9 +
  10 +Separated data
  11 +--------------
  12 +
  13 +The items below are separated for each hosted environment:
  14 +
  15 +* Uploaded files
  16 +* Database
  17 +* Solr index
  18 +* ActiveRecord#cache_key
  19 +* Feed updater
  20 +* Delayed Job Workers
  21 +
  22 +Database configuration file
  23 +---------------------------
  24 +
  25 +The file config/database.yml must follow a structure in order to achieve multitenancy support. In this example, we will set 3 different environments: env1, env2 and env3.
  26 +
  27 +Each "hosted" environment must have an entry like this:
  28 +
  29 + env1_production:
  30 + adapter: postgresql
  31 + encoding: unicode
  32 + database: noosfero
  33 + schema_search_path: public
  34 + username: noosfero
  35 + domains:
  36 + - env1.com
  37 + - env1.org
  38 +
  39 + env2_production:
  40 + adapter: postgresql
  41 + encoding: unicode
  42 + database: noosfero
  43 + schema_search_path: env2
  44 + username: noosfero
  45 + domains:
  46 + - env2.com
  47 + - env2.org
  48 +
  49 + env3_production:
  50 + adapter: postgresql
  51 + encoding: unicode
  52 + database: noosfero
  53 + schema_search_path: env3
  54 + username: noosfero
  55 + domains:
  56 + - env3.com
  57 + - env3.net
  58 +
  59 +The "hosted" environments define, besides the `schema_search_path`, a list of domains that, when accessed, tells which database the application should use. Also, the environment name must end with "`_<hosting>`", where `<hosting>` is the name of the hosting environment.
  60 +
  61 +You must also tell the application which is the default environment.
  62 +
  63 + production:
  64 + env1_production
  65 +
  66 +On the example above there are only three hosted environments, but it can be more than three. The schemas `env2` and `env3` must already exist in the same database of the hosting environment. As postgres user, you can create them typing:
  67 +
  68 + $ psql database_name -c "CREATE SCHEMA env2 AUTHORIZATION database_user"
  69 + $ psql database_name -c "CREATE SCHEMA env3 AUTHORIZATION database_user"
  70 +
  71 +Replace `database_name` and `database_user` above with your stuff.
  72 +
  73 +So, yet on this same example, when a user accesses http://env2.com or http://env2.org, the Noosfero application running on production will turn the database schema to `env2`. When the access is from domains http://env3.com or http://env3.net, the schema to be loaded will be `env3`.
  74 +
  75 +There is an example of this file in `config/database.yml.multitenancy`
  76 +
  77 +Preparing the database
  78 +----------------------
  79 +
  80 +Now create the environments:
  81 +
  82 + $ RAILS_ENV=production rake multitenancy:create
  83 +
  84 +This command above will create the hosted environment files equal to their hosting environment, here called 'production'.
  85 +
  86 +Run db:schema:load for each other environment:
  87 +
  88 + $ RAILS_ENV=env2_production rake db:schema:load
  89 + $ RAILS_ENV=env3_production rake db:schema:load
  90 +
  91 +Then run the migrations for the hosting environment, and it will run for each of its hosted environments:
  92 +
  93 + RAILS_ENV=production rake db:migrate
  94 +
  95 +Start Noosfero
  96 +--------------
  97 +
  98 +Run Noosfero init file as root:
  99 +
  100 + # invoke-rc.d noosfero start
  101 +
  102 +Feed updater & Delayed job
  103 +--------------------------
  104 +
  105 +Just for your information, a daemon of `feed-updater` and `delayed_job` must be running for each environment. Noosfero initializer do this, relax.
  106 +
  107 +Uploaded files
  108 +--------------
  109 +
  110 +When running with PostgreSQL, Noosfero uploads stuff to a folder named the same way as the running schema. Inside the upload folder root, for example, will be `public/image_uploads/env2` and `public/image_uploads/env3`.
  111 +
  112 +Adding multitenancy support to an existing Noosfero environment
  113 +---------------------------------------------------------------
  114 +
  115 +If you already have a Noosfero environment, you can turn it multitenant by following the steps below in addition to the previous steps:
  116 +
  117 +### 1. Reindex your database
  118 +
  119 +Rebuild the Solr index by running the following task just for your hosting environment, do this as noosfero user:
  120 +
  121 + $ RAILS_ENV=production rake multitenancy:reindex
  122 +
  123 +### 2. Move the uploaded files to the right place
  124 +
  125 +Add a directory with the same name as your schema name (by default this name is `public`) in the root of each upload directory, for example, `public/articles/0000` will be moved to `public/articles/public/0000`. Do this with the directories `public/image_uploads`, `public/articles` and `public/thumbnails`.
  126 +
  127 +### 3. Fix paths on activities
  128 +
  129 +The profile activities store static paths to the images, so it's necessary to fix these paths. You can do this easily by setting an alias on your webserver. On Apache you can add the three rules below, where 'public' is the schema name:
  130 +
  131 + RewriteRule ^/articles(.+) /articles/public$1
  132 + RewriteRule ^/image_uploads(.+) /image_uploads/public$1
  133 + RewriteRule ^/thumbnails(.+) /thumbnails/public$1
... ...
INSTALL.varnish
... ... @@ -1,71 +0,0 @@
1   -= Setting up Varnish for your Noosfero site
2   -
3   -Varnish is a HTTP caching server, and using it together with Noosfero is highly
4   -recommended. See http://www.varnish-cache.org/ for more information on Varnish.
5   -
6   -Varnish can be set up to use with Noosfero with the following steps:
7   -
8   -1) setup Noosfero with apache according to the INSTALL file. If you used the
9   -Debian package to install noosfero, you don't need to do anything about this.
10   -
11   -2) install Varnish
12   -
13   - # apt-get install varnish
14   -
15   -Install the RPAF apache module (or skip this step if not using apache):
16   -
17   - # apt-get install libapache2-mod-rpaf
18   -
19   -3) Change Apache to listen on port 8080 instead of 80
20   -
21   -3a) Edit /etc/apache2/ports.conf, and:
22   -
23   - * change 'NameVirtualHost *:80' to 'NameVirtualHost *:8080'
24   - * change 'Listen 80' to 'Listen 127.0.0.1:8080'
25   -
26   -3b) Edit /etc/apache2/sites-enabled/*, and change '<VirtualHost *:80>' to
27   -'<VirtualHost *:8080>'
28   -
29   -3c) Restart apache
30   -
31   - # invoke-rc.d apache2 restart
32   -
33   -4) Varnish configuration
34   -
35   -4a) Edit /etc/default/varnish
36   -
37   - * change the line that says "START=no" to say "START=yes"
38   - * change '-a :6081' to '-a :80'
39   -
40   -4b) Edit /etc/varnish/default.vcl and add the following lines at the end:
41   -
42   - include "/etc/noosfero/varnish-noosfero.vcl";
43   - include "/etc/noosfero/varnish-accept-language.vcl";
44   -
45   -On manual installations, change "/etc/noosfero/*" to
46   -"{Rails.root}/etc/noosfero/*"
47   -
48   -NOTE: it is very important that the *.vcl files are included in that order,
49   -i.e. *first* include "varnish-noosfero.vcl", and *after*
50   -"noosfero-accept-language.cvl".
51   -
52   -4c) Restart Varnish
53   -
54   - # invoke-rc.d varnish restart
55   -
56   -5) Enable varnish logging:
57   -
58   -5a) Edit /etc/default/varnishncsa and uncomment the line that contains:
59   -
60   -VARNISHNCSA_ENABLED=1
61   -
62   -The varnish log will be written to /var/log/varnish/varnishncsa.log in an
63   -apache-compatible format. You should change your statistics generation software
64   -(e.g. awstats) to use that instead of apache logs.
65   -
66   -5b) Restart Varnish Logging service
67   -
68   - # invoke-rc.d varnishncsa restart
69   -
70   -Thanks to Cosimo Streppone for varnish-accept-language. See
71   -http://github.com/cosimo/varnish-accept-language for more information.
INSTALL.varnish.md 0 → 100644
... ... @@ -0,0 +1,63 @@
  1 +Setting up Varnish for your Noosfero site
  2 +=========================================
  3 +
  4 +Varnish is a HTTP caching server, and using it together with Noosfero is highly recommended. See http://www.varnish-cache.org/ for more information on Varnish.
  5 +
  6 +Varnish can be set up to use with Noosfero with the following steps:
  7 +
  8 +1) setup Noosfero with apache according to the `INSTALL.md` file. If you used the Debian package to install noosfero, you don't need to do anything about this.
  9 +
  10 +2) install Varnish
  11 +
  12 + # apt-get install varnish
  13 +
  14 +Install the RPAF apache module (or skip this step if not using apache):
  15 +
  16 + # apt-get install libapache2-mod-rpaf
  17 +
  18 +3) Change Apache to listen on port `8080` instead of `80`
  19 +
  20 +3a) Edit `/etc/apache2/ports.conf`, and:
  21 +
  22 + * change `NameVirtualHost *:80` to `NameVirtualHost *:8080`
  23 + * change `Listen 80` to `Listen 127.0.0.1:8080`
  24 +
  25 +3b) Edit `/etc/apache2/sites-enabled/*`, and change `<VirtualHost *:80>` to `<VirtualHost *:8080>`
  26 +
  27 +3c) Restart apache
  28 +
  29 + # invoke-rc.d apache2 restart
  30 +
  31 +4) Varnish configuration
  32 +
  33 +4a) Edit `/etc/default/varnish`
  34 +
  35 + * change the line that says `START=no` to say `START=yes`
  36 + * change `-a :6081` to `-a :80`
  37 +
  38 +4b) Edit `/etc/varnish/default.vcl` and add the following lines at the end:
  39 +
  40 + include "/etc/noosfero/varnish-noosfero.vcl";
  41 + include "/etc/noosfero/varnish-accept-language.vcl";
  42 +
  43 +On manual installations, change `/etc/noosfero/*` to `{Rails.root}/etc/noosfero/*`
  44 +
  45 +**NOTE**: it is very important that the `*.vcl` files are included in that order, i.e. *first* include `varnish-noosfero.vcl`, and *after* `noosfero-accept-language.cvl`.
  46 +
  47 +4c) Restart Varnish
  48 +
  49 + # invoke-rc.d varnish restart
  50 +
  51 +5) Enable varnish logging:
  52 +
  53 +5a) Edit `/etc/default/varnishncsa` and uncomment the line that contains:
  54 +
  55 + VARNISHNCSA_ENABLED=1
  56 +
  57 +The varnish log will be written to `/var/log/varnish/varnishncsa.log` in an apache-compatible format. You should change your statistics generation software (e.g. awstats) to use that instead of apache logs.
  58 +
  59 +5b) Restart Varnish Logging service
  60 +
  61 + # invoke-rc.d varnishncsa restart
  62 +
  63 +Thanks to Cosimo Streppone for varnish-accept-language. See http://github.com/cosimo/varnish-accept-language for more information.
... ...
... ... @@ -1,33 +0,0 @@
1   -Noosfero - a web-based social platform
2   -======================================
3   -
4   -http://www.noosfero.org/
5   -
6   -Documentation
7   --------------
8   -
9   -The following documentation is available:
10   -
11   -File Purpose
12   -~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
13   -INSTALL install instructions
14   -INSTALL.awstats install instructions - access statistics service
15   -INSTALL.chat install instructions - chat service
16   -INSTALL.email install instructions - email service
17   -INSTALL.multitenancy install instructions - multiple sites
18   -INSTALL.varnish install instructions - varnish HTTP caching (recommended)
19   -HACKING development instruction
20   -RELEASING instructions for doing releases
21   -doc/noosfero/* user documentation (available through the app itself)
22   -
23   -
24   -Authors and copyright
25   ----------------------
26   -
27   -Authorship and copyright information is available in the files listed below.
28   -
29   -File Purpose
30   -~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31   -AUTHORS list of authors (updated at each release)
32   -COPYRIGHT Copyright statement for the project
33   -COPYING Full text of the project license
README.md 0 → 100644
... ... @@ -0,0 +1,33 @@
  1 +Noosfero - a web-based social platform
  2 +======================================
  3 +
  4 +http://www.noosfero.org
  5 +
  6 +Documentation
  7 +-------------
  8 +
  9 +The following documentation is available:
  10 +
  11 + File Purpose
  12 + ----------------------- --------------------------------------------------------
  13 + INSTALL.md install instructions
  14 + INSTALL.awstats.md install instructions - access statistics service
  15 + INSTALL.chat.md install instructions - chat service
  16 + INSTALL.email.md install instructions - email service
  17 + INSTALL.multitenancy.md install instructions - multiple sites
  18 + INSTALL.varnish.md install instructions - varnish HTTP caching (recommended)
  19 + HACKING.md development instruction
  20 + RELEASING.md instructions for doing releases
  21 + doc/noosfero/* user documentation (available through the app itself)
  22 +
  23 +
  24 +Authors and copyright
  25 +---------------------
  26 +
  27 +Authorship and copyright information is available in the files listed below.
  28 +
  29 + File Purpose
  30 + -------------------- -----------------------------------------
  31 + AUTHORS.md list of authors (updated at each release)
  32 + COPYRIGHT Copyright statement for the project
  33 + COPYING Full text of the project license
... ...
README.rails
... ... @@ -1,183 +0,0 @@
1   -== Welcome to Rails
2   -
3   -Rails is a web-application and persistence framework that includes everything
4   -needed to create database-backed web-applications according to the
5   -Model-View-Control pattern of separation. This pattern splits the view (also
6   -called the presentation) into "dumb" templates that are primarily responsible
7   -for inserting pre-built data in between HTML tags. The model contains the
8   -"smart" domain objects (such as Account, Product, Person, Post) that holds all
9   -the business logic and knows how to persist themselves to a database. The
10   -controller handles the incoming requests (such as Save New Account, Update
11   -Product, Show Post) by manipulating the model and directing data to the view.
12   -
13   -In Rails, the model is handled by what's called an object-relational mapping
14   -layer entitled Active Record. This layer allows you to present the data from
15   -database rows as objects and embellish these data objects with business logic
16   -methods. You can read more about Active Record in
17   -link:files/vendor/rails/activerecord/README.html.
18   -
19   -The controller and view are handled by the Action Pack, which handles both
20   -layers by its two parts: Action View and Action Controller. These two layers
21   -are bundled in a single package due to their heavy interdependence. This is
22   -unlike the relationship between the Active Record and Action Pack that is much
23   -more separate. Each of these packages can be used independently outside of
24   -Rails. You can read more about Action Pack in
25   -link:files/vendor/rails/actionpack/README.html.
26   -
27   -
28   -== Getting started
29   -
30   -1. Start the web server: <tt>ruby script/server</tt> (run with --help for options)
31   -2. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!"
32   -3. Follow the guidelines to start developing your application
33   -
34   -
35   -== Web servers
36   -
37   -Rails uses the built-in web server in Ruby called WEBrick by default, so you don't
38   -have to install or configure anything to play around.
39   -
40   -If you have lighttpd installed, though, it'll be used instead when running script/server.
41   -It's considerably faster than WEBrick and suited for production use, but requires additional
42   -installation and currently only works well on OS X/Unix (Windows users are encouraged
43   -to start with WEBrick). We recommend version 1.4.11 and higher. You can download it from
44   -http://www.lighttpd.net.
45   -
46   -If you want something that's halfway between WEBrick and lighttpd, we heartily recommend
47   -Mongrel. It's a Ruby-based web server with a C-component (so it requires compilation) that
48   -also works very well with Windows. See more at http://mongrel.rubyforge.org/.
49   -
50   -But of course its also possible to run Rails with the premiere open source web server Apache.
51   -To get decent performance, though, you'll need to install FastCGI. For Apache 1.3, you want
52   -to use mod_fastcgi. For Apache 2.0+, you want to use mod_fcgid.
53   -
54   -See http://wiki.rubyonrails.com/rails/pages/FastCGI for more information on FastCGI.
55   -
56   -== Example for Apache conf
57   -
58   - <VirtualHost *:80>
59   - ServerName rails
60   - DocumentRoot /path/application/public/
61   - ErrorLog /path/application/log/server.log
62   -
63   - <Directory /path/application/public/>
64   - Options ExecCGI FollowSymLinks
65   - AllowOverride all
66   - Allow from all
67   - Order allow,deny
68   - </Directory>
69   - </VirtualHost>
70   -
71   -NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI
72   -should be on and ".cgi" should respond. All requests from 127.0.0.1 go
73   -through CGI, so no Apache restart is necessary for changes. All other requests
74   -go through FCGI (or mod_ruby), which requires a restart to show changes.
75   -
76   -
77   -== Debugging Rails
78   -
79   -Have "tail -f" commands running on both the server.log, production.log, and
80   -test.log files. Rails will automatically display debugging and runtime
81   -information to these files. Debugging info will also be shown in the browser
82   -on requests from 127.0.0.1.
83   -
84   -
85   -== Breakpoints
86   -
87   -Breakpoint support is available through the script/breakpointer client. This
88   -means that you can break out of execution at any point in the code, investigate
89   -and change the model, AND then resume execution! Example:
90   -
91   - class WeblogController < ActionController::Base
92   - def index
93   - @posts = Post.find_all
94   - breakpoint "Breaking out from the list"
95   - end
96   - end
97   -
98   -So the controller will accept the action, run the first line, then present you
99   -with a IRB prompt in the breakpointer window. Here you can do things like:
100   -
101   -Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
102   -
103   - >> @posts.inspect
104   - => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
105   - #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
106   - >> @posts.first.title = "hello from a breakpoint"
107   - => "hello from a breakpoint"
108   -
109   -...and even better is that you can examine how your runtime objects actually work:
110   -
111   - >> f = @posts.first
112   - => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
113   - >> f.
114   - Display all 152 possibilities? (y or n)
115   -
116   -Finally, when you're ready to resume execution, you press CTRL-D
117   -
118   -
119   -== Console
120   -
121   -You can interact with the domain model by starting the console through script/console.
122   -Here you'll have all parts of the application configured, just like it is when the
123   -application is running. You can inspect domain models, change values, and save to the
124   -database. Starting the script without arguments will launch it in the development environment.
125   -Passing an argument will specify a different environment, like <tt>script/console production</tt>.
126   -
127   -To reload your controllers and models after launching the console run <tt>reload!</tt>
128   -
129   -
130   -
131   -== Description of contents
132   -
133   -app
134   - Holds all the code that's specific to this particular application.
135   -
136   -app/controllers
137   - Holds controllers that should be named like weblog_controller.rb for
138   - automated URL mapping. All controllers should descend from
139   - ActionController::Base.
140   -
141   -app/models
142   - Holds models that should be named like post.rb.
143   - Most models will descend from ActiveRecord::Base.
144   -
145   -app/views
146   - Holds the template files for the view that should be named like
147   - weblog/index.rhtml for the WeblogController#index action. All views use eRuby
148   - syntax. This directory can also be used to keep stylesheets, images, and so on
149   - that can be symlinked to public.
150   -
151   -app/helpers
152   - Holds view helpers that should be named like weblog_helper.rb.
153   -
154   -app/apis
155   - Holds API classes for web services.
156   -
157   -config
158   - Configuration files for the Rails environment, the routing map, the database, and other dependencies.
159   -
160   -components
161   - Self-contained mini-applications that can bundle together controllers, models, and views.
162   -
163   -db
164   - Contains the database schema in schema.rb. db/migrate contains all
165   - the sequence of Migrations for your schema.
166   -
167   -lib
168   - Application specific libraries. Basically, any kind of custom code that doesn't
169   - belong under controllers, models, or helpers. This directory is in the load path.
170   -
171   -public
172   - The directory available for the web server. Contains subdirectories for images, stylesheets,
173   - and javascripts. Also contains the dispatchers and the default HTML files.
174   -
175   -script
176   - Helper scripts for automation and generation.
177   -
178   -test
179   - Unit and functional tests along with fixtures.
180   -
181   -vendor
182   - External libraries that the application depends on. Also includes the plugins subdirectory.
183   - This directory is in the load path.
README.rails.md 0 → 100644
... ... @@ -0,0 +1,138 @@
  1 +Welcome to Rails
  2 +================
  3 +
  4 +Rails is a web-application and persistence framework that includes everything needed to create database-backed web-applications according to the Model-View-Control pattern of separation. This pattern splits the view (also called the presentation) into "dumb" templates that are primarily responsible for inserting pre-built data in between HTML tags. The model contains the "smart" domain objects (such as Account, Product, Person, Post) that holds all the business logic and knows how to persist themselves to a database. The controller handles the incoming requests (such as Save New Account, Update Product, Show Post) by manipulating the model and directing data to the view.
  5 +
  6 +In Rails, the model is handled by what's called an object-relational mapping layer entitled Active Record. This layer allows you to present the data from database rows as objects and embellish these data objects with business logic methods. You can read more about Active Record in `.../rails/activerecord/README.html`.
  7 +
  8 +The controller and view are handled by the Action Pack, which handles both layers by its two parts: Action View and Action Controller. These two layers are bundled in a single package due to their heavy interdependence. This is unlike the relationship between the Active Record and Action Pack that is much more separate. Each of these packages can be used independently outside of Rails. You can read more about Action Pack in `.../rails/actionpack/README.html`.
  9 +
  10 +
  11 +Getting started
  12 +---------------
  13 +
  14 +1. Start the web server: `ruby script/server` (run with `--help` for options)
  15 +2. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!"
  16 +3. Follow the guidelines to start developing your application
  17 +
  18 +Web servers
  19 +-----------
  20 +
  21 +Rails uses the built-in web server in Ruby called WEBrick by default, so you don't have to install or configure anything to play around.
  22 +
  23 +If you have lighttpd installed, though, it'll be used instead when running script/server. It's considerably faster than WEBrick and suited for production use, but requires additional installation and currently only works well on OS X/Unix (Windows users are encouraged to start with WEBrick). We recommend version 1.4.11 and higher. You can download it from http://www.lighttpd.net.
  24 +
  25 +If you want something that's halfway between WEBrick and lighttpd, we heartily recommend Mongrel. It's a Ruby-based web server with a C-component (so it requires compilation) that also works very well with Windows. See more at http://mongrel.rubyforge.org/.
  26 +
  27 +But of course its also possible to run Rails with the premiere open source web server Apache. To get decent performance, though, you'll need to install FastCGI. For Apache 1.3, you want to use mod_fastcgi. For Apache 2.0+, you want to use mod_fcgid.
  28 +
  29 +See http://wiki.rubyonrails.com/rails/pages/FastCGI for more information on FastCGI.
  30 +
  31 +Example for Apache conf
  32 +-----------------------
  33 +
  34 + <VirtualHost *:80>
  35 + ServerName rails
  36 + DocumentRoot /path/application/public/
  37 + ErrorLog /path/application/log/server.log
  38 +
  39 + <Directory /path/application/public/>
  40 + Options ExecCGI FollowSymLinks
  41 + AllowOverride all
  42 + Allow from all
  43 + Order allow,deny
  44 + </Directory>
  45 + </VirtualHost>
  46 +
  47 +NOTE: Be sure that CGIs can be executed in that directory as well. So ExecCGI should be on and ".cgi" should respond. All requests from 127.0.0.1 go through CGI, so no Apache restart is necessary for changes. All other requests go through FCGI (or mod_ruby), which requires a restart to show changes.
  48 +
  49 +Debugging Rails
  50 +---------------
  51 +
  52 +Have "tail -f" commands running on both the server.log, production.log, and test.log files. Rails will automatically display debugging and runtime information to these files. Debugging info will also be shown in the browser on requests from 127.0.0.1.
  53 +
  54 +Breakpoints
  55 +-----------
  56 +
  57 +Breakpoint support is available through the script/breakpointer client. This means that you can break out of execution at any point in the code, investigate and change the model, AND then resume execution! Example:
  58 +
  59 + class WeblogController < ActionController::Base
  60 + def index
  61 + @posts = Post.find_all
  62 + breakpoint "Breaking out from the list"
  63 + end
  64 + end
  65 +
  66 +So the controller will accept the action, run the first line, then present you with a IRB prompt in the breakpointer window. Here you can do things like:
  67 +
  68 +Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
  69 +
  70 + >> @posts.inspect
  71 + => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
  72 + #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
  73 + >> @posts.first.title = "hello from a breakpoint"
  74 + => "hello from a breakpoint"
  75 +
  76 +...and even better is that you can examine how your runtime objects actually work:
  77 +
  78 + >> f = @posts.first
  79 + => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
  80 + >> f.
  81 + Display all 152 possibilities? (y or n)
  82 +
  83 +Finally, when you're ready to resume execution, you press CTRL-D
  84 +
  85 +Console
  86 +-------
  87 +
  88 +You can interact with the domain model by starting the console through script/console. Here you'll have all parts of the application configured, just like it is when the application is running. You can inspect domain models, change values, and save to the database. Starting the script without arguments will launch it in the development environment. Passing an argument will specify a different environment, like `script/console production`.
  89 +
  90 +To reload your controllers and models after launching the console run `reload!`
  91 +
  92 +Description of contents
  93 +-----------------------
  94 +
  95 +* `app`
  96 + Holds all the code that's specific to this particular application.
  97 +
  98 +* `app/controllers`
  99 + Holds controllers that should be named like weblog_controller.rb for automated URL mapping. All controllers should descend from `ActionController::Base`.
  100 +
  101 +* `app/models`
  102 + Holds models that should be named like post.rb. Most models will descend from `ActiveRecord::Base`.
  103 +
  104 +* `app/views`
  105 + Holds the template files for the view that should be named like `weblog/index.rhtml` for the `WeblogController#index` action. All views use eRuby syntax. This directory can also be used to keep stylesheets, images, and so on that can be symlinked to public.
  106 +
  107 +* `app/helpers`
  108 + Holds view helpers that should be named like `weblog_helper.rb`.
  109 +
  110 +* `app/apis`
  111 + Holds API classes for web services.
  112 +
  113 +* `config`
  114 + Configuration files for the Rails environment, the routing map, the database, and other dependencies.
  115 +
  116 +* `components`
  117 + Self-contained mini-applications that can bundle together controllers, models, and views.
  118 +
  119 +* `db`
  120 + Contains the database schema in `schema.rb`.
  121 +
  122 +* `db/migrate`
  123 + Contains all the sequence of Migrations for your schema.
  124 +
  125 +* `lib`
  126 + Application specific libraries. Basically, any kind of custom code that doesn't belong under controllers, models, or helpers. This directory is in the load path.
  127 +
  128 +* `public`
  129 + The directory available for the web server. Contains subdirectories for images, stylesheets, and javascripts. Also contains the dispatchers and the default HTML files.
  130 +
  131 +* `script`
  132 + Helper scripts for automation and generation.
  133 +
  134 +* `test`
  135 + Unit and functional tests along with fixtures.
  136 +
  137 +* `vendor`
  138 + External libraries that the application depends on. Also includes the plugins subdirectory. This directory is in the load path.
... ...
RELEASING
... ... @@ -1,40 +0,0 @@
1   -= Noosfero release tasks
2   -
3   -This file documents release-related activities.
4   -
5   -== Working with translations
6   -
7   -* Update translation files: <tt>rake updatepo</tt>. Then <tt>git commit</tt> them.
8   -* Send the PO files to the translators.
9   -* Get the PO files back from translators, put in po/ under the correct language
10   - name (e.,g. po/pt_BR/) and <tt>git commit</tt>.
11   -* test translations: <tt>rake makemo</tt> and browse the application on the web.
12   -
13   -== Releasing noosfero
14   -
15   -Considering you are on a Debian GNU/Linux or Debian-based system
16   - # apt-get install devscripts debhelper
17   -
18   -To prepare a release of noosfero, you must follow the steps below:
19   -
20   -* Finish all requirements and bugs assigned to the to-be-released version
21   -* Make sure all tests pass
22   -* Write release notes at the version's wiki topic
23   -* Generate packages with <tt>rake noosfero:release[(stable|test)]</tt>. This task will:
24   - * Update the version in lib/noosfero.rb and debian/changelog.
25   - * Create the tarbal and the deb pkg under pkg/ directory.
26   - * Create a git tag and push it.
27   - * Upload the pkg to the configured repository (if configured) on ~/.dput.cf.
28   -* Test that the tarball and deb package are ok
29   -* Go to the version's wiki topic and edit it to reflect the new reality
30   -* Edit the topic WebPreferences and update DEBIAN_REPOSITORY_TOPICS setting
31   -* Attach the generated packages to that topic. Before attaching calculate the
32   - sha1 of the package (with sha1sum and paste the SHA1 hash as comment in the
33   - attachment form)
34   -* Download the attached and verify the MD5 hash
35   -* Update an eventual demonstration version that you run.
36   -* Write an announcement e-mail to the relevant mailing lists pointing to the
37   - release notes, and maybe to the demonstration version.
38   -
39   -If you had any problem during these steps, you can do <tt>rake clobber_package</tt> to
40   -completely delete the generated packages and start the process again.
RELEASING.md 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +Noosfero release tasks
  2 +======================
  3 +
  4 +This file documents release-related activities.
  5 +
  6 +Working with translations
  7 +-------------------------
  8 +
  9 +* Update translation files: `rake updatepo`. Then `git commit` them.
  10 +* Send the PO files to the translators.
  11 +* Get the PO files back from translators, put in `po/` under the correct language name (e.,g. `po/pt_BR/`) and `git commit`.
  12 +* test translations: `rake makemo` and browse the application on the web.
  13 +
  14 +Releasing noosfero
  15 +------------------
  16 +
  17 +Considering you are on a Debian GNU/Linux or Debian-based system
  18 +
  19 + # apt-get install devscripts debhelper
  20 +
  21 +To prepare a release of noosfero, you must follow the steps below:
  22 +
  23 +* Finish all requirements and bugs assigned to the to-be-released version
  24 +* Make sure all tests pass
  25 +* Write release notes at the version's wiki topic
  26 +* Generate packages with `rake noosfero:release[(stable|test)]`. This task will:
  27 + * Update the version in lib/noosfero.rb and debian/changelog.
  28 + * Create the tarbal and the deb pkg under pkg/ directory.
  29 + * Create a git tag and push it.
  30 + * Upload the pkg to the configured repository (if configured) on ~/.dput.cf.
  31 +* Test that the tarball and deb package are ok
  32 +* Go to the version's wiki topic and edit it to reflect the new reality
  33 +* Edit the topic WebPreferences and update DEBIAN_REPOSITORY_TOPICS setting
  34 +* Attach the generated packages to that topic. Before attaching calculate the sha1 of the package (with sha1sum and paste the SHA1 hash as comment in the attachment form)
  35 +* Download the attached and verify the MD5 hash
  36 +* Update an eventual demonstration version that you run.
  37 +* Write an announcement e-mail to the relevant mailing lists pointing to the release notes, and maybe to the demonstration version.
  38 +
  39 +If you had any problem during these steps, you can do `rake clobber_package` to completely delete the generated packages and start the process again.
... ...
app/controllers/admin/features_controller.rb
... ... @@ -2,7 +2,7 @@ class FeaturesController &lt; AdminController
2 2 protect 'edit_environment_features', :environment
3 3  
4 4 def index
5   - @features = Environment.available_features
  5 + @features = Environment.available_features.sort_by{|k,v|v}
6 6 end
7 7  
8 8 post_only :update
... ...
app/controllers/admin/users_controller.rb
... ... @@ -4,12 +4,52 @@ class UsersController &lt; AdminController
4 4  
5 5 protect 'manage_environment_users', :environment
6 6  
  7 + include UsersHelper
  8 +
7 9 def index
  10 + @filter = params[:filter]
  11 + scope = environment.people.no_templates
  12 + if @filter == 'admin_users'
  13 + scope = scope.admins
  14 + elsif @filter == 'activated_users'
  15 + scope = scope.activated
  16 + elsif @filter == 'deactivated_users'
  17 + scope = scope.deactivated
  18 + end
  19 + @q = params[:q]
  20 + @collection = find_by_contents(:people, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results]
  21 + end
  22 +
  23 + def set_admin_role
  24 + person = environment.people.find(params[:id])
  25 + environment.add_admin(person)
  26 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  27 + end
  28 +
  29 + def reset_admin_role
  30 + person = environment.people.find(params[:id])
  31 + environment.remove_admin(person)
  32 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  33 + end
  34 +
  35 + def activate
  36 + person = environment.people.find(params[:id])
  37 + person.user.activate
  38 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  39 + end
  40 +
  41 + def deactivate
  42 + person = environment.people.find(params[:id])
  43 + person.user.deactivate
  44 + redirect_to :action => :index, :q => params[:q], :filter => params[:filter]
  45 + end
  46 +
  47 + def download
8 48 respond_to do |format|
9 49 format.html
10 50 format.xml do
11   - @users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
12   - send_data @users.to_xml(
  51 + users = User.find(:all, :conditions => {:environment_id => environment.id}, :include => [:person])
  52 + send_data users.to_xml(
13 53 :skip_types => true,
14 54 :only => %w[email login created_at updated_at],
15 55 :include => { :person => {:only => %w[name updated_at created_at address birth_date contact_phone identifier lat lng] } }),
... ... @@ -45,4 +85,10 @@ class UsersController &lt; AdminController
45 85 end
46 86 end
47 87  
  88 + private
  89 +
  90 + def per_page
  91 + 10
  92 + end
  93 +
48 94 end
... ...
app/controllers/application_controller.rb
... ... @@ -2,7 +2,7 @@ class ApplicationController &lt; ActionController::Base
2 2  
3 3 before_filter :setup_multitenancy
4 4 before_filter :detect_stuff_by_domain
5   - before_filter :init_noosfero_plugins
  5 + before_filter :init_noosfero_plugins_controller_filters
6 6 before_filter :allow_cross_domain_access
7 7  
8 8 def allow_cross_domain_access
... ... @@ -21,8 +21,12 @@ class ApplicationController &lt; ActionController::Base
21 21 include ApplicationHelper
22 22 layout :get_layout
23 23 def get_layout
24   - prepend_view_path('public/' + theme_path)
25   - theme_option(:layout) || 'application'
  24 + theme_layout = theme_option(:layout)
  25 + if theme_layout
  26 + theme_view_file('layouts/'+theme_layout) || theme_layout
  27 + else
  28 + 'application'
  29 + end
26 30 end
27 31  
28 32 filter_parameter_logging :password
... ... @@ -122,22 +126,21 @@ class ApplicationController &lt; ActionController::Base
122 126  
123 127 include Noosfero::Plugin::HotSpot
124 128  
125   - def init_noosfero_plugins
126   - plugins.each do |plugin|
127   - prepend_view_path(plugin.class.view_path)
128   - end
129   - init_noosfero_plugins_controller_filters
130   - end
131   -
132 129 # This is a generic method that initialize any possible filter defined by a
133 130 # plugin to the current controller being initialized.
134 131 def init_noosfero_plugins_controller_filters
135 132 plugins.each do |plugin|
136 133 filters = plugin.send(self.class.name.underscore + '_filters')
137 134 filters = [filters] if !filters.kind_of?(Array)
  135 + controller_filters = self.class.filter_chain.map {|c| c.method }
138 136 filters.each do |plugin_filter|
139   - self.class.send(plugin_filter[:type], plugin.class.name.underscore + '_' + plugin_filter[:method_name], (plugin_filter[:options] || {}))
140   - self.class.send(:define_method, plugin.class.name.underscore + '_' + plugin_filter[:method_name], plugin_filter[:block])
  137 + filter_method = plugin.class.name.underscore.gsub('/','_') + '_' + plugin_filter[:method_name]
  138 + unless controller_filters.include?(filter_method)
  139 + self.class.send(plugin_filter[:type], filter_method, (plugin_filter[:options] || {}))
  140 + self.class.send(:define_method, filter_method) do
  141 + instance_eval(&plugin_filter[:block]) if environment.plugin_enabled?(plugin.class)
  142 + end
  143 + end
141 144 end
142 145 end
143 146 end
... ... @@ -174,7 +177,7 @@ class ApplicationController &lt; ActionController::Base
174 177 end
175 178  
176 179 def find_by_contents(asset, scope, query, paginate_options={:page => 1}, options={})
177   - @plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) ||
  180 + plugins.dispatch_first(:find_by_contents, asset, scope, query, paginate_options, options) ||
178 181 fallback_find_by_contents(asset, scope, query, paginate_options, options)
179 182 end
180 183  
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -2,6 +2,8 @@ class CmsController &lt; MyProfileController
2 2  
3 3 protect 'edit_profile', :profile, :only => [:set_home_page]
4 4  
  5 + include ArticleHelper
  6 +
5 7 def self.protect_if(*args)
6 8 before_filter(*args) do |c|
7 9 user, profile = c.send(:user), c.send(:profile)
... ... @@ -64,20 +66,32 @@ class CmsController &lt; MyProfileController
64 66 end
65 67  
66 68 def edit
  69 + @success_back_to = params[:success_back_to]
67 70 @article = profile.articles.find(params[:id])
  71 + version = params[:version]
  72 + @article.revert_to(version) if version
  73 +
68 74 @parent_id = params[:parent_id]
69 75 @type = params[:type] || @article.class.to_s
70 76 translations if @article.translatable?
71 77 continue = params[:continue]
72 78  
  79 + @article.article_privacy_exceptions = params[:q].split(/,/).map{|n| environment.people.find n.to_i} unless params[:q].nil?
  80 +
  81 + @tokenized_children = prepare_to_token_input(
  82 + profile.members.includes(:articles_with_access).find_all{ |m|
  83 + m.articles_with_access.include?(@article)
  84 + }
  85 + )
73 86 refuse_blocks
74 87 record_coming
75 88 if request.post?
  89 + @article.image = nil if params[:remove_image] == 'true'
76 90 @article.last_changed_by = user
77 91 if @article.update_attributes(params[:article])
78 92 if !continue
79 93 if @article.content_type.nil? || @article.image?
80   - redirect_to @article.view_url
  94 + success_redirect
81 95 else
82 96 redirect_to :action => (@article.parent ? 'view' : 'index'), :id => @article.parent
83 97 end
... ... @@ -89,6 +103,7 @@ class CmsController &lt; MyProfileController
89 103 def new
90 104 # FIXME this method should share some logic wirh edit !!!
91 105  
  106 + @success_back_to = params[:success_back_to]
92 107 # user must choose an article type first
93 108  
94 109 @parent = profile.articles.find(params[:parent_id]) if params && params[:parent_id]
... ... @@ -129,11 +144,13 @@ class CmsController &lt; MyProfileController
129 144  
130 145 continue = params[:continue]
131 146 if request.post?
  147 + @article.article_privacy_exceptions = params[:q].split(/,/).map{|n| environment.people.find n.to_i} unless params[:q].nil?
  148 +
132 149 if @article.save
133 150 if continue
134 151 redirect_to :action => 'edit', :id => @article
135 152 else
136   - redirect_to @article.view_url
  153 + success_redirect
137 154 end
138 155 return
139 156 end
... ... @@ -144,10 +161,15 @@ class CmsController &lt; MyProfileController
144 161  
145 162 post_only :set_home_page
146 163 def set_home_page
147   - @article = profile.articles.find(params[:id])
148   - profile.home_page = @article
149   - profile.save(false)
150   - session[:notice] = _('"%s" configured as home page.') % @article.name
  164 + article = params[:id].nil? ? nil : profile.articles.find(params[:id])
  165 + profile.update_attribute(:home_page, article)
  166 +
  167 + if article.nil?
  168 + session[:notice] = _('Homepage reseted.')
  169 + else
  170 + session[:notice] = _('"%s" configured as homepage.') % article.name
  171 + end
  172 +
151 173 redirect_to (request.referer || profile.url)
152 174 end
153 175  
... ... @@ -284,6 +306,12 @@ class CmsController &lt; MyProfileController
284 306 render :text => article_list_to_json(results), :content_type => 'application/json'
285 307 end
286 308  
  309 + def search_article_privacy_exceptions
  310 + arg = params[:q].downcase
  311 + result = profile.members.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
  312 + render :text => prepare_to_token_input(result).to_json
  313 + end
  314 +
287 315 def media_upload
288 316 files_uploaded = []
289 317 parent = check_parent(params[:parent_id])
... ... @@ -380,5 +408,12 @@ class CmsController &lt; MyProfileController
380 408 true
381 409 end
382 410  
383   -end
  411 + def success_redirect
  412 + if !@success_back_to.blank?
  413 + redirect_to @success_back_to
  414 + else
  415 + redirect_to @article.view_url
  416 + end
  417 + end
384 418  
  419 +end
... ...
app/controllers/my_profile/memberships_controller.rb
1 1 class MembershipsController < MyProfileController
2 2  
3 3 protect 'manage_memberships', :profile
4   -
  4 +
5 5 def index
6   - @memberships = profile.memberships
  6 + @roles = environment.roles.select do |role|
  7 + ra = profile.role_assignments.find_by_role_id(role.id)
  8 + ra.present? && ra.resource_type == 'Profile'
  9 + end
  10 + @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  11 + begin
  12 + @memberships = @filter.nil? ? profile.memberships : profile.memberships_by_role(environment.roles.find(@filter))
  13 + rescue ActiveRecord::RecordNotFound
  14 + @memberships = []
  15 + end
7 16 end
8 17  
9 18 def new_community
10 19 @community = Community.new(params[:community])
11 20 @community.environment = environment
  21 + @back_to = params[:back_to] || url_for(:action => 'index')
12 22 if request.post? && @community.valid?
13 23 @community = Community.create_after_moderation(user, {:environment => environment}.merge(params[:community]))
14   - redirect_to :action => 'index'
  24 + redirect_to @back_to
15 25 return
16 26 end
17 27 end
... ...
app/controllers/public/account_controller.rb
... ... @@ -141,22 +141,34 @@ class AccountController &lt; ApplicationController
141 141 end
142 142 end
143 143  
144   - # The user requests a password change. She forgot her old password.
145   - #
146   - # Posts back.
  144 + include ForgotPasswordHelper
  145 + helper :forgot_password
  146 +
147 147 def forgot_password
148 148 if @plugins.dispatch(:allow_password_recovery).include?(false)
149 149 redirect_back_or_default(:controller => 'home')
150 150 session[:notice] = _("This environment doesn't allow password recovery.")
151 151 end
152   - @change_password = ChangePassword.new(params[:change_password])
  152 +
  153 + @change_password = ChangePassword.new
153 154  
154 155 if request.post?
155 156 begin
156   - @change_password.save!
  157 + requestors = fetch_requestors(params[:value])
  158 + raise ActiveRecord::RecordNotFound if requestors.blank? || params[:value].blank?
  159 +
  160 + requestors.each do |requestor|
  161 + ChangePassword.create!(:requestor => requestor)
  162 + end
157 163 render :action => 'password_recovery_sent'
158   - rescue ActiveRecord::RecordInvalid => e
159   - nil # just pass and render at the end of the action
  164 + rescue ActiveRecord::RecordNotFound
  165 + if params[:value].blank?
  166 + @change_password.errors.add_to_base(_('Can not recover user password with blank value.'))
  167 + else
  168 + @change_password.errors.add_to_base(_('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]])
  169 + end
  170 + rescue ActiveRecord::RecordInvald
  171 + @change_password.errors.add_to_base(_('Could not perform password recovery for the user.'))
160 172 end
161 173 end
162 174 end
... ... @@ -262,7 +274,7 @@ class AccountController &lt; ApplicationController
262 274 def user_data
263 275 user_data =
264 276 if logged_in?
265   - current_user.data_hash
  277 + current_user.data_hash(gravatar_default)
266 278 else
267 279 { }
268 280 end
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -9,6 +9,7 @@ class ContentViewerController &lt; ApplicationController
9 9  
10 10 def view_page
11 11 path = params[:page].join('/')
  12 + @version = params[:version].to_i
12 13  
13 14 if path.blank?
14 15 @page = profile.home_page
... ... @@ -27,22 +28,15 @@ class ContentViewerController &lt; ApplicationController
27 28 end
28 29 end
29 30  
30   - if !@page.nil? && !@page.display_to?(user)
31   - if !profile.public?
32   - private_profile_partial_parameters
33   - render :template => 'profile/_private_profile.rhtml', :status => 403
34   - else #if !profile.visible?
35   - message = _('You are not allowed to view this content.')
36   - message += ' ' + _('You can contact the owner of this profile to request access then.')
37   - render_access_denied(message)
38   - end
39   - return
40   - end
  31 + return unless allow_access_to_page(path)
41 32  
42   - # page not found, give error
43   - if @page.nil?
44   - render_not_found(@path)
45   - return
  33 + if @version > 0
  34 + return render_access_denied unless @page.display_versions?
  35 + @versioned_article = @page.versions.find_by_version(@version)
  36 + if @versioned_article && @page.versions.latest.version != @versioned_article.version
  37 + render :template => 'content_viewer/versioned_article.rhtml'
  38 + return
  39 + end
46 40 end
47 41  
48 42 if request.xhr? && params[:toolbar]
... ... @@ -52,6 +46,16 @@ class ContentViewerController &lt; ApplicationController
52 46  
53 47 redirect_to_translation if @page.profile.redirect_l10n
54 48  
  49 + if request.post?
  50 + if @page.forum? && @page.has_terms_of_use && params[:terms_accepted] == "true"
  51 + @page.add_agreed_user(user)
  52 + end
  53 + elsif !@page.parent.nil? && @page.parent.forum?
  54 + unless @page.parent.agrees_with_terms?(user)
  55 + redirect_to @page.parent.url
  56 + end
  57 + end
  58 +
55 59 # At this point the page will be showed
56 60 @page.hit
57 61  
... ... @@ -98,7 +102,7 @@ class ContentViewerController &lt; ApplicationController
98 102 end
99 103  
100 104 if @page.folder? && @page.gallery?
101   - @images = @page.images
  105 + @images = @page.images.select{ |a| a.display_to? user }
102 106 @images = @images.paginate(:per_page => per_page, :page => params[:npage]) unless params[:slideshow]
103 107 end
104 108  
... ... @@ -120,8 +124,17 @@ class ContentViewerController &lt; ApplicationController
120 124 end
121 125 end
122 126  
123   - def versioning_articles(string1, string2)
124   - Diffy::Diff.new('string1', 'string2').to_s(:html)
  127 + def differences_between_article_versions(version1, version2)
  128 + Diffy::Diff.new('version1', 'version2').to_s(:html)
  129 + end
  130 +
  131 + def article_versions
  132 + path = params[:page].join('/')
  133 + @page = profile.articles.find_by_path(path)
  134 + return unless allow_access_to_page(path)
  135 +
  136 + render_access_denied unless @page.display_versions?
  137 + @versions = @page.versions.paginate(:per_page => per_page, :page => params[:npage])
125 138 end
126 139  
127 140 protected
... ... @@ -154,6 +167,24 @@ class ContentViewerController &lt; ApplicationController
154 167 end
155 168 helper_method :pass_without_comment_captcha?
156 169  
  170 + def allow_access_to_page(path)
  171 + allowed = true
  172 + if @page.nil? # page not found, give error
  173 + render_not_found(path)
  174 + allowed = false
  175 + elsif !@page.display_to?(user)
  176 + if !profile.public?
  177 + private_profile_partial_parameters
  178 + render :template => 'profile/_private_profile.rhtml', :status => 403
  179 + allowed = false
  180 + else #if !profile.visible?
  181 + render_access_denied
  182 + allowed = false
  183 + end
  184 + end
  185 + allowed
  186 + end
  187 +
157 188 end
158 189  
159 190  
... ...
app/controllers/public/events_controller.rb
1 1 class EventsController < PublicController
2 2  
3 3 needs_profile
4   - no_design_blocks
5 4  
6 5 def events
7   - @selected_day = nil
8   - @events_of_the_day = []
9   - date = build_date(params[:year], params[:month], params[:day])
  6 + @events = []
  7 + @date = build_date(params[:year], params[:month], params[:day])
10 8  
11   - if params[:day] || !params[:year] && !params[:month]
12   - @selected_day = date
13   - @events_of_the_day = profile.events.by_day(@selected_day)
  9 + if !params[:year] && !params[:month] && !params[:day]
  10 + @events = profile.events.next_events_from_month(@date)
14 11 end
15 12  
16   - events = profile.events.by_range((date - 1.month).at_beginning_of_month..(date + 1.month).at_end_of_month)
  13 + if params[:year] || params[:month]
  14 + @events = profile.events.by_month(@date)
  15 + end
  16 +
  17 + events_in_range = profile.events.by_range((@date - 1.month).at_beginning_of_month .. (@date + 1.month).at_end_of_month)
17 18  
18   - @calendar = populate_calendar(date, events)
19   - @previous_calendar = populate_calendar(date - 1.month, events)
20   - @next_calendar = populate_calendar(date + 1.month, events)
  19 + @calendar = populate_calendar(@date, events_in_range)
21 20 end
22 21  
23 22 def events_by_day
24   - @selected_day = build_date(params[:year], params[:month], params[:day])
25   - @events_of_the_day = profile.events.by_day(@selected_day)
26   - render :partial => 'events_by_day'
  23 + @date = build_date(params[:year], params[:month], params[:day])
  24 + @events = profile.events.by_day(@date)
  25 + render :partial => 'events'
27 26 end
28 27  
29 28 protected
... ...
app/controllers/public/profile_controller.rb
... ... @@ -206,10 +206,50 @@ class ProfileController &lt; PublicController
206 206 end
207 207  
208 208 def view_more_network_activities
209   - @activities = @profile.tracked_notifications.paginate(:per_page => 10, :page => params[:page])
  209 + @activities = @profile.tracked_notifications.paginate(:per_page => 10, :page => params[:page])
210 210 render :partial => 'profile_network_activities', :locals => {:network_activities => @activities}
211 211 end
212 212  
  213 + def more_comments
  214 + activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity], :user_id => @profile})
  215 + comments_count = activity.comments.count
  216 + comment_page = (params[:comment_page] || 1).to_i
  217 + comments_per_page = 5
  218 + no_more_pages = comments_count <= comment_page * comments_per_page
  219 +
  220 + render :update do |page|
  221 + page.insert_html :bottom, 'profile-wall-activities-comments-'+params[:activity],
  222 + :partial => 'comment', :collection => activity.comments.paginate(:per_page => comments_per_page, :page => comment_page)
  223 +
  224 + if no_more_pages
  225 + page.remove 'profile-wall-activities-comments-more-'+params[:activity]
  226 + else
  227 + page.replace_html 'profile-wall-activities-comments-more-'+params[:activity],
  228 + :partial => 'more_comments', :locals => {:activity => activity, :comment_page => comment_page}
  229 + end
  230 + end
  231 + end
  232 +
  233 + def more_replies
  234 + activity = Scrap.find(:first, :conditions => {:id => params[:activity], :receiver_id => @profile, :scrap_id => nil})
  235 + comments_count = activity.replies.count
  236 + comment_page = (params[:comment_page] || 1).to_i
  237 + comments_per_page = 5
  238 + no_more_pages = comments_count <= comment_page * comments_per_page
  239 +
  240 + render :update do |page|
  241 + page.insert_html :bottom, 'profile-wall-activities-comments-'+params[:activity],
  242 + :partial => 'profile_scrap', :collection => activity.replies.paginate(:per_page => comments_per_page, :page => comment_page), :as => :scrap
  243 +
  244 + if no_more_pages
  245 + page.remove 'profile-wall-activities-comments-more-'+params[:activity]
  246 + else
  247 + page.replace_html 'profile-wall-activities-comments-more-'+params[:activity],
  248 + :partial => 'more_replies', :locals => {:activity => activity, :comment_page => comment_page}
  249 + end
  250 + end
  251 + end
  252 +
213 253 def remove_scrap
214 254 begin
215 255 scrap = current_user.person.scraps(params[:scrap_id])
... ... @@ -343,6 +383,7 @@ class ProfileController &lt; PublicController
343 383 end
344 384 end
345 385  
  386 +
346 387 protected
347 388  
348 389 def check_access_to_profile
... ... @@ -393,4 +434,5 @@ class ProfileController &lt; PublicController
393 434 def relations_to_include
394 435 [:image, :domains, :preferred_domain, :environment]
395 436 end
  437 +
396 438 end
... ...
app/controllers/public/search_controller.rb
... ... @@ -93,25 +93,27 @@ class SearchController &lt; PublicController
93 93 year = (params[:year] ? params[:year].to_i : Date.today.year)
94 94 month = (params[:month] ? params[:month].to_i : Date.today.month)
95 95 day = (params[:day] ? params[:day].to_i : Date.today.day)
96   - date = build_date(params[:year], params[:month], params[:day])
97   - date_range = (date - 1.month).at_beginning_of_month..(date + 1.month).at_end_of_month
  96 + @date = build_date(year, month, day)
  97 + date_range = (@date - 1.month).at_beginning_of_month..(@date + 1.month).at_end_of_month
98 98  
99   - @selected_day = nil
100   - @events_of_the_day = []
  99 + @events = []
101 100 if params[:day] || !params[:year] && !params[:month]
102   - @selected_day = date
103   - @events_of_the_day = @category ?
104   - environment.events.by_day(@selected_day).in_category(Category.find(@category_id)) :
105   - environment.events.by_day(@selected_day)
  101 + @events = @category ?
  102 + environment.events.by_day(@date).in_category(Category.find(@category_id)) :
  103 + environment.events.by_day(@date)
  104 + end
  105 +
  106 + if params[:year] || params[:month]
  107 + @events = @category ?
  108 + environment.events.by_month(@date).in_category(Category.find(@category_id)) :
  109 + environment.events.by_month(@date)
106 110 end
107 111  
108 112 @scope = date_range && params[:action] == 'events' ? environment.events.by_range(date_range) : environment.events
109 113 full_text_search
110 114  
111 115 events = @searches[@asset][:results]
112   - @calendar = populate_calendar(date, events)
113   - @previous_calendar = populate_calendar(date - 1.month, events)
114   - @next_calendar = populate_calendar(date + 1.month, events)
  116 + @calendar = populate_calendar(@date, events)
115 117 end
116 118  
117 119 # keep old URLs workings
... ... @@ -136,9 +138,9 @@ class SearchController &lt; PublicController
136 138 end
137 139  
138 140 def events_by_day
139   - @selected_day = build_date(params[:year], params[:month], params[:day])
140   - @events_of_the_day = environment.events.by_day(@selected_day)
141   - render :partial => 'events/events_by_day'
  141 + @date = build_date(params[:year], params[:month], params[:day])
  142 + @events = environment.events.by_day(@date)
  143 + render :partial => 'events/events'
142 144 end
143 145  
144 146 #######################################################
... ...
app/helpers/application_helper.rb
... ... @@ -38,6 +38,10 @@ module ApplicationHelper
38 38  
39 39 include LayoutHelper
40 40  
  41 + include Noosfero::Gravatar
  42 +
  43 + include TokenHelper
  44 +
41 45 def locale
42 46 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale
43 47 end
... ... @@ -366,7 +370,7 @@ module ApplicationHelper
366 370 def current_theme
367 371 @current_theme ||=
368 372 begin
369   - if (session[:theme])
  373 + if session[:theme]
370 374 session[:theme]
371 375 else
372 376 # utility for developers: set the theme to 'random' in development mode and
... ... @@ -375,7 +379,7 @@ module ApplicationHelper
375 379 if ENV['RAILS_ENV'] == 'development' && environment.theme == 'random'
376 380 @random_theme ||= Dir.glob('public/designs/themes/*').map { |f| File.basename(f) }.rand
377 381 @random_theme
378   - elsif ENV['RAILS_ENV'] == 'development' && params[:theme] && File.exists?(File.join(Rails.root, 'public/designs/themes', params[:theme]))
  382 + elsif ENV['RAILS_ENV'] == 'development' && respond_to?(:params) && params[:theme] && File.exists?(File.join(Rails.root, 'public/designs/themes', params[:theme]))
379 383 params[:theme]
380 384 else
381 385 if profile && !profile.theme.nil?
... ... @@ -397,16 +401,24 @@ module ApplicationHelper
397 401 end
398 402 end
399 403  
400   - def theme_include(template)
  404 + def theme_view_file(template)
401 405 ['.rhtml', '.html.erb'].each do |ext|
402   - file = (RAILS_ROOT + '/public' + theme_path + '/' + template + ext)
403   - if File.exists?(file)
404   - return render :file => file, :use_full_path => false
405   - end
  406 + file = (RAILS_ROOT + '/public' + theme_path + '/' + template + ext)
  407 + return file if File.exists?(file)
406 408 end
407 409 nil
408 410 end
409 411  
  412 + def theme_include(template, options = {})
  413 + file = theme_view_file(template)
  414 + options.merge!({:file => file, :use_full_path => false})
  415 + if file
  416 + render options
  417 + else
  418 + nil
  419 + end
  420 + end
  421 +
410 422 def theme_favicon
411 423 return '/designs/themes/' + current_theme + '/favicon.ico' if profile.nil? || profile.theme.nil?
412 424 if File.exists?(File.join(RAILS_ROOT, 'public', theme_path, 'favicon.ico'))
... ... @@ -589,33 +601,8 @@ module ApplicationHelper
589 601 :class => 'vcard'), :class => 'common-profile-list-block')
590 602 end
591 603  
592   - def gravatar_url_for(email, options = {})
593   - # Ta dando erro de roteamento
594   - default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil
595   - url_for( { :gravatar_id => Digest::MD5.hexdigest(email.to_s),
596   - :host => 'www.gravatar.com',
597   - :protocol => 'http://',
598   - :only_path => false,
599   - :controller => 'avatar.php',
600   - :d => default
601   - }.merge(options) )
602   - end
603   -
604   - def str_gravatar_url_for(email, options = {})
605   - default = theme_option['gravatar'] || NOOSFERO_CONF['gravatar'] || nil
606   - url = 'http://www.gravatar.com/avatar.php?gravatar_id=' +
607   - Digest::MD5.hexdigest(email.to_s)
608   - {
609   - :only_path => false,
610   - :d => default
611   - }.merge(options).each { |k,v|
612   - url += ( '&%s=%s' % [ k,v ] )
613   - }
614   - url
615   - end
616   -
617   - def gravatar_profile_url(email)
618   - 'http://www.gravatar.com/'+ Digest::MD5.hexdigest(email.to_s)
  604 + def gravatar_default
  605 + (respond_to?(:theme_option) && theme_option.present? && theme_option['gravatar']) || NOOSFERO_CONF['gravatar']
619 606 end
620 607  
621 608 attr_reader :environment
... ... @@ -940,7 +927,7 @@ module ApplicationHelper
940 927 (@category ? " - #{@category.full_name}" : '')
941 928 end
942 929  
943   - # DEPRECATED. Do not use this·
  930 + # DEPRECATED. Do not use this.
944 931 def import_controller_stylesheets(options = {})
945 932 stylesheet_import( "controller_"+ @controller.controller_name(), options )
946 933 end
... ... @@ -1141,12 +1128,12 @@ module ApplicationHelper
1141 1128 end
1142 1129  
1143 1130 def manage_enterprises
1144   - return unless user
  1131 + return unless user && user.environment.enabled?(:display_my_enterprises_on_user_menu)
1145 1132 manage_link(user.enterprises, :enterprises)
1146 1133 end
1147 1134  
1148 1135 def manage_communities
1149   - return unless user && user.environment.enabled?('display_my_communities_on_user_menu')
  1136 + return unless user && user.environment.enabled?(:display_my_communities_on_user_menu)
1150 1137 administered_communities = user.communities.more_popular.select {|c| c.admins.include? user}
1151 1138 manage_link(administered_communities, :communities)
1152 1139 end
... ... @@ -1158,12 +1145,12 @@ module ApplicationHelper
1158 1145 pending_tasks_count = link_to(count.to_s, @environment.top_url + '/myprofile/{login}/tasks', :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1159 1146 end
1160 1147  
1161   - (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) +
  1148 + (_("<span class='welcome'>Welcome,</span> %s") % link_to('<i style="background-image:url({avatar})"></i><strong>{login}</strong>', @environment.top_url + '/{login}', :id => "homepage-link", :title => _('Go to your homepage'))) +
1162 1149 render_environment_features(:usermenu) +
1163   - link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :id => "controlpanel", :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +
  1150 + link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', @environment.top_url + '/admin', :title => _("Configure the environment"), :class => 'admin-link', :style => 'display: none') +
1164 1151 manage_enterprises.to_s +
1165 1152 manage_communities.to_s +
1166   - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :id => "controlpanel", :title => _("Configure your personal account and content")) +
  1153 + link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', @environment.top_url + '/myprofile/{login}', :class => 'ctrl-panel', :title => _("Configure your personal account and content")) +
1167 1154 pending_tasks_count +
1168 1155 link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system"))
1169 1156 end
... ... @@ -1315,10 +1302,6 @@ module ApplicationHelper
1315 1302 content_tag(:div, content_tag(:ul, titles) + raw(contents), :class => 'ui-tabs')
1316 1303 end
1317 1304  
1318   - def jquery_token_input_messages_json(hintText = _('Type in an keyword'), noResultsText = _('No results'), searchingText = _('Searching...'))
1319   - "hintText: '#{hintText}', noResultsText: '#{noResultsText}', searchingText: '#{searchingText}'"
1320   - end
1321   -
1322 1305 def delete_article_message(article)
1323 1306 if article.folder?
1324 1307 _("Are you sure that you want to remove the folder \"#{article.name}\"? Note that all the items inside it will also be removed!")
... ... @@ -1340,8 +1323,8 @@ module ApplicationHelper
1340 1323 @plugins.dispatch("content_remove_#{action.to_s}", @page).include?(true)
1341 1324 end
1342 1325  
1343   - def template_options(klass, field_name)
1344   - templates = klass.templates(environment)
  1326 + def template_options(kind, field_name)
  1327 + templates = environment.send(kind).templates
1345 1328 return '' if templates.count == 0
1346 1329 return hidden_field_tag("#{field_name}[template_id]", templates.first.id) if templates.count == 1
1347 1330  
... ... @@ -1359,50 +1342,6 @@ module ApplicationHelper
1359 1342 )
1360 1343 end
1361 1344  
1362   - def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {})
1363   - options[:min_chars] ||= 3
1364   - options[:hint_text] ||= _("Type in a search term")
1365   - options[:no_results_text] ||= _("No results")
1366   - options[:searching_text] ||= _("Searching...")
1367   - options[:search_delay] ||= 1000
1368   - options[:prevent_duplicates] ||= true
1369   - options[:backspace_delete_item] ||= false
1370   - options[:focus] ||= false
1371   - options[:avoid_enter] ||= true
1372   - options[:on_result] ||= 'null'
1373   - options[:on_add] ||= 'null'
1374   - options[:on_delete] ||= 'null'
1375   - options[:on_ready] ||= 'null'
1376   -
1377   - result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id})))
1378   - result += javascript_tag("jQuery('##{element_id}')
1379   - .tokenInput('#{url_for(search_action)}', {
1380   - minChars: #{options[:min_chars].to_json},
1381   - prePopulate: #{options[:pre_populate].to_json},
1382   - hintText: #{options[:hint_text].to_json},
1383   - noResultsText: #{options[:no_results_text].to_json},
1384   - searchingText: #{options[:searching_text].to_json},
1385   - searchDelay: #{options[:serach_delay].to_json},
1386   - preventDuplicates: #{options[:prevent_duplicates].to_json},
1387   - backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
1388   - queryParam: #{name.to_json},
1389   - tokenLimit: #{options[:token_limit].to_json},
1390   - onResult: #{options[:on_result]},
1391   - onAdd: #{options[:on_add]},
1392   - onDelete: #{options[:on_delete]},
1393   - onReady: #{options[:on_ready]},
1394   - });
1395   - ")
1396   - result += javascript_tag("jQuery('##{element_id}').focus();") if options[:focus]
1397   - if options[:avoid_enter]
1398   - result += javascript_tag("jQuery('#token-input-#{element_id}')
1399   - .live('keydown', function(event){
1400   - if(event.keyCode == '13') return false;
1401   - });")
1402   - end
1403   - result
1404   - end
1405   -
1406 1345 def expirable_content_reference(content, action, text, url, options = {})
1407 1346 reason = @plugins.dispatch("content_expire_#{action.to_s}", content).first
1408 1347 options[:title] = reason
... ... @@ -1431,8 +1370,8 @@ module ApplicationHelper
1431 1370 end
1432 1371  
1433 1372 def filter_html(html, source)
1434   - if @plugins && source.has_macro?
1435   - html = convert_macro(html, source)
  1373 + if @plugins && source && source.has_macro?
  1374 + html = convert_macro(html, source) unless @plugins.enabled_macros.blank?
1436 1375 #TODO This parse should be done through the macro infra, but since there
1437 1376 # are old things that do not support it we are keeping this hot spot.
1438 1377 html = @plugins.pipeline(:parse_content, html, source).first
... ... @@ -1463,4 +1402,8 @@ module ApplicationHelper
1463 1402 content.nil? ? '' : content.id.to_s
1464 1403 end
1465 1404  
  1405 + def display_article_versions(article, version = nil)
  1406 + content_tag('ul', article.versions.map {|v| link_to("r#{v.version}", @page.url.merge(:version => v.version))})
  1407 + end
  1408 +
1466 1409 end
... ...
app/helpers/article_helper.rb
1 1 module ArticleHelper
2 2  
3   - def custom_options_for_article(article)
  3 + include TokenHelper
  4 +
  5 + def custom_options_for_article(article, tokenized_children)
4 6 @article = article
5   - content_tag('h4', _('Visibility')) +
6   - content_tag('div',
7   - content_tag('div',
8   - radio_button(:article, :published, true) +
9   - content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true')
10   - ) +
11   - content_tag('div',
12   - radio_button(:article, :published, false) +
13   - content_tag('label', _('Private'), :for => 'article_published_false')
14   - )
15   - ) +
  7 +
  8 + visibility_options(@article, tokenized_children) +
16 9 content_tag('h4', _('Options')) +
17 10 content_tag('div',
18 11 (article.profile.has_members? ?
... ... @@ -35,7 +28,7 @@ module ArticleHelper
35 28 'div',
36 29 check_box(:article, :notify_comments) +
37 30 content_tag('label', _('I want to receive a notification of each comment written by e-mail'), :for => 'article_notify_comments') +
38   - observe_field(:article_accept_comments, :function => "$('article_notify_comments').disabled = ! $('article_accept_comments').checked;$('article_moderate_comments').disabled = ! $('article_accept_comments').checked")
  31 + observe_field(:article_accept_comments, :function => "$('article_notify_comments').disabled = ! $('article_accept_comments').checked;$('article_moderate_comments').disabled = ! $('article_accept_comments').checked")
39 32 ) +
40 33  
41 34 content_tag(
... ... @@ -49,10 +42,40 @@ module ArticleHelper
49 42 'div',
50 43 check_box(:article, :display_hits) +
51 44 content_tag('label', _('I want this article to display the number of hits it received'), :for => 'article_display_hits')
  45 + ) : '') +
  46 +
  47 + (article.can_display_versions? ?
  48 + content_tag(
  49 + 'div',
  50 + check_box(:article, :display_versions) +
  51 + content_tag('label', _('I want this article to display a link to older versions'), :for => 'article_display_versions')
52 52 ) : '')
  53 +
53 54 )
54 55 end
55 56  
  57 + def visibility_options(article, tokenized_children)
  58 + content_tag('h4', _('Visibility')) +
  59 + content_tag('div',
  60 + content_tag('div',
  61 + radio_button(:article, :published, true) +
  62 + content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true')
  63 + ) +
  64 + content_tag('div',
  65 + radio_button(:article, :published, false) +
  66 + content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private")
  67 + ) +
  68 + (article.profile.community? ? content_tag('div',
  69 + content_tag('label', _('Fill in the search field to add the exception users to see this content'), :id => "text-input-search-exception-users") +
  70 + token_input_field_tag(:q, 'search-article-privacy-exceptions', {:action => 'search_article_privacy_exceptions'},
  71 + {:focus => false, :hint_text => _('Type in a search term for a user'), :pre_populate => tokenized_children})) :
  72 + ''))
  73 + end
  74 +
  75 + def prepare_to_token_input(array)
  76 + array.map { |object| {:id => object.id, :name => object.name} }
  77 + end
  78 +
56 79 def cms_label_for_new_children
57 80 _('New article')
58 81 end
... ...
app/helpers/blog_helper.rb
1 1 module BlogHelper
2 2  
3   - def custom_options_for_article(article)
  3 + include ArticleHelper
  4 +
  5 + def custom_options_for_article(article,tokenized_children)
4 6 @article = article
5 7 hidden_field_tag('article[published]', 1) +
6   - hidden_field_tag('article[accept_comments]', 0)
  8 + hidden_field_tag('article[accept_comments]', 0) +
  9 + visibility_options(article,tokenized_children)
7 10 end
8 11  
9 12 def cms_label_for_new_children
... ...
app/helpers/box_organizer_helper.rb
... ... @@ -4,4 +4,10 @@ module BoxOrganizerHelper
4 4 render :partial => 'icon_selector', :locals => { :icon => icon }
5 5 end
6 6  
7   -end
  7 + def extra_option_checkbox(option)
  8 + if [:human_name, :name, :value, :checked, :options].all? {|k| option.key? k}
  9 + labelled_check_box(option[:human_name], option[:name], option[:value], option[:checked], option[:options])
  10 + end
  11 + end
  12 +
  13 +end
8 14 \ No newline at end of file
... ...
app/helpers/boxes_helper.rb
... ... @@ -102,14 +102,16 @@ module BoxesHelper
102 102  
103 103 result = filter_html(result, block)
104 104  
105   - box_decorator.block_target(block.box, block) +
106   - content_tag('div',
107   - content_tag('div',
  105 + content_tag('div',
  106 + box_decorator.block_target(block.box, block) +
  107 + content_tag('div',
108 108 content_tag('div',
109   - result + footer_content + box_decorator.block_edit_buttons(block),
110   - :class => 'block-inner-2'),
111   - :class => 'block-inner-1'),
112   - options) +
  109 + content_tag('div',
  110 + result + footer_content + box_decorator.block_edit_buttons(block),
  111 + :class => 'block-inner-2'),
  112 + :class => 'block-inner-1'),
  113 + options),
  114 + :class => 'block-outer') +
113 115 box_decorator.block_handle(block)
114 116 end
115 117  
... ... @@ -225,15 +227,11 @@ module BoxesHelper
225 227  
226 228 # DEPRECATED. Do not use this.
227 229 def import_blocks_stylesheets(options = {})
228   - @blocks_css_files ||= current_blocks.map{|b|'blocks/' + block_css_class_name(b)}.uniq
  230 + @blocks_css_files ||= current_blocks.map{|block|'blocks/' + block.class.name.to_css_class}.uniq
229 231 stylesheet_import(@blocks_css_files, options)
230 232 end
231   -
232   - def block_css_class_name(block)
233   - block.class.name.underscore.gsub('_', '-')
234   - end
235 233 def block_css_classes(block)
236   - classes = block_css_class_name(block)
  234 + classes = block.class.name.to_css_class
237 235 classes += ' invisible-block' if block.display == 'never'
238 236 classes
239 237 end
... ...
app/helpers/categories_helper.rb
... ... @@ -3,10 +3,21 @@ module CategoriesHelper
3 3  
4 4 COLORS = [
5 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 ],
  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]
10 21 ]
11 22  
12 23 TYPES = [
... ...
app/helpers/cms_helper.rb
... ... @@ -22,9 +22,9 @@ module CmsHelper
22 22  
23 23 attr_reader :environment
24 24  
25   - def options_for_article(article)
  25 + def options_for_article(article, tokenized_children=nil)
26 26 article_helper = helper_for_article(article)
27   - article_helper.custom_options_for_article(article)
  27 + article_helper.custom_options_for_article(article, tokenized_children)
28 28 end
29 29  
30 30 def link_to_article(article)
... ...
app/helpers/dates_helper.rb
... ... @@ -35,6 +35,18 @@ module DatesHelper
35 35 end
36 36 end
37 37  
  38 + def show_date_month(date, use_numbers = false, year=true)
  39 + if date && use_numbers
  40 + date_format = year ? _('%{month}/%{year}') : _('%{month}/%{day}')
  41 + date_format % { :month => date.month, :year => date.year }
  42 + elsif date
  43 + date_format = year ? _('%{month_name}, %{year}') : _('%{month_name}')
  44 + date_format % { :month_name => month_name(date.month), :year => date.year }
  45 + else
  46 + ''
  47 + end
  48 + end
  49 +
38 50 # formats a datetime for displaying.
39 51 def show_time(time)
40 52 if time
... ... @@ -98,7 +110,11 @@ module DatesHelper
98 110 elsif opts[:previous]
99 111 date = date << 1
100 112 end
101   - _('%{month} %{year}') % { :year => date.year, :month => month_name(date.month.to_i) }
  113 + if opts[:only_month]
  114 + _('%{month}') % {:month => month_name(date.month.to_i) }
  115 + else
  116 + _('%{month} %{year}') % { :year => date.year, :month => month_name(date.month.to_i) }
  117 + end
102 118 end
103 119  
104 120 def build_date(year, month, day = 1)
... ... @@ -123,7 +139,7 @@ module DatesHelper
123 139 previous_month_date = date - 1.month
124 140  
125 141 label ||= show_month(previous_month_date.year, previous_month_date.month)
126   - link_to label, :year => previous_month_date.year, :month => previous_month_date.month
  142 + button(:back, label, {:year => previous_month_date.year, :month => previous_month_date.month})
127 143 end
128 144  
129 145 def link_to_next_month(year, month, label = nil)
... ... @@ -131,7 +147,7 @@ module DatesHelper
131 147 next_month_date = date + 1.month
132 148  
133 149 label ||= show_month(next_month_date.year, next_month_date.month)
134   - link_to label, :year => next_month_date.year, :month => next_month_date.month
  150 + button(:next, label, {:year => next_month_date.year, :month => next_month_date.month})
135 151 end
136 152  
137 153 def pick_date(object, method, options = {}, html_options = {})
... ...
app/helpers/events_helper.rb
1 1 module EventsHelper
2 2  
3 3 def list_events(date, events)
4   - return content_tag('em', _("Select a day on the left to display it's events here"), :class => 'select-a-day') unless date
5   - title = _('Events for %s') % show_date(date)
  4 + title = _('Events for %s') % show_date_month(date)
6 5 content_tag('h2', title) +
7 6 content_tag('div',
8 7 (events.any? ?
9 8 content_tag('table', events.select { |item| item.display_to?(user) }.map {|item| display_event_in_listing(item)}.join('')) :
10   - content_tag('em', _('No events for this date'), :class => 'no-events')
  9 + content_tag('em', _('No events for this month'), :class => 'no-events')
11 10 ), :id => 'agenda-items'
12 11 )
13 12 end
14 13  
15 14 def display_event_in_listing(article)
16   - content_tag(
17   - 'tr',
18   - content_tag('td', link_to(article.name, article.url, :class => icon_for_article(article))),
19   - :class => 'agenda-item'
  15 +
  16 + content_tag( 'tr',
  17 + content_tag('td',
  18 + content_tag('div', show_date(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_date(article.end_date))),:class => 'event-date' ) +
  19 + content_tag('div',link_to(article.name,article.url),:class => 'event-title') +
  20 + content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place')
  21 + )
20 22 )
21 23 end
22 24  
... ...
app/helpers/folder_helper.rb
1 1 module FolderHelper
2 2  
3 3 include ShortFilename
  4 + include ArticleHelper
4 5  
5 6 def list_articles(articles, recursive = false)
6 7 if !articles.blank?
... ... @@ -60,19 +61,10 @@ module FolderHelper
60 61 "icon-new icon-new%s" % klass.icon_name
61 62 end
62 63  
63   - def custom_options_for_article(article)
  64 + def custom_options_for_article(article,tokenized_children)
64 65 @article = article
65   - content_tag('h4', _('Visibility')) +
66   - content_tag('div',
67   - content_tag('div',
68   - radio_button(:article, :published, true) +
69   - content_tag('label', _('Public (visible to other people)'), :for => 'article_published_true')
70   - ) +
71   - content_tag('div',
72   - radio_button(:article, :published, false) +
73   - content_tag('label', _('Private'), :for => 'article_published_false')
74   - )
75   - ) +
  66 +
  67 + visibility_options(article,tokenized_children) +
76 68 content_tag('div',
77 69 hidden_field_tag('article[accept_comments]', 0)
78 70 )
... ...
app/helpers/forgot_password_helper.rb 0 → 100644
... ... @@ -0,0 +1,43 @@
  1 +module ForgotPasswordHelper
  2 + def plugins_options
  3 + @plugins.dispatch(:change_password_fields)
  4 + end
  5 +
  6 + def user_fields
  7 + %w[login email] + plugins_options.select {|options| options[:model].to_sym == :user }.map { |options| options[:field].to_s }
  8 + end
  9 +
  10 + def person_fields
  11 + %w[] + plugins_options.select {|options| options[:model].to_sym == :person }.map { |options| options[:field].to_s }
  12 + end
  13 +
  14 + def fields
  15 + user_fields + person_fields
  16 + end
  17 +
  18 + def fields_label
  19 + labels = [
  20 + _('Username'),
  21 + _('Email'),
  22 + ] + plugins_options.map { |options| options[:name] }
  23 +
  24 + last = labels.pop
  25 + label = labels.join(', ')
  26 + "#{label} #{_('or')} #{last}"
  27 + end
  28 +
  29 + def build_query(fields, value)
  30 + fields.map {|field| "#{field} = '#{value}'"}.join(' OR ')
  31 + end
  32 +
  33 + def fetch_requestors(value)
  34 + requestors = []
  35 + person_query = build_query(person_fields, value)
  36 + user_query = build_query(user_fields, value)
  37 +
  38 + requestors += Person.where(person_query).where(:environment_id => environment.id) if person_fields.present?
  39 + requestors += User.where(user_query).where(:environment_id => environment.id).map(&:person) if user_fields.present?
  40 + requestors
  41 + end
  42 +
  43 +end
... ...
app/helpers/sweeper_helper.rb
... ... @@ -44,4 +44,30 @@ module SweeperHelper
44 44 def expire_profile_index(profile)
45 45 expire_timeout_fragment(profile.relationships_cache_key)
46 46 end
  47 +
  48 + def expire_blocks_cache(context, causes)
  49 + if context.kind_of?(Profile)
  50 + profile = context
  51 + environment = profile.environment
  52 + else
  53 + environment = context
  54 + profile = nil
  55 + end
  56 +
  57 + blocks_to_expire = []
  58 + if profile
  59 + profile.blocks.each {|block|
  60 + conditions = block.class.expire_on
  61 + blocks_to_expire << block unless (conditions[:profile] & causes).empty?
  62 + }
  63 + end
  64 + environment.blocks.each {|block|
  65 + conditions = block.class.expire_on
  66 + blocks_to_expire << block unless (conditions[:environment] & causes).empty?
  67 + }
  68 +
  69 + blocks_to_expire.uniq!
  70 + BlockSweeper.expire_blocks(blocks_to_expire)
  71 + end
  72 +
47 73 end
... ...
app/helpers/token_helper.rb 0 → 100644
... ... @@ -0,0 +1,51 @@
  1 +module TokenHelper
  2 +
  3 + def jquery_token_input_messages_json(hintText = _('Type in an keyword'), noResultsText = _('No results'), searchingText = _('Searching...'))
  4 + "hintText: '#{hintText}', noResultsText: '#{noResultsText}', searchingText: '#{searchingText}'"
  5 + end
  6 +
  7 + def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {})
  8 + options[:min_chars] ||= 3
  9 + options[:hint_text] ||= _("Type in a search term")
  10 + options[:no_results_text] ||= _("No results")
  11 + options[:searching_text] ||= _("Searching...")
  12 + options[:search_delay] ||= 1000
  13 + options[:prevent_duplicates] ||= true
  14 + options[:backspace_delete_item] ||= false
  15 + options[:focus] ||= false
  16 + options[:avoid_enter] ||= true
  17 + options[:on_result] ||= 'null'
  18 + options[:on_add] ||= 'null'
  19 + options[:on_delete] ||= 'null'
  20 + options[:on_ready] ||= 'null'
  21 +
  22 + result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id})))
  23 + result += javascript_tag("jQuery('##{element_id}')
  24 + .tokenInput('#{url_for(search_action)}', {
  25 + minChars: #{options[:min_chars].to_json},
  26 + prePopulate: #{options[:pre_populate].to_json},
  27 + hintText: #{options[:hint_text].to_json},
  28 + noResultsText: #{options[:no_results_text].to_json},
  29 + searchingText: #{options[:searching_text].to_json},
  30 + searchDelay: #{options[:serach_delay].to_json},
  31 + preventDuplicates: #{options[:prevent_duplicates].to_json},
  32 + backspaceDeleteItem: #{options[:backspace_delete_item].to_json},
  33 + queryParam: #{name.to_json},
  34 + tokenLimit: #{options[:token_limit].to_json},
  35 + onResult: #{options[:on_result]},
  36 + onAdd: #{options[:on_add]},
  37 + onDelete: #{options[:on_delete]},
  38 + onReady: #{options[:on_ready]},
  39 + });
  40 + ")
  41 + result += javascript_tag("jQuery('##{element_id}').focus();") if options[:focus]
  42 + if options[:avoid_enter]
  43 + result += javascript_tag("jQuery('#token-input-#{element_id}')
  44 + .live('keydown', function(event){
  45 + if(event.keyCode == '13') return false;
  46 + });")
  47 + end
  48 + result
  49 + end
  50 +
  51 +end
0 52 \ No newline at end of file
... ...
app/helpers/users_helper.rb 0 → 100644
... ... @@ -0,0 +1,25 @@
  1 +module UsersHelper
  2 +
  3 + FILTER_TRANSLATION = {
  4 + 'all_users' => _('All users'),
  5 + 'admin_users' => _('Admin users'),
  6 + 'activated_users' => _('Activated users'),
  7 + 'deactivated_users' => _('Deativated users'),
  8 + }
  9 +
  10 + def filter_selector(filter, float = 'right')
  11 + options = options_for_select(FILTER_TRANSLATION.map {|key, name| [name, key]}, :selected => filter)
  12 + url_params = url_for(params.merge(:filter => 'FILTER'))
  13 + onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)"
  14 + select_field = select_tag(:filter, options, :onchange => onchange)
  15 + content_tag('div',
  16 + content_tag('strong', _('Filter')) + ': ' + select_field,
  17 + :class => "environment-users-customize-search"
  18 + )
  19 + end
  20 +
  21 + def filter_title(filter)
  22 + FILTER_TRANSLATION[filter]
  23 + end
  24 +
  25 +end
... ...
app/models/article.rb
... ... @@ -2,6 +2,8 @@ require &#39;hpricot&#39;
2 2  
3 3 class Article < ActiveRecord::Base
4 4  
  5 + acts_as_having_image
  6 +
5 7 SEARCHABLE_FIELDS = {
6 8 :name => 10,
7 9 :abstract => 3,
... ... @@ -67,6 +69,7 @@ class Article &lt; ActiveRecord::Base
67 69 settings_items :allow_members_to_edit, :type => :boolean, :default => false
68 70 settings_items :moderate_comments, :type => :boolean, :default => false
69 71 settings_items :followers, :type => Array, :default => []
  72 + has_and_belongs_to_many :article_privacy_exceptions, :class_name => 'Person', :join_table => 'article_privacy_exceptions'
70 73  
71 74 belongs_to :reference_article, :class_name => "Article", :foreign_key => 'reference_article_id'
72 75  
... ... @@ -155,7 +158,7 @@ class Article &lt; ActiveRecord::Base
155 158 end
156 159  
157 160 def css_class_list
158   - [self.class.name.underscore.dasherize]
  161 + [self.class.name.to_css_class]
159 162 end
160 163  
161 164 def css_class_name
... ... @@ -198,6 +201,7 @@ class Article &lt; ActiveRecord::Base
198 201 acts_as_filesystem
199 202  
200 203 acts_as_versioned
  204 + self.non_versioned_columns << 'setting'
201 205  
202 206 def comment_data
203 207 comments.map {|item| [item.title, item.body].join(' ') }.join(' ')
... ... @@ -286,6 +290,11 @@ class Article &lt; ActiveRecord::Base
286 290 'text-html'
287 291 end
288 292  
  293 + # TODO Migrate the class method icon_name to instance methods.
  294 + def icon_name
  295 + self.class.icon_name(self)
  296 + end
  297 +
289 298 def mime_type
290 299 'text/html'
291 300 end
... ... @@ -348,22 +357,6 @@ class Article &lt; ActiveRecord::Base
348 357 true
349 358 end
350 359  
351   - def folder?
352   - false
353   - end
354   -
355   - def blog?
356   - false
357   - end
358   -
359   - def forum?
360   - false
361   - end
362   -
363   - def uploaded_file?
364   - false
365   - end
366   -
367 360 def has_posts?
368 361 false
369 362 end
... ... @@ -457,11 +450,12 @@ class Article &lt; ActiveRecord::Base
457 450 end
458 451  
459 452 named_scope :published, :conditions => { :published => true }
460   - named_scope :folders, :conditions => { :type => folder_types}
461   - named_scope :no_folders, :conditions => ['type NOT IN (?)', folder_types]
  453 + named_scope :folders, lambda {|profile|{:conditions => { :type => profile.folder_types} }}
  454 + named_scope :no_folders, lambda {|profile|{:conditions => ['type NOT IN (?)', profile.folder_types]}}
462 455 named_scope :galleries, :conditions => { :type => 'Gallery' }
463 456 named_scope :images, :conditions => { :is_image => true }
464 457 named_scope :text_articles, :conditions => [ 'articles.type IN (?)', text_article_types ]
  458 + named_scope :with_types, lambda { |types| { :conditions => [ 'articles.type IN (?)', types ] } }
465 459  
466 460 named_scope :more_popular, :order => 'hits DESC'
467 461 named_scope :more_comments, :order => "comments_count DESC"
... ... @@ -478,7 +472,8 @@ class Article &lt; ActiveRecord::Base
478 472  
479 473 def display_unpublished_article_to?(user)
480 474 user == author || allow_view_private_content?(user) || user == profile ||
481   - user.is_admin?(profile.environment) || user.is_admin?(profile)
  475 + user.is_admin?(profile.environment) || user.is_admin?(profile) ||
  476 + article_privacy_exceptions.include?(user)
482 477 end
483 478  
484 479 def display_to?(user = nil)
... ... @@ -594,17 +589,50 @@ class Article &lt; ActiveRecord::Base
594 589 false
595 590 end
596 591  
597   - def author
598   - if versions.empty?
599   - last_changed_by
600   - else
601   - author_id = versions.first.last_changed_by_id
  592 + def folder?
  593 + false
  594 + end
  595 +
  596 + def blog?
  597 + false
  598 + end
  599 +
  600 + def forum?
  601 + false
  602 + end
  603 +
  604 + def uploaded_file?
  605 + false
  606 + end
  607 +
  608 + settings_items :display_versions, :type => :boolean, :default => false
  609 +
  610 + def can_display_versions?
  611 + false
  612 + end
  613 +
  614 + def display_versions?
  615 + can_display_versions? && display_versions
  616 + end
  617 +
  618 + def author(version_number = nil)
  619 + if version_number
  620 + version = versions.find_by_version(version_number)
  621 + author_id = version.last_changed_by_id if version
602 622 Person.exists?(author_id) ? Person.find(author_id) : nil
  623 + else
  624 + if versions.empty?
  625 + last_changed_by
  626 + else
  627 + author_id = versions.first.last_changed_by_id
  628 + Person.exists?(author_id) ? Person.find(author_id) : nil
  629 + end
603 630 end
604 631 end
605 632  
606   - def author_name
607   - author ? author.name : (setting[:author_name] || _('Unknown'))
  633 + def author_name(version_number = nil)
  634 + person = version_number ? author(version_number) : author
  635 + person ? person.name : (setting[:author_name] || _('Unknown'))
608 636 end
609 637  
610 638 def author_url
... ... @@ -615,13 +643,20 @@ class Article &lt; ActiveRecord::Base
615 643 author ? author.id : nil
616 644 end
617 645  
  646 + def version_license(version_number = nil)
  647 + return license if version_number.nil?
  648 + profile.environment.licenses.find_by_id(versions.find_by_version(version_number).license_id)
  649 + end
  650 +
618 651 alias :active_record_cache_key :cache_key
619 652 def cache_key(params = {}, the_profile = nil, language = 'en')
620 653 active_record_cache_key+'-'+language +
621 654 (allow_post_content?(the_profile) ? "-owner" : '') +
622 655 (params[:npage] ? "-npage-#{params[:npage]}" : '') +
623 656 (params[:year] ? "-year-#{params[:year]}" : '') +
624   - (params[:month] ? "-month-#{params[:month]}" : '')
  657 + (params[:month] ? "-month-#{params[:month]}" : '') +
  658 + (params[:version] ? "-version-#{params[:version]}" : '')
  659 +
625 660 end
626 661  
627 662 def first_paragraph
... ...
app/models/article_block.rb
... ... @@ -23,7 +23,7 @@ class ArticleBlock &lt; Block
23 23 def article_id
24 24 self.settings[:article_id]
25 25 end
26   -
  26 +
27 27 def article_id= value
28 28 self.settings[:article_id] = value.blank? ? nil : value.to_i
29 29 end
... ... @@ -49,8 +49,8 @@ class ArticleBlock &lt; Block
49 49 end
50 50  
51 51 def available_articles
52   - return [] if self.box.nil? or self.box.owner.nil?
53   - self.box.owner.kind_of?(Environment) ? self.box.owner.portal_community.articles : self.box.owner.articles
  52 + return [] if self.owner.nil?
  53 + self.owner.kind_of?(Environment) ? self.owner.portal_community.articles : self.owner.articles
54 54 end
55 55  
56 56 def posts_per_page
... ... @@ -63,4 +63,9 @@ class ArticleBlock &lt; Block
63 63 end
64 64  
65 65 settings_items :visualization_format, :type => :string, :default => 'short'
  66 +
  67 + def self.expire_on
  68 + { :profile => [:article], :environment => [:article] }
  69 + end
  70 +
66 71 end
... ...
app/models/block.rb
... ... @@ -40,7 +40,7 @@ class Block &lt; ActiveRecord::Base
40 40 if context[:article]
41 41 return context[:article] != owner.home_page
42 42 else
43   - return context[:request_path] != '/' + owner.identifier
  43 + return context[:request_path] != '/' + (owner.kind_of?(Profile) ? owner.identifier : '')
44 44 end
45 45 end
46 46 end
... ... @@ -142,4 +142,30 @@ class Block &lt; ActiveRecord::Base
142 142 false
143 143 end
144 144  
  145 + # Override in your subclasses.
  146 + # Define which events and context should cause the block cache to expire
  147 + # Possible events are: :article, :profile, :friendship, :category
  148 + # Possible contexts are: :profile, :environment
  149 + def self.expire_on
  150 + {
  151 + :profile => [],
  152 + :environment => []
  153 + }
  154 + end
  155 +
  156 + DISPLAY_OPTIONS = {
  157 + 'always' => __('In all pages'),
  158 + 'home_page_only' => __('Only in the homepage'),
  159 + 'except_home_page' => __('In all pages, except in the homepage'),
  160 + 'never' => __('Don\'t display'),
  161 + }
  162 +
  163 + def display_options
  164 + DISPLAY_OPTIONS.keys
  165 + end
  166 +
  167 + def display_option_label(option)
  168 + DISPLAY_OPTIONS[option]
  169 + end
  170 +
145 171 end
... ...
app/models/blog.rb
... ... @@ -6,7 +6,7 @@ class Blog &lt; Folder
6 6 #FIXME This should be used until there is a migration to fix all blogs that
7 7 # already have folders inside them
8 8 def posts_with_no_folders
9   - posts_without_no_folders.no_folders
  9 + posts_without_no_folders.no_folders(profile)
10 10 end
11 11 alias_method_chain :posts, :no_folders
12 12  
... ...
app/models/blog_archives_block.rb
... ... @@ -45,4 +45,7 @@ class BlogArchivesBlock &lt; Block
45 45 content_tag('div', link_to(_('Subscribe RSS Feed'), owner_blog.feed.url), :class => 'subscribe-feed')
46 46 end
47 47  
  48 + def self.expire_on
  49 + { :profile => [:article], :environment => [:article] }
  50 + end
48 51 end
... ...
app/models/box.rb
... ... @@ -3,12 +3,15 @@ class Box &lt; ActiveRecord::Base
3 3 acts_as_list :scope => 'owner_id = #{owner_id} and owner_type = \'#{owner_type}\''
4 4 has_many :blocks, :dependent => :destroy, :order => 'position'
5 5  
  6 + include Noosfero::Plugin::HotSpot
  7 +
6 8 def environment
7 9 owner ? (owner.kind_of?(Environment) ? owner : owner.environment) : nil
8 10 end
9 11  
10 12 def acceptable_blocks
11   - to_css_class_name central? ? Box.acceptable_center_blocks : Box.acceptable_side_blocks
  13 + blocks_classes = central? ? Box.acceptable_center_blocks + plugins.dispatch(:extra_blocks, :position => 1) : Box.acceptable_side_blocks + plugins.dispatch(:extra_blocks, :position => [2, 3])
  14 + to_css_class_name(blocks_classes)
12 15 end
13 16  
14 17 def central?
... ... @@ -74,8 +77,8 @@ class Box &lt; ActiveRecord::Base
74 77  
75 78 private
76 79  
77   - def to_css_class_name(blocks)
78   - blocks.map{ |block| block.to_s.underscore.tr('_', '-') }
  80 + def to_css_class_name(blocks_classes)
  81 + blocks_classes.map{ |block_class| block_class.name.to_css_class }
79 82 end
80 83  
81 84 end
... ...
app/models/categories_block.rb
... ... @@ -35,4 +35,7 @@ class CategoriesBlock &lt; Block
35 35 end
36 36 end
37 37  
  38 + def self.expire_on
  39 + { :profile => [], :environment => [:category] }
  40 + end
38 41 end
... ...
app/models/category.rb
... ... @@ -12,7 +12,7 @@ class Category &lt; ActiveRecord::Base
12 12 validates_uniqueness_of :slug,:scope => [ :environment_id, :parent_id ], :message => N_('{fn} is already being used by another category.').fix_i18n
13 13 belongs_to :environment
14 14  
15   - validates_inclusion_of :display_color, :in => [ 1, 2, 3, 4, nil ]
  15 + validates_inclusion_of :display_color, :in => 1..15, :allow_nil => true
16 16 validates_uniqueness_of :display_color, :scope => :environment_id, :if => (lambda { |cat| ! cat.display_color.nil? }), :message => N_('{fn} was already assigned to another category.').fix_i18n
17 17  
18 18 # Finds all top level categories for a given environment.
... ...
app/models/change_password.rb
1 1 class ChangePassword < Task
2 2  
3   - attr_accessor :login, :email, :password, :password_confirmation, :environment_id
  3 + attr_accessor :password, :password_confirmation
4 4  
5 5 def self.human_attribute_name(attrib)
6 6 case attrib.to_sym
7   - when :login:
8   - _('Username')
9   - when :email
10   - _('e-mail')
11 7 when :password
12 8 _('Password')
13 9 when :password_confirmation
... ... @@ -17,29 +13,7 @@ class ChangePassword &lt; Task
17 13 end
18 14 end
19 15  
20   - ###################################################
21   - # validations for creating a ChangePassword task
22   -
23   - validates_presence_of :login, :email, :environment_id, :on => :create, :message => _('must be filled in')
24   -
25   - validates_format_of :email, :on => :create, :with => Noosfero::Constants::EMAIL_FORMAT, :if => (lambda { |obj| !obj.email.blank? })
26   -
27   - validates_each :login, :on => :create do |data,attr,value|
28   - unless data.login.blank? || data.email.blank?
29   - user = User.find_by_login_and_environment_id(data.login, data.environment_id)
30   - if user.nil?
31   - data.errors.add(:login, _('is invalid or user does not exists.'))
32   - else
33   - if user.email != data.email
34   - data.errors.add(:email, _('does not match the username you filled in'))
35   - end
36   - end
37   - end
38   - end
39   -
40   - before_validation_on_create do |change_password|
41   - change_password.requestor = Person.find_by_identifier_and_environment_id(change_password.login, change_password.environment_id)
42   - end
  16 + validates_presence_of :requestor
43 17  
44 18 ###################################################
45 19 # validations for updating a ChangePassword task
... ... @@ -49,6 +23,10 @@ class ChangePassword &lt; Task
49 23 validates_presence_of :password_confirmation, :on => :update, :if => lambda { |change| change.status != Task::Status::CANCELLED }
50 24 validates_confirmation_of :password, :if => lambda { |change| change.status != Task::Status::CANCELLED }
51 25  
  26 + def environment
  27 + requestor.environment unless requestor.nil?
  28 + end
  29 +
52 30 def title
53 31 _("Change password")
54 32 end
... ... @@ -87,12 +65,8 @@ class ChangePassword &lt; Task
87 65 url = url_for(:host => hostname, :controller => 'account', :action => 'new_password', :code => code)
88 66  
89 67 lambda do
90   - _("In order to change your password, please visit the following address:\n\n%s") % url
  68 + _("In order to change your password, please visit the following address:\n\n%s\n\nIf you did not required any change to your password just desconsider this email.") % url
91 69 end
92 70 end
93 71  
94   - def environment
95   - self.requestor.environment
96   - end
97   -
98 72 end
... ...
app/models/environment.rb
... ... @@ -128,7 +128,8 @@ class Environment &lt; ActiveRecord::Base
128 128 'skip_new_user_email_confirmation' => _('Skip e-mail confirmation for new users'),
129 129 'send_welcome_email_to_new_users' => _('Send welcome e-mail to new users'),
130 130 'allow_change_of_redirection_after_login' => _('Allow users to set the page to redirect after login'),
131   - 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage')
  131 + 'display_my_communities_on_user_menu' => _('Display on menu the list of communities the user can manage'),
  132 + 'display_my_enterprises_on_user_menu' => _('Display on menu the list of enterprises the user can manage')
132 133 }
133 134 end
134 135  
... ...
app/models/event.rb
... ... @@ -30,7 +30,25 @@ class Event &lt; Article
30 30 end
31 31  
32 32 named_scope :by_day, lambda { |date|
33   - {:conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}]}
  33 + { :conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}],
  34 + :order => 'start_date ASC'
  35 + }
  36 + }
  37 +
  38 + named_scope :next_events_from_month, lambda { |date|
  39 + date_temp = date.strftime("%Y-%m-%d")
  40 + { :conditions => ["start_date >= ?","#{date_temp}"],
  41 + :limit => 10,
  42 + :order => 'start_date ASC'
  43 + }
  44 + }
  45 +
  46 + named_scope :by_month, lambda { |date|
  47 + date_temp = date.strftime("%Y-%m")
  48 + { :conditions => ["EXTRACT(YEAR FROM start_date) = ? AND EXTRACT(MONTH FROM start_date) = ?",date.year,date.month],
  49 + :limit => 10,
  50 + :order => 'start_date ASC'
  51 + }
34 52 }
35 53  
36 54 include WhiteListFilter
... ... @@ -105,7 +123,7 @@ class Event &lt; Article
105 123  
106 124 # TODO: some good soul, please clean this ugly hack:
107 125 if self.body
108   - html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description')
  126 + html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description')
109 127 end
110 128 }
111 129  
... ...
app/models/forum.rb
... ... @@ -3,6 +3,21 @@ class Forum &lt; Folder
3 3 acts_as_having_posts :order => 'updated_at DESC'
4 4 include PostsLimit
5 5  
  6 + settings_items :terms_of_use, :type => :string, :default => ""
  7 + settings_items :has_terms_of_use, :type => :boolean, :default => false
  8 + has_and_belongs_to_many :users_with_agreement, :class_name => 'Person', :join_table => 'terms_forum_people'
  9 +
  10 + before_save do |forum|
  11 + if forum.has_terms_of_use
  12 + last_editor = forum.profile.environment.people.find_by_id(forum.last_changed_by_id)
  13 + if last_editor && !forum.users_with_agreement.exists?(last_editor)
  14 + forum.users_with_agreement << last_editor
  15 + end
  16 + else
  17 + forum.users_with_agreement.clear
  18 + end
  19 + end
  20 +
6 21 def self.type_name
7 22 _('Forum')
8 23 end
... ... @@ -39,4 +54,16 @@ class Forum &lt; Folder
39 54 paragraphs = Hpricot(body).search('p')
40 55 paragraphs.empty? ? '' : paragraphs.first.to_html
41 56 end
  57 +
  58 + def add_agreed_user(user)
  59 + self.users_with_agreement << user
  60 + self.save
  61 + end
  62 +
  63 + def agrees_with_terms?(user)
  64 + return true unless self.has_terms_of_use
  65 + return false unless user
  66 + self.users_with_agreement.exists? user
  67 + end
  68 +
42 69 end
... ...
app/models/link_list_block.rb
... ... @@ -33,6 +33,12 @@ class LinkListBlock &lt; Block
33 33 ['chat', N_('Chat')]
34 34 ]
35 35  
  36 + TARGET_OPTIONS = [
  37 + [N_('Same page'), '_self'],
  38 + [N_('New tab'), '_blank'],
  39 + [N_('New window'), '_new'],
  40 + ]
  41 +
36 42 settings_items :links, Array, :default => []
37 43  
38 44 before_save do |block|
... ... @@ -57,7 +63,7 @@ class LinkListBlock &lt; Block
57 63 def link_html(link)
58 64 klass = 'icon-' + link[:icon] if link[:icon]
59 65 sanitize_link(
60   - link_to(link[:name], expand_address(link[:address]), :class => klass)
  66 + link_to(link[:name], expand_address(link[:address]), :target => link[:target], :class => klass)
61 67 )
62 68 end
63 69  
... ...
app/models/main_block.rb
... ... @@ -17,11 +17,15 @@ class MainBlock &lt; Block
17 17 end
18 18  
19 19 def editable?
20   - false
  20 + true
21 21 end
22 22  
23 23 def cacheable?
24   - false
  24 + false
  25 + end
  26 +
  27 + def display_options
  28 + ['always', 'except_home_page']
25 29 end
26 30  
27 31 end
... ...
app/models/members_block.rb
1 1 class MembersBlock < ProfileListBlock
  2 + settings_items :show_join_leave_button, :type => :boolean, :default => false
2 3  
3 4 def self.description
4 5 _('Members')
... ... @@ -14,8 +15,10 @@ class MembersBlock &lt; ProfileListBlock
14 15  
15 16 def footer
16 17 profile = self.owner
  18 + s = show_join_leave_button
  19 +
17 20 lambda do
18   - link_to _('View all'), :profile => profile.identifier, :controller => 'profile', :action => 'members'
  21 + render :file => 'blocks/members', :locals => { :profile => profile, :show_join_leave_button => s}
19 22 end
20 23 end
21 24  
... ... @@ -23,4 +26,14 @@ class MembersBlock &lt; ProfileListBlock
23 26 owner.members
24 27 end
25 28  
  29 + def extra_option
  30 + data = {
  31 + :human_name => _("Show join leave button"),
  32 + :name => 'block[show_join_leave_button]',
  33 + :value => true,
  34 + :checked => show_join_leave_button,
  35 + :options => {}
  36 + }
  37 + end
  38 +
26 39 end
... ...
app/models/person.rb
... ... @@ -46,6 +46,10 @@ class Person &lt; Profile
46 46 Profile.memberships_of(self)
47 47 end
48 48  
  49 + def memberships_by_role(role)
  50 + memberships.where('role_assignments.role_id = ?', role.id)
  51 + end
  52 +
49 53 has_many :friendships, :dependent => :destroy
50 54 has_many :friends, :class_name => 'Person', :through => :friendships
51 55  
... ... @@ -59,6 +63,9 @@ class Person &lt; Profile
59 63  
60 64 has_many :scraps_sent, :class_name => 'Scrap', :foreign_key => :sender_id, :dependent => :destroy
61 65  
  66 + has_and_belongs_to_many :acepted_forums, :class_name => 'Forum', :join_table => 'terms_forum_people'
  67 + has_and_belongs_to_many :articles_with_access, :class_name => 'Article', :join_table => 'article_privacy_exceptions'
  68 +
62 69 named_scope :more_popular,
63 70 :select => "#{Profile.qualified_column_names}, count(friend_id) as total",
64 71 :group => Profile.qualified_column_names,
... ... @@ -75,6 +82,10 @@ class Person &lt; Profile
75 82 named_scope :abusers, :joins => :abuse_complaints, :conditions => ['tasks.status = 3'], :select => 'DISTINCT profiles.*'
76 83 named_scope :non_abusers, :joins => "LEFT JOIN tasks ON profiles.id = tasks.requestor_id AND tasks.type='AbuseComplaint'", :conditions => ["tasks.status != 3 OR tasks.id is NULL"], :select => "DISTINCT profiles.*"
77 84  
  85 + named_scope :admins, :joins => [:role_assignments => :role], :conditions => ['roles.key = ?', 'environment_administrator' ]
  86 + named_scope :activated, :joins => :user, :conditions => ['users.activation_code IS NULL AND users.activated_at IS NOT NULL']
  87 + named_scope :deactivated, :joins => :user, :conditions => ['NOT (users.activation_code IS NULL AND users.activated_at IS NOT NULL)']
  88 +
78 89 after_destroy do |person|
79 90 Friendship.find(:all, :conditions => { :friend_id => person.id}).each { |friendship| friendship.destroy }
80 91 end
... ... @@ -468,7 +479,7 @@ class Person &lt; Profile
468 479 end
469 480  
470 481 def activities
471   - Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} and action_tracker.verb != 'leave_scrap_to_self' and action_tracker.verb != 'add_member_in_community' ORDER BY updated_at DESC")
  482 + Scrap.find_by_sql("SELECT id, updated_at, '#{Scrap.to_s}' AS klass FROM #{Scrap.table_name} WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} WHERE action_tracker.user_id = #{self.id} and action_tracker.verb != 'leave_scrap_to_self' and action_tracker.verb != 'add_member_in_community' and action_tracker.verb != 'reply_scrap_on_self' ORDER BY updated_at DESC")
472 483 end
473 484  
474 485 # by default, all fields are private
... ... @@ -476,6 +487,13 @@ class Person &lt; Profile
476 487 self.fields_privacy.nil? ? [] : self.fields_privacy.reject{ |k, v| v != 'public' }.keys.map(&:to_s)
477 488 end
478 489  
  490 + include Noosfero::Gravatar
  491 +
  492 + def profile_custom_icon(gravatar_default=nil)
  493 + (self.image.present? && self.image.public_filename(:icon)) ||
  494 + gravatar_profile_image_url(self.email, :size=>20, :d => gravatar_default)
  495 + end
  496 +
479 497 protected
480 498  
481 499 def followed_by?(profile)
... ...
app/models/profile.rb
... ... @@ -78,7 +78,8 @@ class Profile &lt; ActiveRecord::Base
78 78 #FIXME: these will work only if the subclass is already loaded
79 79 named_scope :enterprises, lambda { {:conditions => (Enterprise.send(:subclasses).map(&:name) << 'Enterprise').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
80 80 named_scope :communities, lambda { {:conditions => (Community.send(:subclasses).map(&:name) << 'Community').map { |klass| "profiles.type = '#{klass}'"}.join(" OR ")} }
81   - named_scope :templates, lambda { |environment| { :conditions => {:is_template => true, :environment_id => environment.id} } }
  81 + named_scope :templates, {:conditions => {:is_template => true}}
  82 + named_scope :no_templates, {:conditions => {:is_template => false}}
82 83  
83 84 def members
84 85 scopes = plugins.dispatch_scopes(:organization_members, self)
... ... @@ -98,7 +99,6 @@ class Profile &lt; ActiveRecord::Base
98 99 alias_method_chain :count, :distinct
99 100 end
100 101  
101   -
102 102 def members_by_role(role)
103 103 Person.members_of(self).all(:conditions => ['role_assignments.role_id = ?', role.id])
104 104 end
... ... @@ -112,6 +112,7 @@ class Profile &lt; ActiveRecord::Base
112 112 end
113 113  
114 114 named_scope :visible, :conditions => { :visible => true }
  115 + named_scope :public, :conditions => { :visible => true, :public_profile => true }
115 116 # Subclasses must override these methods
116 117 named_scope :more_popular
117 118 named_scope :more_active
... ... @@ -193,7 +194,7 @@ class Profile &lt; ActiveRecord::Base
193 194  
194 195 has_many :tasks, :dependent => :destroy, :as => 'target'
195 196  
196   - has_many :events, :source => 'articles', :class_name => 'Event', :order => 'name'
  197 + has_many :events, :source => 'articles', :class_name => 'Event', :order => 'start_date'
197 198  
198 199 def find_in_all_tasks(task_id)
199 200 begin
... ... @@ -760,8 +761,20 @@ private :generate_url, :url_options
760 761 !environment.enabled?('disable_contact_' + self.class.name.downcase)
761 762 end
762 763  
  764 + include Noosfero::Plugin::HotSpot
  765 +
  766 + def folder_types
  767 + types = Article.folder_types
  768 + plugins.dispatch(:content_types).each {|type|
  769 + if type < Folder
  770 + types << type.name
  771 + end
  772 + }
  773 + types
  774 + end
  775 +
763 776 def folders
764   - articles.folders
  777 + articles.folders(self)
765 778 end
766 779  
767 780 def image_galleries
... ... @@ -844,8 +857,10 @@ private :generate_url, :url_options
844 857 }[amount] || _("%s members") % amount
845 858 end
846 859  
847   - def profile_custom_icon
848   - self.image.public_filename(:icon) unless self.image.blank?
  860 + include Noosfero::Gravatar
  861 +
  862 + def profile_custom_icon(gravatar_default=nil)
  863 + image.public_filename(:icon) if image.present?
849 864 end
850 865  
851 866 def jid(options = {})
... ...
app/models/profile_list_block.rb
... ... @@ -62,4 +62,8 @@ class ProfileListBlock &lt; Block
62 62 title.gsub('{#}', profile_count.to_s)
63 63 end
64 64  
  65 + # override in subclasses! See MembersBlock for example
  66 + def extra_option
  67 + {}
  68 + end
65 69 end
... ...
app/models/recent_documents_block.rb
... ... @@ -30,4 +30,7 @@ class RecentDocumentsBlock &lt; Block
30 30 end
31 31 end
32 32  
  33 + def self.expire_on
  34 + { :profile => [:article], :environment => [:article] }
  35 + end
33 36 end
... ...
app/models/scrap.rb
... ... @@ -14,9 +14,11 @@ class Scrap &lt; ActiveRecord::Base
14 14  
15 15 named_scope :not_replies, :conditions => {:scrap_id => nil}
16 16  
17   - track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.receiver != s.sender}, :custom_target => :action_tracker_target
  17 + track_actions :leave_scrap, :after_create, :keep_params => ['sender.name', 'content', 'receiver.name', 'receiver.url'], :if => Proc.new{|s| s.sender != s.receiver && s.sender != s.top_root.receiver}, :custom_target => :action_tracker_target
18 18  
19   - track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.receiver == s.sender}
  19 + track_actions :leave_scrap_to_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender == s.receiver}
  20 +
  21 + track_actions :reply_scrap_on_self, :after_create, :keep_params => ['sender.name', 'content'], :if => Proc.new{|s| s.sender != s.receiver && s.sender == s.top_root.receiver}
20 22  
21 23 after_create do |scrap|
22 24 scrap.root.update_attribute('updated_at', DateTime.now) unless scrap.root.nil?
... ... @@ -25,6 +27,12 @@ class Scrap &lt; ActiveRecord::Base
25 27  
26 28 before_validation :strip_all_html_tags
27 29  
  30 + def top_root
  31 + scrap = self
  32 + scrap = Scrap.find(scrap.scrap_id) while scrap.scrap_id
  33 + scrap
  34 + end
  35 +
28 36 def strip_all_html_tags
29 37 sanitizer = HTML::WhiteListSanitizer.new
30 38 self.content = sanitizer.sanitize(self.content, :tags => [])
... ...
app/models/tags_block.rb
... ... @@ -59,4 +59,8 @@ class TagsBlock &lt; Block
59 59 15.minutes
60 60 end
61 61  
  62 + def self.expire_on
  63 + { :profile => [:article], :environment => [:article] }
  64 + end
  65 +
62 66 end
... ...
app/models/text_article.rb
... ... @@ -17,4 +17,7 @@ class TextArticle &lt; Article
17 17 end
18 18 end
19 19  
  20 + def can_display_versions?
  21 + true
  22 + end
20 23 end
... ...
app/models/uploaded_file.rb
... ... @@ -41,7 +41,25 @@ class UploadedFile &lt; Article
41 41 end
42 42  
43 43 def self.max_size
44   - UploadedFile.attachment_options[:max_size]
  44 + default = 5.megabytes
  45 +
  46 + multipliers = {
  47 + :KB => :kilobytes,
  48 + :MB => :megabytes,
  49 + :GB => :gigabytes,
  50 + :TB => :terabytes,
  51 + }
  52 + max_upload_size = NOOSFERO_CONF['max_upload_size']
  53 +
  54 + if max_upload_size =~ /^(\d+(\.\d+)?)\s*(KB|MB|GB|TB)?$/
  55 + number = $1.to_f
  56 + unit = $3 || :MB
  57 + multiplier = multipliers[unit.to_sym]
  58 +
  59 + number.send(multiplier).to_i
  60 + else
  61 + default
  62 + end
45 63 end
46 64  
47 65 # FIXME need to define min/max file size
... ... @@ -52,9 +70,9 @@ class UploadedFile &lt; Article
52 70 has_attachment :storage => :file_system,
53 71 :thumbnails => { :icon => [24,24], :thumb => '130x130>', :slideshow => '320x240>', :display => '640X480>' },
54 72 :thumbnail_class => Thumbnail,
55   - :max_size => 5.megabytes # remember to update validate message below
  73 + :max_size => self.max_size
56 74  
57   - validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n
  75 + validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n
58 76  
59 77 delay_attachment_fu_thumbnails
60 78  
... ...
app/models/user.rb
... ... @@ -143,6 +143,21 @@ class User &lt; ActiveRecord::Base
143 143 end
144 144 end
145 145  
  146 + # Deactivates the user in the database.
  147 + def deactivate
  148 + return false unless self.person
  149 + self.activated_at = nil
  150 + self.person.visible = false
  151 + begin
  152 + self.person.save! && self.save!
  153 + rescue Exception => exception
  154 + logger.error(exception.to_s)
  155 + false
  156 + else
  157 + true
  158 + end
  159 + end
  160 +
146 161 def activated?
147 162 self.activation_code.nil? && !self.activated_at.nil?
148 163 end
... ... @@ -275,19 +290,21 @@ class User &lt; ActiveRecord::Base
275 290 end
276 291 end
277 292  
278   - def data_hash
  293 + def data_hash(gravatar_default = nil)
279 294 friends_list = {}
280 295 enterprises = person.enterprises.map { |e| { 'name' => e.short_name, 'identifier' => e.identifier } }
281 296 self.person.friends.online.map do |person|
282 297 friends_list[person.identifier] = {
283   - 'avatar' => person.profile_custom_icon,
  298 + 'avatar' => person.profile_custom_icon(gravatar_default),
284 299 'name' => person.short_name,
285 300 'jid' => person.full_jid,
286 301 'status' => person.user.chat_status,
287 302 }
288 303 end
  304 +
289 305 {
290 306 'login' => self.login,
  307 + 'avatar' => self.person.profile_custom_icon(gravatar_default),
291 308 'is_admin' => self.person.is_admin?,
292 309 'since_month' => self.person.created_at.month,
293 310 'since_year' => self.person.created_at.year,
... ...
app/sweepers/article_sweeper.rb
... ... @@ -16,15 +16,15 @@ class ArticleSweeper &lt; ActiveRecord::Observer
16 16 end
17 17 end
18 18  
  19 +
19 20 protected
20 21  
21 22 def expire_caches(article)
  23 + expire_blocks_cache(article.profile, [:article])
  24 +
22 25 return if !article.environment
  26 +
23 27 article.hierarchy(true).each { |a| a.touch if a != article }
24   - blocks = article.profile.blocks
25   - blocks += article.profile.environment.blocks if article.profile.environment
26   - blocks = blocks.select{|b|[RecentDocumentsBlock, BlogArchivesBlock].any?{|c| b.kind_of?(c)}}
27   - BlockSweeper.expire_blocks(blocks)
28 28 env = article.profile.environment
29 29 if env && (env.portal_community == article.profile)
30 30 article.environment.locales.keys.each do |locale|
... ...
app/sweepers/category_sweeper.rb
... ... @@ -3,7 +3,13 @@ class CategorySweeper &lt; ActiveRecord::Observer
3 3 include SweeperHelper
4 4  
5 5 def after_save(category)
  6 + expire_blocks_cache(category.environment, [:category])
  7 +
  8 + # Needed for environments with application layout
6 9 expire_fragment(category.environment.id.to_s + "_categories_menu")
7 10 end
8 11  
  12 + def after_destroy(category)
  13 + expire_blocks_cache(category.environment, [:category])
  14 + end
9 15 end
... ...
app/views/account/_signup_form.rhtml
... ... @@ -101,7 +101,7 @@
101 101  
102 102 <%= @plugins.dispatch(:signup_extra_contents).collect { |content| instance_eval(&content) }.join("") %>
103 103  
104   - <%= template_options(Person, 'profile_data') %>
  104 + <%= template_options(:people, 'profile_data') %>
105 105  
106 106 <% unless @terms_of_use.blank? %>
107 107 <div id='terms-of-use-box' class='formfieldline'>
... ...
app/views/account/forgot_password.rhtml
... ... @@ -2,21 +2,13 @@
2 2  
3 3 <%= error_messages_for :change_password, :header_message => _('Instructions to password recovery could not be sent'), :message => nil %>
4 4  
5   -<% labelled_form_for :change_password, @change_password, :url => { :action => 'forgot_password' } do |f| %>
6   -
7   - <%= f.text_field :login,
8   - :onchange => 'this.value = convToValidUsername( this.value )' %>
9   -
10   - <%= f.text_field :email %>
11   -
12   - <%= f.hidden_field :environment_id, :value => environment.id %>
13   -
14   -<div>
15   - <% button_bar do %>
16   - <%= submit_button('send', _('Send instructions')) %>
17   - <% end %>
18   -</div>
19   -<%= content_tag(:small,_('After clicking the button above, you will receive an email with a link to a page where you will be able to create a new password.')) %>
20   -
  5 +<% form_tag do %>
  6 + <%= labelled_form_field fields_label, text_field_tag(:value) %>
  7 +
  8 + <div>
  9 + <% button_bar do %>
  10 + <%= submit_button('send', _('Send instructions')) %>
  11 + <% end %>
  12 + </div>
  13 + <%= content_tag(:small,_('After clicking the button above, you will receive an email with a link to a page where you will be able to create a new password.')) %>
21 14 <% end %>
22   -
... ...
app/views/blocks/members.rhtml 0 → 100644
... ... @@ -0,0 +1,5 @@
  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/profile_info_actions/_join_leave_community.rhtml 0 → 100644
... ... @@ -0,0 +1,29 @@
  1 +<div class='join-leave-button'>
  2 + <% if logged_in? %>
  3 + <% if profile.members.include?(user) %>
  4 + <%= button(:delete, content_tag('span', __('Leave community')), profile.leave_url,
  5 + :class => 'leave-community',
  6 + :title => _("Leave community"),
  7 + :style => 'position: relative;') %>
  8 + <%= button(:add, content_tag('span', __('Join')), profile.join_url,
  9 + :class => 'join-community',
  10 + :title => _("Join community"),
  11 + :style => 'position: relative; display: none;') %>
  12 + <% else %>
  13 + <% unless profile.already_request_membership?(user) %>
  14 + <%= button(:delete, content_tag('span', __('Leave community')), profile.leave_url,
  15 + :class => 'leave-community',
  16 + :title => _("Leave community"),
  17 + :style => 'position: relative; display: none;') %>
  18 + <%= button(:add, content_tag('span', __('Join')), profile.join_url,
  19 + :class => 'join-community',
  20 + :title => _("Join community"),
  21 + :style => 'position: relative;') %>
  22 + <% end %>
  23 + <% end %>
  24 + <% else %>
  25 + <%= link_to content_tag('span', _('Join')), profile.join_not_logged_url,
  26 + :class => 'button with-text icon-add',
  27 + :title => _('Join this community') %>
  28 + <% end %>
  29 +</div>
... ...
app/views/blocks/profile_info_actions/community.rhtml
1 1 <ul>
  2 + <li>
  3 + <%= render "blocks/profile_info_actions/join_leave_community" %>
  4 + </li>
2 5 <% if logged_in? %>
3   - <% if profile.members.include?(user) %>
4   - <li>
5   - <%= button(:delete, content_tag('span', __('Leave community')), profile.leave_url,
6   - :class => 'leave-community',
7   - :title => _("Leave community"),
8   - :style => 'position: relative;') %>
9   - <%= button(:add, content_tag('span', __('Join')), profile.join_url,
10   - :class => 'join-community',
11   - :title => _("Join community"),
12   - :style => 'position: relative; display: none;') %>
13   - </li>
14   - <% else %>
15   - <% unless profile.already_request_membership?(user) %>
16   - <li>
17   - <%= button(:delete, content_tag('span', __('Leave community')), profile.leave_url,
18   - :class => 'leave-community',
19   - :title => _("Leave community"),
20   - :style => 'position: relative; display: none;') %>
21   - <%= button(:add, content_tag('span', __('Join')), profile.join_url,
22   - :class => 'join-community',
23   - :title => _("Join community"),
24   - :style => 'position: relative;') %>
25   - </li>
26   - <% end %>
27   - <% end %>
28   -
29 6 <% if profile.enable_contact? %>
30 7 <li>
31 8 <%= link_to content_tag('span', _('Send an e-mail')),
... ... @@ -39,11 +16,5 @@
39 16 <li><%= report_abuse(profile, :button) %></li>
40 17  
41 18 <%= render_environment_features(:profile_actions) %>
42   - <% else %>
43   - <li>
44   - <%= link_to content_tag('span', _('Join')), profile.join_not_logged_url,
45   - :class => 'button with-text icon-add',
46   - :title => _('Join this community') %>
47   - </li>
48 19 <% end %>
49 20 -</ul>
  21 +</ul>
50 22 \ No newline at end of file
... ...
app/views/box_organizer/_article_block.rhtml
1 1 <div class="article-block-edition">
2   -<% if @block.box.owner.kind_of?(Environment) and @block.box.owner.portal_community.nil? %>
  2 +<% if @block.owner.kind_of?(Environment) and @block.owner.portal_community.nil? %>
3 3 <p id="no_portal_community">
4 4 <%= _("You don't have an community defined as the portal community. Define it before use this block properly.") %>
5 5 </p>
... ...
app/views/box_organizer/_link_list_block.rhtml
1 1 <strong><%= _('Links') %></strong>
2 2 <div id='edit-link-list-block' style='width:450px'>
3 3 <table id='links' class='noborder'>
4   - <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th></tr>
  4 + <tr><th><%= _('Icon') %></th><th><%= _('Name') %></th><th><%= _('Address') %></th><th><%= _('Target') %></th></tr>
5 5 <% for link in @block.links do %>
6 6 <tr>
7 7 <td>
... ... @@ -9,6 +9,9 @@
9 9 </td>
10 10 <td><%= text_field_tag 'block[links][][name]', link[:name], :class => 'link-name', :maxlength => 20 %></td>
11 11 <td class='cel-address'><%= text_field_tag 'block[links][][address]', link[:address], :class => 'link-address' %></td>
  12 + <td>
  13 + <%= select_tag('block[links][][target]', options_for_select(LinkListBlock::TARGET_OPTIONS, link[:target])) %>
  14 + </td>
12 15 </tr>
13 16 <% end %>
14 17 </table>
... ... @@ -18,7 +21,9 @@
18 21 page.insert_html :bottom, 'links', content_tag('tr',
19 22 content_tag('td', icon_selector('ok')) +
20 23 content_tag('td', text_field_tag('block[links][][name]', '', :maxlength => 20)) +
21   - content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'cel-address'))
  24 + content_tag('td', text_field_tag('block[links][][address]', nil, :class => 'link-address'), :class => 'cel-address') +
  25 + content_tag('td', select_tag('block[links][][target]',
  26 +options_for_select(LinkListBlock::TARGET_OPTIONS, '_self')))
22 27 ) +
23 28 javascript_tag("$('edit-link-list-block').scrollTop = $('edit-link-list-block').scrollHeight")
24 29 end %>
... ...
app/views/box_organizer/_profile_list_block.rhtml
... ... @@ -2,5 +2,8 @@
2 2 <%= labelled_form_field _('Limit of items'), text_field(:block, :limit, :size => 3) %>
3 3 <%= check_box(:block, :prioritize_profiles_with_image) %>
4 4 <label for="block_prioritize_profiles_with_image"><%= _('Prioritize profiles with image') %></label>
5   -</div>
6 5  
  6 + <div>
  7 + <%= extra_option_checkbox(@block.extra_option) %>
  8 + </div>
  9 +</div>
7 10 \ No newline at end of file
... ...
app/views/box_organizer/edit.rhtml
1 1 <div class="block-config-options <%= @block.class.name %>-options">
2   - <h2 class="title"><%= _('Editing block') %></h2>
  2 + <h2 class="title"><%= _(@block.class.description) %></h2>
3 3  
4 4 <% form_tag(:action => 'save', :id => @block.id) do %>
5 5  
... ... @@ -9,17 +9,11 @@
9 9  
10 10 <%= labelled_form_field _('Display this block:'), '' %>
11 11 <div style='margin-left: 10px'>
12   - <%= radio_button(:block, :display, 'always') %>
13   - <%= label_tag('block_display_always', _('In all pages')) %>
14   - <br/>
15   - <%= radio_button(:block, :display, 'home_page_only') %>
16   - <%= label_tag('block_display_home_page_only', _('Only in the homepage')) %>
17   - <br/>
18   - <%= radio_button(:block, :display, 'except_home_page') %>
19   - <%= label_tag('block_display_except_home_page', _('In all pages, except in the homepage')) %>
20   - <br/>
21   - <%= radio_button(:block, :display, 'never') %>
22   - <%= label_tag('block_display_never', _("Don't display")) %>
  12 + <% @block.display_options.each do |option| %>
  13 + <%= radio_button(:block, :display, option) %>
  14 + <%= label_tag("block_display_#{option}", _(@block.display_option_label(option))) %>
  15 + <br/>
  16 + <% end %>
23 17 </div>
24 18  
25 19 <%= labelled_form_field(_('Show for:'), select(:block, :language, [ [ _('all languages'), 'all']] + environment.locales.map {|key, value| [value, key]} )) %>
... ...
app/views/cms/_blog.rhtml
... ... @@ -54,6 +54,15 @@
54 54  
55 55 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 10)) %>
56 56  
  57 +<% f.fields_for :image_builder, @article.image do |i| %>
  58 + <%= file_field_or_thumbnail(_('Cover image:'), @article.image, i)%>
  59 + <%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %>
  60 +<% end %>
  61 +
  62 +<% unless @article.image.nil? %>
  63 + <%= labelled_check_box(_('Remove cover image'),'remove_image',true,false)%>
  64 +<% end %>
  65 +
57 66 <%= labelled_form_field(_('How to display posts:'), f.select(:visualization_format, [ [ _('Full post'), 'full'], [ _('First paragraph'), 'short'] ])) %>
58 67  
59 68 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Blog.posts_per_page_options)) %>
... ...
app/views/cms/_forum.rhtml
... ... @@ -11,3 +11,9 @@
11 11 <%= labelled_form_field(_('Description:'), text_area(:article, :body, :cols => 64, :rows => 10)) %>
12 12  
13 13 <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Forum.posts_per_page_options)) %>
  14 +
  15 +<%= labelled_form_field(_('Has terms of use:'), check_box(:article, :has_terms_of_use))%>
  16 +
  17 +<div id="text_area_terms_of_use">
  18 + <%= labelled_form_field(_('Terms of use:'), text_area(:article, :terms_of_use, :class => 'mceEditor',:cols => 64, :rows => 10)) %>
  19 +</div>
... ...
app/views/cms/edit.rhtml
1 1 <%= error_messages_for 'article' %>
  2 +<%= javascript_include_tag "article.js" %>
2 3  
3 4 <div class='<%= (environment.enabled?('media_panel') ? 'with_media_panel' : 'no_media_panel') %>'>
4 5 <% labelled_form_for 'article', @article, :html => { :multipart => true, :class => @type } do |f| %>
... ... @@ -9,6 +10,8 @@
9 10  
10 11 <%= hidden_field_tag('back_to', @back_to) %>
11 12  
  13 + <%= hidden_field_tag('success_back_to', @success_back_to) %>
  14 +
12 15 <%= render :partial => partial_for_class(@article.class), :locals => { :f => f } %>
13 16  
14 17 <% if environment.is_portal_community?(profile) %>
... ... @@ -33,7 +36,7 @@
33 36 <%= content_tag( 'small', _('Separate tags with commas') ) %>
34 37  
35 38 <div id='edit-article-options'>
36   - <%= options_for_article(@article) %>
  39 + <%= options_for_article(@article, @tokenized_children) %>
37 40 </div>
38 41  
39 42 <% button_bar do %>
... ...
app/views/cms/view.rhtml
... ... @@ -2,6 +2,18 @@
2 2 <%= _('Content management') %>
3 3 </h1>
4 4  
  5 +<% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %>
  6 + <div class="cms-homepage">
  7 + <%= _('Profile homepage:') %>
  8 + <% if profile.home_page %>
  9 + <%= link_to_article(profile.home_page) %>
  10 + <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %>
  11 + <% else %>
  12 + <span class="cms-homepage-default"><%= _('Profile Information') %></span>
  13 + <% end %>
  14 + </div>
  15 +<% end %>
  16 +
5 17 <% button_bar(:style => 'margin-bottom: 1em;') do %>
6 18 <% parent_id = ((@article && @article.allow_children?) ? @article : nil) %>
7 19  
... ... @@ -56,7 +68,11 @@
56 68 <%= button_without_text :eyes, _('Public view'), article.view_url %>
57 69 <%= display_spread_button(profile, article) unless article.folder? || remove_content_button(:spread)%>
58 70 <% if !environment.enabled?('cant_change_homepage') && !remove_content_button(:home) %>
59   - <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
  71 + <% if profile.home_page != article %>
  72 + <%= expirable_button article, :home, _('Use as homepage'), { :action => 'set_home_page', :id => article.id }, :method => :post %>
  73 + <% else %>
  74 + <%= button_without_text(:'home-not', _('Reset homepage'), { :action => 'set_home_page', :id => nil }, :method => :post) %>
  75 + <% end %>
60 76 <% end %>
61 77 <%= display_delete_button(article) if !remove_content_button(:delete) %>
62 78 </td>
... ...
app/views/comment/_comment.rhtml
... ... @@ -13,11 +13,11 @@
13 13 <% else %>
14 14 <% url_image, status_class = comment.author_id ?
15 15 [comment.removed_user_image, 'icon-user-removed'] :
16   - [str_gravatar_url_for( comment.email, :size => 50, :d=>404 ), 'icon-user-unknown'] %>
  16 + [gravatar_profile_image_url( comment.email, :size => 50, :d=>404 ), 'icon-user-unknown'] %>
17 17  
18 18 <%= link_to(
19 19 image_tag(url_image, :onerror=>'gravatarCommentFailback(this)',
20   - 'data-gravatar'=>str_gravatar_url_for(comment.email, :size=>50)) +
  20 + 'data-gravatar'=>gravatar_profile_image_url(comment.email, :size=>50)) +
21 21 content_tag('span', comment.author_name, :class => 'comment-info') +
22 22 content_tag('span', comment.message,
23 23 :class => 'comment-user-status ' + status_class),
... ...
app/views/content_viewer/_article_toolbar.rhtml
... ... @@ -48,10 +48,17 @@
48 48 <%= expirable_button @page, :suggest, content, url, options %>
49 49 <% end %>
50 50  
  51 + <% if @page.display_versions? %>
  52 + <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %>
  53 + <% end %>
  54 +
51 55 <%= report_abuse(profile, :link, @page) %>
52 56  
53 57 </div>
54 58 <div id="article-header">
  59 + <% if @page.blog? and !@page.image.nil? %>
  60 + <div class="blog-cover"><%= image_tag(@page.image.public_filename())%></div>
  61 + <% end %>
55 62 <%= link_to(image_tag('icons-mime/rss-feed.png'), @page.feed.url, :class => 'blog-feed-link') if @page.has_posts? && @page.feed %>
56 63 <%= article_title(@page, :no_link => true) %>
57 64 <%= article_translations(@page) %>
... ...
app/views/content_viewer/article_versions.rhtml 0 → 100644
... ... @@ -0,0 +1,21 @@
  1 +<%= article_title(@page, :no_link => true) %>
  2 +
  3 +<p><%= _('This is the list of all versions of this content. Select a version to see it and then revert to it.') %>.</p>
  4 +
  5 +<ul class='article-versions'>
  6 + <% @versions.each do |v| %>
  7 + <li>
  8 + <%= radio_button_tag :first, "#{v.version}" %>
  9 + <%= radio_button_tag :end, "#{v.version}" %>
  10 + <%= link_to(_("Version #{v.version}"), @page.url.merge(:version => v.version)) %>
  11 + <%= @page.version == v.version ? _('(current)') : '' %>
  12 + <span class='updated-by'><%= _('by %{author}') % {:author => link_to(@page.author_name(v.version), @page.author_url)} %></span>
  13 + <div class='updated-on'><%= show_time(v.updated_at) %></div>
  14 + </li>
  15 + <% end %>
  16 +</ul>
  17 +
  18 +<%= button_to "Show differences between selected versions", :id => "diff-versions",
  19 + :class => "diff-versions", :method => :get %>
  20 +
  21 +<%= pagination_links @versions, :param_name => 'npage' %>
... ...
app/views/content_viewer/forum_page.rhtml
1 1 <% add_rss_feed_to_head(@page.name, @page.feed.url) if @page.forum? && @page.feed %>
  2 +<% if @page.agrees_with_terms?(user) %>
2 3  
3   -<div>
4   - <div class='forum-description'>
5   - <%= @page.body %>
  4 + <div>
  5 + <div class='forum-description'>
  6 + <%= @page.body %>
  7 + </div>
6 8 </div>
7   -</div>
8   -<hr class="pre-posts"/>
9   -<div class="forum-posts">
10   - <%= (@posts.compact.empty? ? content_tag('em', _('(no posts)')) : list_forum_posts(@posts)) %>
11   -</div>
  9 + <hr class="pre-posts"/>
  10 + <div class="forum-posts">
  11 + <%= (@posts.compact.empty? ? content_tag('em', _('(no posts)')) : list_forum_posts(@posts)) %>
  12 + </div>
  13 +
  14 +<% else %>
  15 +
  16 + <p><%= @page.terms_of_use %></p>
  17 +
  18 + <% form_tag @page.url.merge(:terms_accepted => true) do %>
  19 + <% button_bar do %>
  20 + <% if user %>
  21 + <%= submit_button :save, _("Accept") %>
  22 + <% else %>
  23 + <%= button :save, _("Accept"), login_url %>
  24 + <% end %>
  25 + <%= button :cancel, _("Cancel"), profile.url %>
  26 + <% end %>
  27 + <% end %>
  28 +<% end %>
... ...
app/views/content_viewer/versioned_article.rhtml 0 → 100644
... ... @@ -0,0 +1,38 @@
  1 +<div id="article" class="<%= @page.css_class_name %>">
  2 +
  3 + <div id="article-actions">
  4 + <%= button(:clock, _('All versions'), {:controller => 'content_viewer', :profile => profile.identifier, :action => 'article_versions'}, :id => 'article-versions-link') %>
  5 +
  6 + <% if @page.allow_edit?(user) && !remove_content_button(:edit) %>
  7 + <% content = content_tag('span', _('Revert to this version')) %>
  8 + <% url = profile.admin_url.merge({ :controller => 'cms', :action => 'edit', :id => @page.id, :version => @version }) %>
  9 + <%= expirable_button @page, :edit, content, url, :id => 'article-revert-version-link' %>
  10 + <% end %>
  11 + </div>
  12 +
  13 + <div id="article-header">
  14 + <h1 class='title'><%= @versioned_article.name %></h1>
  15 + <%= _("Version %{version} - %{author} on %{date}") % {:version => @version, :author => @page.author_name(@version), :date => show_time(@versioned_article.updated_at) } %>
  16 + </div>
  17 +
  18 + <% if @page.version_license(@version).present? %>
  19 + <div id='article-sub-header'>
  20 + <% if @page.version_license(@version).present? %>
  21 + <div id="article-license">
  22 + <%= _('Licensed under %s') % (@page.version_license(@version).url.present? ? link_to(@page.version_license(@version).name, @page.version_license(@version).url, :target => '_blank') : @page.version_license(@version).name) %>
  23 + </div>
  24 + <% end %>
  25 + </div>
  26 + <% end %>
  27 +
  28 + <% cache(@page.cache_key(params, user, language)) do %>
  29 + <div class="<%="article-body article-body-" + @page.css_class_name %>">
  30 + <%= @versioned_article.body %>
  31 + <br style="clear:both" />
  32 + </div> <!-- end class="article-body" -->
  33 + <% end %>
  34 +
  35 + <%= display_source_info(@page) %>
  36 +
  37 +</div><!-- end id="article" -->
  38 +<%= add_zoom_to_article_images %>
... ...
app/views/content_viewer/view_page.rhtml
... ... @@ -14,6 +14,12 @@
14 14 window.NO_COMMENT_YET = "<%= _('No comments yet') %>";
15 15 </script>
16 16  
  17 +<% if @page.parent && !@page.parent.path.blank? %>
  18 +<div id="article-parent">
  19 + <%= button(:back, _('Go back to %s') % @page.parent.short_title, @page.parent.url) %>
  20 +</div>
  21 +<% end %>
  22 +
17 23 <div id="article-toolbar"></div>
18 24  
19 25 <script type="text/javascript">
... ... @@ -43,11 +49,6 @@
43 49 </div>
44 50 <% end %>
45 51  
46   -<% if @page.parent && !@page.parent.path.blank? %>
47   -<div id="article-parent">
48   - <%= button(:back, _('Go back to %s') % @page.parent.short_title, @page.parent.url) %>
49   -</div>
50   -<% end %>
51 52  
52 53 <%= render :partial => 'shared/disabled_enterprise' %>
53 54  
... ...
app/views/enterprise_registration/basic_information.rhtml
... ... @@ -34,7 +34,7 @@
34 34 <% end %>
35 35 <% end %>
36 36  
37   - <%= template_options(Enterprise, 'create_enterprise')%>
  37 + <%= template_options(:enterprises, 'create_enterprise')%>
38 38  
39 39 <% button_bar do %>
40 40 <%= submit_button('next', _('Next'), :cancel => {:profile => current_user.person.identifier, :action=>"enterprises", :controller=>"profile"}) %>
... ...
app/views/events/_agenda.rhtml
... ... @@ -3,22 +3,14 @@
3 3 <table class='noborder current-month'>
4 4 <caption>
5 5 <h2><%= show_month(params[:year], params[:month]) %></h2>
6   - <%= link_to_previous_month(params[:year], params[:month], '&laquo; %s' % _('previous')) %>
7   - <%= link_to_next_month(params[:year], params[:month], '%s &raquo;' % _('next')) %>
  6 + <%= link_to_previous_month(params[:year], params[:month], show_month(params[:year], params[:month], :previous => true, :only_month => true)) %>
  7 + <%= link_to_next_month(params[:year], params[:month], show_month(params[:year], params[:month], :next => true, :only_month => true)) %>
8 8 </caption>
9 9 <%= render :partial => 'events/month', :locals => {:calendar => @calendar, :abbreviated => true} %>
10 10 </table>
11   - <table class='noborder previous-month'>
12   - <caption><h3><%= link_to_previous_month(params[:year], params[:month], show_month(params[:year], params[:month], :previous => true)) %></h3></caption>
13   - <%= render :partial => 'events/month', :locals => {:calendar => @previous_calendar, :abbreviated => true} %>
14   - </table>
15   - <table class='noborder next-month'>
16   - <caption><h3><%= link_to_next_month(params[:year], params[:month], show_month(params[:year], params[:month], :next => true)) %></h3></caption>
17   - <%= render :partial => 'events/month', :locals => {:calendar => @next_calendar, :abbreviated => true} %>
18   - </table>
19 11 <br clear='both'/>
20 12 </div>
21 13 <div id='events-of-the-day'>
22   - <%= render :partial => 'events/events_by_day' %>
  14 + <%= render :partial => 'events/events' %>
23 15 </div>
24 16 </div>
... ...
app/views/events/_events.rhtml 0 → 100644
... ... @@ -0,0 +1 @@
  1 +<%= list_events(@date, @events) %>
0 2 \ No newline at end of file
... ...
app/views/events/_events_by_day.rhtml
... ... @@ -1 +0,0 @@
1   -<%= list_events(@selected_day, @events_of_the_day) %>
app/views/layouts/application-ng.rhtml
... ... @@ -22,7 +22,7 @@
22 22 DEFAULT_LOADING_MESSAGE = <%="'#{ _('loading...') }'" %>;
23 23 </script>
24 24 </head>
25   - <body class="<%= body_classes %>">
  25 + <body class="<%= h body_classes %>">
26 26 <a href="#content" id="link-go-content"><span><%= _("Go to the content") %></span></a>
27 27  
28 28 <%=
... ...
app/views/memberships/index.rhtml
... ... @@ -8,6 +8,19 @@
8 8 <%= button :back, _('Go back'), :controller => 'profile_editor' %>
9 9 <% end %>
10 10  
11   -<%= render :partial => 'shared/list_groups', :locals => {:groups => @memberships} %>
  11 +<% type_collection = [[nil, _('All')]] %>
  12 +<% type_collection += @roles.sort_by {|role| role.id}.map{|r| ["#{r.id}", r.name]} %>
  13 +
  14 +<p>
  15 + <%= labelled_select(_('Filter')+': ', :filter_type, :first, :last, @filter, type_collection, :onchange => 'document.location.href = "?filter_type="+this.value')%>
  16 +</p>
  17 +
  18 +<% if @memberships.empty? %>
  19 + <p>
  20 + <em><%= _('No groups to list') %></em>
  21 + </p>
  22 +<% else %>
  23 + <%= render :partial => 'shared/list_groups', :locals => {:groups => @memberships} %>
  24 +<% end %>
12 25  
13 26 </div>
... ...
app/views/memberships/new_community.rhtml
... ... @@ -44,11 +44,13 @@
44 44 </div>
45 45 </div>
46 46  
47   - <%= template_options(Community, 'community')%>
  47 + <%= template_options(:communities, 'community')%>
  48 +
  49 + <%= hidden_field_tag('back_to', @back_to) %>
48 50  
49 51 <% button_bar do %>
50 52 <%= submit_button(:save, _('Create')) %>
51   - <%= button(:cancel, _('Cancel'), :action => 'index') %>
  53 + <%= button(:cancel, _('Cancel'), @back_to ) %>
52 54 <% end %>
53 55  
54 56 <% end %>
... ...
app/views/profile/_comment.rhtml
... ... @@ -16,11 +16,11 @@
16 16 <% else %>
17 17 <% url_image, status_class = comment.author_id ?
18 18 [comment.removed_user_image, 'icon-user-removed'] :
19   - [str_gravatar_url_for( comment.email ), 'icon-user-unknown'] %>
  19 + [gravatar_profile_image_url( comment.email ), 'icon-user-unknown'] %>
20 20  
21 21 <%= link_to(
22 22 image_tag(url_image, :onerror=>'gravatarCommentFailback(this)',
23   - 'data-gravatar'=>str_gravatar_url_for(comment.email)) +
  23 + 'data-gravatar'=>gravatar_profile_image_url(comment.email)) +
24 24 content_tag('span', comment.author_name, :class => 'comment-info') +
25 25 content_tag('span', comment.message,
26 26 :class => 'comment-user-status comment-user-status-wall ' + status_class),
... ...
app/views/profile/_more_comments.rhtml 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +<div class='view-more-comments'>
  2 + <%= link_to(_('More'), :profile => @profile.identifier, :controller => 'profile', :action => 'more_comments', :activity => activity, :comment_page => (comment_page + 1)) %>
  3 +</div>
... ...