Commit cd4eff3c40cb9834e9a7673f3b4b2bc02f9d1036

Authored by Francisco Júnior
2 parents 15a4ca5f 3a392608

Merge branch 'staging' into security-search

Showing 1968 changed files with 192212 additions and 85052 deletions   Show diff stats

Too many changes.

To preserve performance only 100 of 1968 files displayed.

.gitlab-ci.yml 0 → 100644
... ... @@ -0,0 +1,26 @@
  1 +before_script:
  2 + - mkdir -p tmp/pids log
  3 + - bundle check || bundle install
  4 +# workaround for plugins with Gemfile
  5 + - perl -pi -e 's/--local //' script/noosfero-plugins
  6 + - script/noosfero-plugins disableall
  7 + - bundle exec rake makemo &>/dev/null
  8 +# database
  9 + - cp config/database.yml.gitlab-ci config/database.yml
  10 + - createdb gitlab_ci_test || true
  11 + - bundle exec rake db:schema:load &>/dev/null
  12 + - bundle exec rake db:migrate &>/dev/null
  13 +
  14 +units:
  15 + script: bundle exec rake test:units
  16 +functionals:
  17 + script: bundle exec rake test:functionals
  18 +integration:
  19 + script: bundle exec rake test:integration
  20 +cucumber:
  21 + script: bundle exec rake cucumber
  22 +selenium:
  23 + script: bundle exec rake selenium
  24 +plugins:
  25 + script: bundle exec rake test:noosfero_plugins
  26 +
... ...
.gitmodules 0 → 100644
... ... @@ -0,0 +1,39 @@
  1 +[submodule "plugins/pairwise"]
  2 + path = plugins/pairwise
  3 + url = https://gitlab.com/noosfero-plugins/pairwise.git
  4 +[submodule "plugins/proposals_discussion"]
  5 + path = plugins/proposals_discussion
  6 + url = https://gitlab.com/noosfero-plugins/proposals_discussion.git
  7 +[submodule "plugins/site_tour"]
  8 + path = plugins/site_tour
  9 + url = https://gitlab.com/noosfero-plugins/site_tour.git
  10 +[submodule "plugins/gamification"]
  11 + path = plugins/gamification
  12 + url = https://gitlab.com/noosfero-plugins/gamification.git
  13 +[submodule "plugins/comment_paragraph"]
  14 + path = plugins/comment_paragraph
  15 + url = https://gitlab.com/noosfero-plugins/comment-paragraph.git
  16 +[submodule "plugins/notification"]
  17 + path = plugins/notification
  18 + url = https://gitlab.com/noosfero-plugins/notification.git
  19 +[submodule "plugins/email_article"]
  20 + path = plugins/email_article
  21 + url = https://gitlab.com/noosfero-plugins/email_article.git
  22 +[submodule "public/proposal-app"]
  23 + path = public/proposal-app
  24 + url = https://gitlab.com/participa/proposal-app.git
  25 +[submodule "plugins/gravatar_provider"]
  26 + path = plugins/gravatar_provider
  27 + url = https://gitlab.com/noosfero-plugins/gravatar-provider.git
  28 +[submodule "plugins/juventude"]
  29 + path = plugins/juventude
  30 + url = https://gitlab.com/noosfero-plugins/juventude.git
  31 +[submodule "plugins/dialoga"]
  32 + path = plugins/dialoga
  33 + url = https://gitlab.com/participa/dialoga-plugin.git
  34 +[submodule "rest-clients/confjuvapp"]
  35 + path = rest-clients/confjuvapp
  36 + url = https://gitlab.com/participa/confjuvapp.git
  37 +[submodule "rest-clients/proposal-app"]
  38 + path = rest-clients/proposal-app
  39 + url = https://gitlab.com/participa/proposal-app.git
... ...
.travis.yml 0 → 100644
... ... @@ -0,0 +1,53 @@
  1 +language: ruby
  2 +rvm:
  3 +# for 2.2 support we need to upgrade the pg gem
  4 + - 2.1.6
  5 +
  6 +sudo: false
  7 +addons:
  8 + apt:
  9 + packages:
  10 + - po4a
  11 + - iso-codes
  12 + - tango-icon-theme
  13 + - pidgin-data
  14 + # for gem extensions
  15 + - libmagickwand-dev
  16 + - libpq-dev
  17 + - libreadline-dev
  18 + - libsqlite3-dev
  19 + - libxslt1-dev
  20 +
  21 +before_install:
  22 + - gem env
  23 +
  24 +# workaround for https://github.com/travis-ci/travis-ci/issues/4536
  25 +before_install:
  26 + - export GEM_HOME=$PWD/vendor/bundle/ruby/2.1.0
  27 + - gem install bundler
  28 +cache: bundler
  29 +
  30 +before_script:
  31 + - mkdir -p tmp/pids log
  32 +# workaround for plugins with Gemfile
  33 + - perl -pi -e 's/cat .+ > \$gemfile/echo "source \\"https:\/\/rubygems.org\\"" > \$gemfile && cat \$source\/Gemfile >> \$gemfile/' script/noosfero-plugins
  34 + - perl -pi -e 's/--local --quiet/install --jobs=3 --retry=3/' script/noosfero-plugins
  35 + - script/noosfero-plugins disableall
  36 + - bundle exec rake makemo &>/dev/null
  37 +# database
  38 + - cp config/database.yml.travis config/database.yml
  39 + - psql -c 'create database myapp_test;' -U postgres
  40 + - bundle exec rake db:schema:load &>/dev/null
  41 + - bundle exec rake db:migrate &>/dev/null
  42 +
  43 +env:
  44 + - TASK=test:units
  45 + - TASK=test:functionals
  46 + - TASK=test:integration
  47 + - TASK=cucumber
  48 + - TASK=selenium
  49 + - TASK=test:noosfero_plugins
  50 +
  51 +script:
  52 + - bundle exec rake $TASK
  53 +
... ...
AUTHORS.md
  1 +This list is automatically generated at release time. Please do not change it.
  2 +
1 3 If you are not listed here, but should be, please write to the noosfero mailing
2 4 list: http://listas.softwarelivre.org/cgi-bin/mailman/listinfo/noosfero-dev
3 5 (this list requires subscription to post, but since you are an author of
... ... @@ -8,256 +10,120 @@ Developers
8 10  
9 11 Ábner Silva de Oliveira <abner.oliveira@serpro.gov.br>
10 12 Alan Freihof Tygel <alantygel@gmail.com>
11   -alcampelo <alcampelo@alcampelo.(none)>
12 13 Alessandro Palmeira <alessandro.palmeira@gmail.com>
13   -Alessandro Palmeira + Caio C. Salgado <alessandro.palmeira@gmail.com>
14   -Alessandro Palmeira + Caio Salgado <alessandro.palmeira@gmail.com>
15   -Alessandro Palmeira + Caio Salgado <caio.csalgado@gmail.com>
16   -Alessandro Palmeira + Caio Salgado + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
17   -Alessandro Palmeira + Carlos Morais <alessandro.palmeira@gmail.com>
18   -Alessandro Palmeira + Daniel Alves <alessandro.palmeira@gmail.com>
19   -Alessandro Palmeira + Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
20   -Alessandro Palmeira + Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
21   -Alessandro Palmeira + Diego Araujo <alessandro.palmeira@gmail.com>
22   -Alessandro Palmeira + Diego Araújo <alessandro.palmeira@gmail.com>
23   -Alessandro Palmeira + Diego Araujo + Daniela Feitosa <alessandro.palmeira@gmail.com>
24   -Alessandro Palmeira + Diego Araujo <diegoamc90@gmail.com>
25   -Alessandro Palmeira + Diego Araújo <diegoamc90@gmail.com>
26   -Alessandro Palmeira + Diego Araujo + Eduardo Morais <alessandro.palmeira@gmail.com>
27   -Alessandro Palmeira + Diego Araújo + João M. M. da Silva <alessandro.palmeira@gmail.com>
28   -Alessandro Palmeira + Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
29   -Alessandro Palmeira + Diego Araujo + João M. M. da Silva + Paulo Meirelles <alessandro.palmeira@gmail.com>
30   -Alessandro Palmeira + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
31   -Alessandro Palmeira + Diego Araújo + Pedro Leal + João M. M. da Silva <diegoamc90@gmail.com>
32   -Alessandro Palmeira + Diego Araujo + Rafael Manzo <alessandro.palmeira@gmail.com>
33   -Alessandro Palmeira + Eduardo Morais <alessandro.palmeira@gmail.com>
34   -Alessandro Palmeira + Guilherme Rojas <alessandro.palmeira@gmail.com>
35   -Alessandro Palmeira + Jefferson Fernandes <alessandro.palmeira@gmail.com>
36   -Alessandro Palmeira + João M. M. da Silva <alessandro.palmeira@gmail.com>
37   -Alessandro Palmeira + Joao M. M. da Silva + Diego Araujo <alessandro.palmeira@gmail.com>
38   -Alessandro Palmeira + João M. M. da Silva + Renan Teruo <alessandro.palmeira@gmail.com>
39   -Alessandro Palmeira + João M. M. Silva <alessandro.palmeira@gmail.com>
40   -Alessandro Palmeira + Paulo Meirelles <alessandro.palmeira@gmail.com>
41   -Alessandro Palmeira + Paulo Meirelles + João M. M. da Silva <alessandro.palmeira@gmail.com>
42   -Alessandro Palmeira + Rafael Manzo <alessandro.palmeira@gmail.com>
43   -analosnak <analosnak@gmail.com>
  14 +Alex Campelo <campelo.al1@gmail.com>
  15 +Álvaro Fernando <alvarofernandoms@gmail.com>
44 16 Ana Losnak <analosnak@gmail.com>
45   -Andre Bernardes <andrebsguedes@gmail.com>
46   -Antonio Terceiro + Carlos Morais <terceiro@colivre.coop.br>
47   -Antonio Terceiro + Paulo Meirelles <terceiro@colivre.coop.br>
  17 +Ana Paula Vargas <anapaulavnoronha@gmail.com>
  18 +Andre Bedran <bedran.fleck@gmail.com>
  19 +André Guedes <andrebsguedes@gmail.com>
  20 +Andrey Aleksanyants <aaleksanyants@yahoo.com>
48 21 Antonio Terceiro <terceiro@colivre.coop.br>
49 22 Arthur Del Esposte <arthurmde@gmail.com>
50   -Arthur Del Esposte <arthurmde@yahoo.com.br>
  23 +Athos Ribeiro <athoscribeiro@gmail.com>
51 24 Aurelio A. Heckert <aurelio@colivre.coop.br>
52   -Braulio Bhavamitra <brauliobo@gmail.com>
53   -Bráulio Bhavamitra <brauliobo@gmail.com>
54 25 Braulio Bhavamitra <braulio@eita.org.br>
55   -Caio <caio.csalgado@gmail.com>
56   -Caio + Diego + Pedro + João <caio.csalgado@gmail.com>
  26 +Brenddon Gontijo <brenddongontijo@msn.com>
57 27 Caio Formiga <caio.formiga@gmail.com>
58   -Caio, Pedro <caio.csalgado@gmail.com>
59   -Caio Salgado + Alessandro Palmeira <caio.csalgado@gmail.com>
60 28 Caio Salgado <caio.csalgado@gmail.com>
61   -Caio Salgado + Carlos Morais + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
62   -Caio Salgado + Diego Araujo <caio.csalgado@gmail.com>
63   -Caio Salgado + Diego Araújo <caio.csalgado@gmail.com>
64   -Caio Salgado + Diego Araújo <diegoamc90@gmail.com>
65   -Caio Salgado + Diego Araújo + Jefferson Fernandes <caio.csalgado@gmail.com>
66   -Caio Salgado + Diego Araújo + João M. M. da Silva <caio.csalgado@gmail.com>
67   -Caio Salgado + Diego Araújo + Pedro Leal <caio.csalgado@gmail.com>
68   -Caio Salgado + Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
69   -Caio Salgado + Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
70   -Caio Salgado + Jefferson Fernandes <caio.csalgado@gmail.com>
71   -Caio Salgado + Jefferson Fernandes <jeffs.fernandes@gmail.com>
72   -Caio Salgado + Rafael Manzo <caio.csalgado@gmail.com>
73   -Caio Salgado + Renan Teruo <caio.csalgado@gmail.com>
74   -Caio Salgado + Renan Teruo <caio.salgado@gmail.com>
75   -Caio Salgado + Renan Teruo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
76   -Caio Salgado + Renan Teruo <renanteruoc@gmail.com>
77 29 Caio SBA <caio@colivre.coop.br>
78 30 Caio Tiago Oliveira <caiotiago@colivre.coop.br>
79 31 Carlos Andre de Souza <carlos.andre.souza@msn.com>
80 32 Carlos Morais <carlos88morais@gmail.com>
81   -Carlos Morais + Diego Araújo <diegoamc90@gmail.com>
82   -Carlos Morais + Eduardo Morais <carlos88morais@gmail.com>
83   -Carlos Morais + Paulo Meirelles <carlos88morais@gmail.com>
84   -Carlos Morais + Pedro Leal <carlos88morais@gmail.com>
85   -Daniel Alves + Diego Araújo <danpaulalves@gmail.com>
86   -Daniel Alves + Diego Araújo <diegoamc90@gmail.com>
87   -Daniel Alves + Diego Araújo + Guilherme Rojas <danpaulalves@gmail.com>
88   -Daniel Alves + Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
89   -Daniel Alves + Diego Araújo + Guilherme Rojas <guilhermehrojas@gmail.com>
90   -Daniel Alves + Guilherme Rojas <danpaulalves@gmail.com>
91   -Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
  33 +Christophe DANIEL <papaeng@gmail.com>
  34 +Daniela Feitosa <alessandro.palmeira@gmail.com>
  35 +Daniel Alves <danpaulalves@gmail.com>
92 36 Daniela Soares Feitosa <danielafeitosa@colivre.coop.br>
93 37 Daniel Bucher <daniel.bucher88@gmail.com>
94 38 Daniel Cunha <daniel@colivre.coop.br>
  39 +Daniel Tygel <dtygel@eita.org.br>
95 40 David Carlos <ddavidcarlos1392@gmail.com>
96   -diegoamc <diegoamc90@gmail.com>
97   -Diego Araújo + Alessandro Palmeira <diegoamc90@gmail.com>
98   -Diego Araújo + Alessandro Palmeira + João M. M. da Silva <diegoamc90@gmail.com>
99   -Diego Araújo + Alessandro Palmeira + Rafael Manzo <rr.manzo@gmail.com>
100   -Diego Araujo + Caio Salgado <diegoamc90@gmail.com>
101   -Diego Araújo + Daniel Alves + Rafael Manzo <rr.manzo@gmail.com>
102   -Diego Araújo <diegoamc90@gmail.com>
103   -Diego Araújo + Eduardo Morais + Paulo Meirelles <diegoamc90@gmail.com>
104   -Diego Araújo + Guilherme Rojas <diegoamc90@gmail.com>
105   -Diego Araújo + Jefferson Fernandes <diegoamc90@gmail.com>
106   -Diego Araujo + Jefferson Fernandes <jeffs.fernandes@gmail.com>
107   -Diego Araújo + João Machini <diegoamc90@gmail.com>
108   -Diego Araújo + João Machini <digoamc90@gmail.com>
109   -Diego Araújo + João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
110   -Diego Araújo + João M. M. da Silva <diegoamc90@gmail.com>
111   -Diego Araújo + João M. M. da Silva + João Machini <diegoamc90@gmail.com>
112   -Diego Araújo + João M. M. da Silva + Pedro Leal <diegoamc90@gmail.com>
113   -Diego Araújo + Paulo Meirelles <diegoamc90@gmail.com>
114   -Diego Araújo + Pedro Leal <diegoamc90@gmail.com>
115   -Diego Araujo + Rafael Manzo <diegoamc90@gmail.com>
116   -Diego Araújo + Rafael Manzo <diegoamc90@gmail.com>
117   -Diego Araújo + Renan Teruo + Alessandro Palmeira <diegoamc90@gmail.com>
118   -Diego Araújo + Renan Teruo <diegoamc90@gmail.com>
119   -Diego Araujo + Rodrigo Souto + Rafael Manzo <rr.manzo@gmail.com>
120   -Diego + Jefferson <diegoamc90@gmail.com>
121   -Diego Martinez <diegoamc90@gmail.com>
122   -Diego + Renan <renanteruoc@gmail.com>
123   -DylanGuedes <djmgguedes@gmail.com>
124   -Eduardo Passos <eduardo@risa.localdomain.localhost>
  41 +Diego Araujo <diegoamc90@gmail.com>
  42 +Dylan Guedes <djmgguedes@gmail.com>
  43 +Eduardo Morais
125 44 Eduardo Passos <eduardosteps@gmail.com>
126 45 Eduardo Tourinho Edington <eduardo.edington@serpro.gov.br>
127   -Evandro Jr <evandrojr@gmail.com>
128   -Evandro Junior <evandrojr@gmail.com>
  46 +Eduardo Vital <vitaldu@gmail.com>
  47 +Evandro Magalhaes Leite Junior <evandro.leite@serpro.gov.br>
129 48 Fabio Teixeira <fabio1079@gmail.com>
130 49 FAMMA TV NOTICIAS MEDIOS DE CO <revistafammatvmusic.oficial@gmail.com>
131 50 Fernanda Lopes <nanda.listas+psl@gmail.com>
132   -Francisco Marcelo A. Lima Júnior <francisco.lima-junior@serpro.gov.br>
133   -Francisco Marcelo de Araujo Lima Junior <79350259591@serpro-1457614.(none)>
  51 +Filipe Ribeiro <firibeiro77@live.com>
134 52 Francisco Marcelo de Araújo Lima Júnior <francisco.lima-junior@serpro.gov.br>
135   -Francisco Marcelo de Araújo Lima Júnior <maljunior@gmail.com>
136 53 Gabriela Navarro <navarro1703@gmail.com>
137 54 Gonzalo Exequiel Pedone <hipersayan.x@gmail.com>
138 55 Grazieno Pellegrino <grazieno@gmail.com>
139   -Gust <darksshades@hotmail.com>
  56 +Guilherme C. Muniz <guilherme.cmuniz@gmail.com>
  57 +Guilherme Rojas <guilhermehrojas@gmail.com>
  58 +Gustavo Jaruga <darksshades@gmail.com>
140 59 Hebert Douglas <hebertdougl@gmail.com>
141 60 Hugo Melo <hugo@riseup.net>
  61 +Iolane Andrade <andrade.icaa@gmail.com>
142 62 Isaac Canan <isaac@intelletto.com.br>
143 63 Italo Valcy <italo@dcc.ufba.br>
144   -Jefferson Fernandes + Diego Araujo + Rafael Manzo <jeffs.fernandes@gmail.com>
145   -Jefferson Fernandes + Joao M. M. da Silva <jeffs.fernandes@gmail.com>
146   -Jefferson Fernandes + Joao M. M. Silva <jeffs.fernandes@gmail.com>
147   -João da Silva + Eduardo Morais + Rafael Manzo <rr.manzo@gmail.com>
148   -João da Silva <jaodsilv@linux.ime.usp.br>
149   -João Marco Maciel da Silva + Rafael Manzo + Renan Teruo <jaodsilv@linux.ime.usp.br>
150   -João M. M. da Silva + Alessandro Palmeira + Diego Araújo + Caio Salgado <jaodsilv@linux.ime.usp.br>
151   -João M. M. da Silva + Alessandro Palmeira + Diego Araújo <jaodsilv@linux.ime.usp.br>
152   -Joao M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
153   -João M. M. da Silva + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
154   -João M. M. da Silva + Alessandro Palmeira + João Machini <jaodsilv@linux.ime.usp.br>
155   -João M. M. da Silva + Caio Salgado + Alessandro Palmeira <jaodsilv@linux.ime.usp.br>
156   -João M. M. da Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>
157   -João M. M. da Silva + Carlos Morais <jaodsilv@linux.ime.usp.br>
158   -João M. M. da Silva + Diego Araújo <diegoamc90@gmail.com>
159   -João M. M. da Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>
160   -João M. M. da Silva + Diego Araújo + Pedro Leal <jaodsilv@linux.ime.usp.br>
  64 +Jefferson Fernandes <jeffs.fernandes@gmail.com>
  65 +Jérôme Jutteau <j.jutteau@gmail.com>
  66 +João Machini
161 67 João M. M. da Silva <jaodsilv@linux.ime.usp.br>
162   -Joao M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
163   -João M. M. da Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
164   -João M. M. da Silva + João M. Miranda <jaodsilv@linux.ime.usp.br>
165   -João M. M. da Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>
166   -João M. M. da Silva + Pedro Leal <jaodsilv@linux.ime.usp.br>
167   -João M. M. da Silva + Rafael Manzo + Diego Araújo <jaodsilv@linux.ime.usp.br>
168   -João M. M. da Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>
169   -João M. M. da Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
170   -João M. M. Silva + Caio Salgado <jaodsilv@linux.ime.usp.br>
171   -João M. M. Silva + Diego Araújo <jaodsilv@linux.ime.usp.br>
172   -Joao M. M. Silva + Jefferson Fernandes <jaodsilv@linux.ime.usp.br>
173   -João M. M. Silva + Paulo Meirelles <jaodsilv@linux.ime.usp.br>
174   -João M. M. Silva + Rafael Manzo <jaodsilv@linux.ime.usp.br>
175   -João M. M. Silva + Renan Teruo <jaodsilv@linux.ime.usp.br>
176 68 Joenio Costa <joenio@colivre.coop.br>
177 69 Josef Spillner <josef.spillner@tu-dresden.de>
178 70 Jose Pedro <1jpsneto@gmail.com>
179   -Junior Silva <junior@bajor.localhost.localdomain>
180   -Junior Silva <junior@sedeantigo.colivre.coop.br>
181 71 Junior Silva <juniorsilva1001@gmail.com>
182   -Junior Silva <juniorsilva7@juniorsilva-Aspire-5750Z.(none)>
183   -Junior Silva <juniorsilva@colivre.coop.br>
184   -juniorsilva <juniorsilva@QonoS.localhost.localdomain>
185 72 Keilla Menezes <keilla@colivre.coop.br>
186 73 Larissa Reis <larissa@colivre.coop.br>
187   -Larissa Reis <reiss.larissa@gmail.com>
188 74 Leandro Alves <leandrosustenido@gmail.com>
189   -Leandro Nunes dos Santos <81665687568@serpro-1541727.Home>
190   -Leandro Nunes dos Santos <81665687568@serpro-1541727.(none)>
191   -Leandro Nunes dos Santos <leandronunes@gmail.com>
192 75 Leandro Nunes dos Santos <leandro.santos@serpro.gov.br>
  76 +Leandro Veloso <leandrovelosorodrigues@gmail.com>
193 77 LinguÁgil 2010 <linguagil.bahia@gmail.com>
  78 +Lucas Couto <loc.unb@gmail.com>
194 79 Lucas Kanashiro <kanashiro.duarte@gmail.com>
195   -Lucas Melo <lucas@colivre.coop.br>
196 80 Lucas Melo <lucaspradomelo@gmail.com>
197   -Luciano <lucianopcbr@gmail.com>
198 81 Luciano Prestes Cavalcanti <lucianopcbr@gmail.com>
199 82 Luis David Aguilar Carlos <ludwig9003@gmail.com>
200 83 Luiz Fernando de Freitas Matos <luiz@luizff.matos@gmail.com>
201   -Marcos <marcos.rpj2@gmail.com>
  84 +Luiz Matos <luizff.matos@gmail.com>
202 85 Marcos Ramos <ms.ramos@outlook.com>
  86 +Marcos Ronaldo <marcos.rpj2@gmail.com>
  87 +Mariel Zasso <noosfero-br@listas.softwarelivre.org>
203 88 Martín Olivera <molivera@solar.org.ar>
  89 +Matheus Faria <matheus.sousa.faria@gmail.com>
204 90 Maurilio Atila <cabelotaina@gmail.com>
205 91 M for Momo <mo@rtnp.org>
206 92 Michal Čihař <michal@cihar.com>
  93 +Michel Felipe <mfelipeof@gmail.com>
207 94 Moises Machado <moises@colivre.coop.br>
208 95 Naíla Alves <naila@colivre.coop.br>
209 96 Nanda Lopes <nanda.listas+psl@gmail.com>
210 97 Niemand Jedermann <predatorix@web.de>
211 98 Parley Martins <parleypachecomartins@gmail.com>
212   -Paulo Meirelles + Alessandro Palmeira + João M. M. da Silva <paulo@softwarelivre.org>
213   -Paulo Meirelles + Alessandro Palmeira <paulo@softwarelivre.org>
214   -Paulo Meirelles + Carlos Morais <paulo@softwarelivre.org>
215   -Paulo Meirelles + Diego Araújo <paulo@softwarelivre.org>
216   -Paulo Meirelles + João M. M. da Silva <paulo@softwarelivre.org>
217 99 Paulo Meirelles <paulo@softwarelivre.org>
218   -Paulo Meirelles + Rafael Manzo <paulo@softwarelivre.org>
  100 +Pedro de Lyra <pedrodelyra@gmail.com>
  101 +Pedro Leal
  102 +Rafael de Souza Queiroz <querafael@live.com>
219 103 Rafael Gomes <rafaelgomes@techfree.com.br>
220   -Rafael Manzo + Alessandro Palmeira <rr.manzo@gmail.com>
221   -Rafael Manzo + Daniel Alves <danpaulalves@gmail.com>
222   -Rafael Manzo + Diego Araújo <rr.manzo@gmail.com>
223   -Rafael Manzo + João M. M. Silva <rr.manzo@gmail.com>
224   -Rafael Manzo + Paulo Meirelles <rr.manzo@gmail.com>
225 104 Rafael Martins <rmmartins@gmail.com>
226   -Rafael Reggiani Manzo + Caio Salgado + Jefferson Fernandes <rr.manzo@gmail.com>
227   -Rafael Reggiani Manzo + Diego Araujo <diegoamc90@gmail.com>
228   -Rafael Reggiani Manzo + Diego Araujo <rr.manzo@gmail.com>
229   -Rafael Reggiani Manzo + Diego Araújo <rr.manzo@gmail.com>
230   -Rafael Reggiani Manzo + João M. M. da Silva <rr.manzo@gmail.com>
231 105 Rafael Reggiani Manzo <rr.manzo@gmail.com>
232 106 Raphaël Rousseau <raph@r4f.org>
233 107 Raquel Lira <raquel.lira@gmail.com>
234 108 Raquel <rcordioli@gmail.com>
235   -Renan Teruo + Caio Salgado <renanteruoc@gmail.com>
236   -Renan Teruoc + Diego Araujo <renanteruoc@gmail.com>
237   -Renan Teruo + Diego Araujo <renanteruoc@gmail.com>
238   -Renan Teruo + Diego Araújo <renanteruoc@gmail.com>
239   -Renan Teruo + Paulo Meirelles <renanteruoc@gmail.com>
240   -Renan Teruo + Rafael Manzo <renanteruoc@gmail.com>
241   -Rodrigo Souto + Ana Losnak + Daniel Bucher + Caio Almeida + Leandro Nunes + Daniela Feitosa + Mariel Zasso <noosfero-br@listas.softwarelivre.org>
  109 +Renan Costa <renan2727@hotmail.com>
  110 +Renan Teruo <renanteruoc@gmail.com>
  111 +Rodrigo Medeiros <rodrigo.mss01@gmail.com>
242 112 Rodrigo Souto <rodrigo@colivre.coop.br>
243 113 Ronny Kursawe <kursawe.ronny@googlemail.com>
244   -root <root@debian.sdr.serpro>
245 114 Samuel R. C. Vale <srcvale@holoscopio.com>
246   -Tallys Martins <tallysmartins@gmail.com>
247 115 Tallys Martins <tallysmartins@yahoo.com.br>
248   -tallys <tallys@tallys>
249   -tallys <tallys@tallys.(none)>
  116 +Thiago Casotti <thiago.casotti@uol.com.br>
  117 +Thiago Kairala <thiagor.kairala@gmail.com>
  118 +Thiago Ribeiro <thiagitosouza@hotmail.com>
250 119 Thiago Zoroastro <thiago.zoroastro@bol.com.br>
251 120 Tuux <tuxa@galaxie.eu.org>
  121 +TWS <tablettws@gmail.com>
252 122 Valessio Brito <contato@valessiobrito.com.br>
253   -Valessio Brito <contato@valessiobrito.info>
254   -Valessio Brito <valessio@gmail.com>
255   -vfcosta <vfcosta@gmail.com>
256   -Victor Carvalho <victorhugodf.ac@gmail.com>
257 123 Victor Costa <vfcosta@gmail.com>
258 124 Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com>
259 125 Vinicius Cubas Brand <viniciuscb@gmail.com>
260   -Visita <visita@debian.(none)>
  126 +Wilton Rodrigues <braynwilton@gmail.com>
261 127 Yann Lugrin <yann.lugrin@liquid-concept.ch>
262 128  
263 129 Ideas, specifications and incentive
... ...
Gemfile
1 1 source "https://rubygems.org"
2   -gem 'rails', '~> 3.2.21'
  2 +gem 'rails', '~> 3.2.22'
3 3 gem 'minitest', '~> 3.2.0'
4 4 gem 'fast_gettext', '~> 0.6.8'
5 5 gem 'acts-as-taggable-on', '~> 3.4.2'
... ... @@ -11,27 +11,46 @@ gem &#39;will_paginate&#39;, &#39;~&gt; 3.0.3&#39;
11 11 gem 'ruby-feedparser', '~> 0.7'
12 12 gem 'daemons', '~> 1.1.5'
13 13 gem 'thin', '~> 1.3.1'
14   -gem 'nokogiri', '~> 1.5.5'
  14 +gem 'nokogiri', '~> 1.6.0'
15 15 gem 'rake', :require => false
16 16 gem 'rest-client', '~> 1.6.7'
17 17 gem 'exception_notification', '~> 4.0.1'
18 18 gem 'gettext', '~> 2.2.1', :require => false
19 19 gem 'locale', '~> 2.0.5'
20 20 gem 'whenever', :require => false
21   -gem 'eita-jrails', '>= 0.9.5', :require => 'jrails'
  21 +gem 'eita-jrails', '~> 0.9.5', require: 'jrails'
22 22  
23   -group :assets do
24   - gem 'uglifier', '>= 1.0.3'
25   - gem 'sass-rails'
26   -end
  23 +# API dependencies
  24 +gem 'grape', '~> 0.12'
  25 +gem 'grape-entity'
  26 +#FIXME Get the Grape Loggin from master yo solve this issue https://github.com/intridea/grape/issues/1059
  27 +#We have to remove this commit referenve code when update the next release of grape_logging. Actualy we are using (1.1.2)
  28 +gem 'grape_logging', :git => 'https://github.com/aceunreal/grape_logging.git', :ref => 'f1755ae'
  29 +gem 'rack-cors'
  30 +gem 'rack-contrib'
  31 +gem 'liquid', '~> 3.0.3'
  32 +#gem 'grape-swagger-rails'
  33 +gem 'rubyzip'
  34 +
  35 +gem 'execjs'
  36 +gem 'therubyracer'
  37 +
  38 +# FIXME list here all actual dependencies (i.e. the ones in debian/control),
  39 +# with their GEM names (not the Debian package names)
  40 +
  41 +gem 'api-pagination', '~> 4.1.1'
  42 +
  43 +# asset pipeline
  44 +gem 'uglifier', '>= 1.0.3'
  45 +gem 'sass-rails'
27 46  
28 47 group :production do
29 48 gem 'dalli', '~> 2.7.0'
30 49 end
31 50  
32 51 group :test do
33   - gem 'rspec', '~> 2.10.0'
34   - gem 'rspec-rails', '~> 2.10.1'
  52 + gem 'rspec', '~> 2.14.0'
  53 + gem 'rspec-rails', '~> 2.14.1'
35 54 gem 'mocha', '~> 1.1.0', :require => false
36 55 end
37 56  
... ...
Gemfile.lock 0 → 100644
... ... @@ -0,0 +1,281 @@
  1 +GIT
  2 + remote: https://github.com/aceunreal/grape_logging.git
  3 + revision: f1755ae4e1d897a65b20218d40681f59a9630f1b
  4 + ref: f1755ae
  5 + specs:
  6 + grape_logging (1.1.2)
  7 + grape
  8 +
  9 +GEM
  10 + remote: https://rubygems.org/
  11 + specs:
  12 + RedCloth (4.2.9)
  13 + actionmailer (3.2.22)
  14 + actionpack (= 3.2.22)
  15 + mail (~> 2.5.4)
  16 + actionpack (3.2.22)
  17 + activemodel (= 3.2.22)
  18 + activesupport (= 3.2.22)
  19 + builder (~> 3.0.0)
  20 + erubis (~> 2.7.0)
  21 + journey (~> 1.0.4)
  22 + rack (~> 1.4.5)
  23 + rack-cache (~> 1.2)
  24 + rack-test (~> 0.6.1)
  25 + sprockets (~> 2.2.1)
  26 + activemodel (3.2.22)
  27 + activesupport (= 3.2.22)
  28 + builder (~> 3.0.0)
  29 + activerecord (3.2.22)
  30 + activemodel (= 3.2.22)
  31 + activesupport (= 3.2.22)
  32 + arel (~> 3.0.2)
  33 + tzinfo (~> 0.3.29)
  34 + activeresource (3.2.22)
  35 + activemodel (= 3.2.22)
  36 + activesupport (= 3.2.22)
  37 + activesupport (3.2.22)
  38 + i18n (~> 0.6, >= 0.6.4)
  39 + multi_json (~> 1.0)
  40 + acts-as-taggable-on (3.4.4)
  41 + activerecord (>= 3.2, < 5)
  42 + api-pagination (4.1.1)
  43 + arel (3.0.3)
  44 + axiom-types (0.1.1)
  45 + descendants_tracker (~> 0.0.4)
  46 + ice_nine (~> 0.11.0)
  47 + thread_safe (~> 0.3, >= 0.3.1)
  48 + builder (3.0.4)
  49 + capybara (2.1.0)
  50 + mime-types (>= 1.16)
  51 + nokogiri (>= 1.3.3)
  52 + rack (>= 1.0.0)
  53 + rack-test (>= 0.5.4)
  54 + xpath (~> 2.0)
  55 + childprocess (0.5.6)
  56 + ffi (~> 1.0, >= 1.0.11)
  57 + chronic (0.10.2)
  58 + coercible (1.0.0)
  59 + descendants_tracker (~> 0.0.1)
  60 + cucumber (1.0.6)
  61 + builder (>= 2.1.2)
  62 + diff-lcs (>= 1.1.2)
  63 + gherkin (~> 2.4.18)
  64 + json (>= 1.4.6)
  65 + term-ansicolor (>= 1.0.6)
  66 + cucumber-rails (1.0.6)
  67 + capybara (>= 1.1.1)
  68 + cucumber (>= 1.0.6)
  69 + nokogiri (>= 1.5.0)
  70 + daemons (1.1.9)
  71 + dalli (2.7.4)
  72 + database_cleaner (1.2.0)
  73 + descendants_tracker (0.0.4)
  74 + thread_safe (~> 0.3, >= 0.3.1)
  75 + diff-lcs (1.2.5)
  76 + eita-jrails (0.9.5)
  77 + actionpack (~> 3.2, >= 3.1.0)
  78 + activesupport (~> 3.2, >= 3.0.0)
  79 + equalizer (0.0.11)
  80 + erubis (2.7.0)
  81 + eventmachine (1.0.7)
  82 + exception_notification (4.0.1)
  83 + actionmailer (>= 3.0.4)
  84 + activesupport (>= 3.0.4)
  85 + execjs (2.5.2)
  86 + fast_gettext (0.6.12)
  87 + ffi (1.9.10)
  88 + gettext (2.2.1)
  89 + locale
  90 + gherkin (2.4.21)
  91 + json (>= 1.4.6)
  92 + git-version-bump (0.15.1)
  93 + grape (0.12.0)
  94 + activesupport
  95 + builder
  96 + hashie (>= 2.1.0)
  97 + multi_json (>= 1.3.2)
  98 + multi_xml (>= 0.5.2)
  99 + rack (>= 1.3.0)
  100 + rack-accept
  101 + rack-mount
  102 + virtus (>= 1.0.0)
  103 + grape-entity (0.4.5)
  104 + activesupport
  105 + multi_json (>= 1.3.2)
  106 + hashie (2.1.2)
  107 + hike (1.2.3)
  108 + i18n (0.7.0)
  109 + ice_nine (0.11.1)
  110 + journey (1.0.4)
  111 + json (1.8.3)
  112 + libv8 (3.16.14.11)
  113 + liquid (3.0.6)
  114 + locale (2.0.9)
  115 + magic (0.2.9)
  116 + ffi (>= 0.6.3)
  117 + mail (2.5.4)
  118 + mime-types (~> 1.16)
  119 + treetop (~> 1.4.8)
  120 + metaclass (0.0.4)
  121 + mime-types (1.25.1)
  122 + mini_portile (0.6.2)
  123 + minitest (3.2.0)
  124 + mocha (1.1.0)
  125 + metaclass (~> 0.0.1)
  126 + multi_json (1.11.2)
  127 + multi_xml (0.5.5)
  128 + nokogiri (1.6.6.2)
  129 + mini_portile (~> 0.6.0)
  130 + pg (0.13.2)
  131 + polyglot (0.3.5)
  132 + rack (1.4.7)
  133 + rack-accept (0.4.5)
  134 + rack (>= 0.4)
  135 + rack-cache (1.2)
  136 + rack (>= 0.4)
  137 + rack-contrib (1.3.0)
  138 + git-version-bump (~> 0.15)
  139 + rack (~> 1.4)
  140 + rack-cors (0.4.0)
  141 + rack-mount (0.8.3)
  142 + rack (>= 1.0.0)
  143 + rack-ssl (1.3.4)
  144 + rack
  145 + rack-test (0.6.3)
  146 + rack (>= 1.0)
  147 + rails (3.2.22)
  148 + actionmailer (= 3.2.22)
  149 + actionpack (= 3.2.22)
  150 + activerecord (= 3.2.22)
  151 + activeresource (= 3.2.22)
  152 + activesupport (= 3.2.22)
  153 + bundler (~> 1.0)
  154 + railties (= 3.2.22)
  155 + rails_autolink (1.1.6)
  156 + rails (> 3.1)
  157 + railties (3.2.22)
  158 + actionpack (= 3.2.22)
  159 + activesupport (= 3.2.22)
  160 + rack-ssl (~> 1.3.2)
  161 + rake (>= 0.8.7)
  162 + rdoc (~> 3.4)
  163 + thor (>= 0.14.6, < 2.0)
  164 + rake (10.4.2)
  165 + rdoc (3.12.2)
  166 + json (~> 1.4)
  167 + ref (2.0.0)
  168 + rest-client (1.6.9)
  169 + mime-types (~> 1.16)
  170 + rmagick (2.13.4)
  171 + rspec (2.14.1)
  172 + rspec-core (~> 2.14.0)
  173 + rspec-expectations (~> 2.14.0)
  174 + rspec-mocks (~> 2.14.0)
  175 + rspec-core (2.14.8)
  176 + rspec-expectations (2.14.5)
  177 + diff-lcs (>= 1.1.3, < 2.0)
  178 + rspec-mocks (2.14.6)
  179 + rspec-rails (2.14.2)
  180 + actionpack (>= 3.0)
  181 + activemodel (>= 3.0)
  182 + activesupport (>= 3.0)
  183 + railties (>= 3.0)
  184 + rspec-core (~> 2.14.0)
  185 + rspec-expectations (~> 2.14.0)
  186 + rspec-mocks (~> 2.14.0)
  187 + ruby-feedparser (0.9.3)
  188 + magic
  189 + rubyzip (1.1.7)
  190 + sass (3.4.15)
  191 + sass-rails (3.2.6)
  192 + railties (~> 3.2.0)
  193 + sass (>= 3.1.10)
  194 + tilt (~> 1.3)
  195 + selenium-webdriver (2.39.0)
  196 + childprocess (>= 0.2.5)
  197 + multi_json (~> 1.0)
  198 + rubyzip (~> 1.0)
  199 + websocket (~> 1.0.4)
  200 + sprockets (2.2.3)
  201 + hike (~> 1.2)
  202 + multi_json (~> 1.0)
  203 + rack (~> 1.0)
  204 + tilt (~> 1.1, != 1.3.0)
  205 + term-ansicolor (1.3.2)
  206 + tins (~> 1.0)
  207 + therubyracer (0.12.2)
  208 + libv8 (~> 3.16.14.0)
  209 + ref
  210 + thin (1.3.1)
  211 + daemons (>= 1.0.9)
  212 + eventmachine (>= 0.12.6)
  213 + rack (>= 1.0.0)
  214 + thor (0.19.1)
  215 + thread_safe (0.3.5)
  216 + tilt (1.4.1)
  217 + tins (1.5.4)
  218 + treetop (1.4.15)
  219 + polyglot
  220 + polyglot (>= 0.3.1)
  221 + tzinfo (0.3.44)
  222 + uglifier (2.7.1)
  223 + execjs (>= 0.3.0)
  224 + json (>= 1.8.0)
  225 + virtus (1.0.5)
  226 + axiom-types (~> 0.1)
  227 + coercible (~> 1.0)
  228 + descendants_tracker (~> 0.0, >= 0.0.3)
  229 + equalizer (~> 0.0, >= 0.0.9)
  230 + websocket (1.0.7)
  231 + whenever (0.9.4)
  232 + chronic (>= 0.6.3)
  233 + will_paginate (3.0.7)
  234 + xpath (2.0.0)
  235 + nokogiri (~> 1.3)
  236 +
  237 +PLATFORMS
  238 + ruby
  239 +
  240 +DEPENDENCIES
  241 + RedCloth (~> 4.2.9)
  242 + acts-as-taggable-on (~> 3.4.2)
  243 + api-pagination (~> 4.1.1)
  244 + capybara (~> 2.1.0)
  245 + cucumber (~> 1.0.6)
  246 + cucumber-rails (~> 1.0.6)
  247 + daemons (~> 1.1.5)
  248 + dalli (~> 2.7.0)
  249 + database_cleaner (~> 1.2.0)
  250 + eita-jrails (~> 0.9.5)
  251 + exception_notification (~> 4.0.1)
  252 + execjs
  253 + fast_gettext (~> 0.6.8)
  254 + gettext (~> 2.2.1)
  255 + grape (~> 0.12)
  256 + grape-entity
  257 + grape_logging!
  258 + liquid (~> 3.0.3)
  259 + locale (~> 2.0.5)
  260 + minitest (~> 3.2.0)
  261 + mocha (~> 1.1.0)
  262 + nokogiri (~> 1.6.0)
  263 + pg (~> 0.13.2)
  264 + rack-contrib
  265 + rack-cors
  266 + rails (~> 3.2.22)
  267 + rails_autolink (~> 1.1.5)
  268 + rake
  269 + rest-client (~> 1.6.7)
  270 + rmagick (~> 2.13.1)
  271 + rspec (~> 2.14.0)
  272 + rspec-rails (~> 2.14.1)
  273 + ruby-feedparser (~> 0.7)
  274 + rubyzip
  275 + sass-rails
  276 + selenium-webdriver (~> 2.39.0)
  277 + therubyracer
  278 + thin (~> 1.3.1)
  279 + uglifier (>= 1.0.3)
  280 + whenever
  281 + will_paginate (~> 3.0.3)
... ...
INSTALL.chat.md
1   -XMPP/Chat Setup
2   -===============
  1 +Automatic XMPP/Chat Setup
  2 +=========================
  3 +
  4 +Since Noosfero 1.2, the XMPP/Chat can be installed via `noosfero-chat` Debian
  5 +package. So you don't need to follow the manual instructions here if you
  6 +already have it installed on your system.
  7 +
  8 +But if you are going to install the `noosfero-chat` package on a system that
  9 +already has `noosfero` older 1.2 installed then you need to check if apache's
  10 +configuration file `/etc/apache2/sites-available/noosfero` has this line below:
  11 +
  12 + Include /usr/share/noosfero/util/chat/apache/xmpp.conf
  13 +
  14 +Manual XMPP/Chat Setup
  15 +======================
3 16  
4 17 The samples of config file to configure a XMPP/BOSH server with ejabberd,
5 18 postgresql and apache2 can be found at util/chat directory.
... ... @@ -8,7 +21,7 @@ This setup supposes that you are using Noosfero installed via Debian package
8 21 in a production environment.
9 22  
10 23 Steps
11   -=====
  24 +-----
12 25  
13 26 This is a step-by-step guide to get a XMPP service working, in a Debian system.
14 27  
... ... @@ -144,15 +157,8 @@ You should see a page with a message like that:
144 157  
145 158 ## 9. Test chat session
146 159  
147   -Open Noosfero console and execute:
148   -
149   ->> environment = Environment.default
150   ->> user = Person['guest']
151   ->> password = user.user.crypted_password
152   ->> login = user.jid
153   ->> RubyBOSH.initialize_session(login, password, "http://#{environment.default_hostname}/http-bind", :wait => 30, :hold => 1, :window => 5
154   -
155   -If you have luck, should see something like that:
  160 +Run `./script/noosfero-test-chat-session`. If you have luck, should see
  161 +something like that:
156 162  
157 163 Ruby-BOSH - SEND
158 164 <body window="5" rid="60265" xmlns="http://jabber.org/protocol/httpbind" xmlns:xmpp="urn:xmpp:xbosh" to="vagrant-debian-squeeze.vagrantup.com" wait="30" xmpp:version="1.0" hold="1"/>
... ...
INSTALL.https.md
... ... @@ -11,8 +11,8 @@ as below:
11 11  
12 12 # mkdir /etc/noosfero/ssl
13 13 # cd /etc/noosfero/ssl
14   - # openssl genrsa 1024 > noosfero.key
15   - # openssl req -new -x509 -nodes -sha1 -days $[10*365] -key noosfero.key > noosfero.cert
  14 + # openssl genrsa 2048 > noosfero.key
  15 + # openssl req -new -x509 -sha256 -nodes -days $[10*365] -key noosfero.key > noosfero.cert
16 16 # cat noosfero.key noosfero.cert > noosfero.pem
17 17  
18 18 ## Web server configuration
... ...
INSTALL.md
... ... @@ -74,7 +74,7 @@ downloading from git
74 74  
75 75 Here we are cloning the noosfero repository from git. Note: you will need to install git before.
76 76  
77   - $ git clone git://gitorious.org/noosfero/noosfero.git current
  77 + $ git clone https://gitlab.com/noosfero/noosfero.git current
78 78 $ cd current
79 79 $ git checkout -b stable origin/stable
80 80  
... ...
Rakefile
... ... @@ -15,4 +15,21 @@ Noosfero::Application.load_tasks
15 15 Dir.glob(pattern).sort
16 16 end.flatten.each do |taskfile|
17 17 load taskfile
  18 +end
  19 +
  20 +# plugins' tasks
  21 +plugins_tasks = Dir.glob("config/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake").sort +
  22 + Dir.glob("config/plugins/*/vendor/plugins/*/{tasks,lib/tasks,rails/tasks}/**/*.rake").sort
  23 +plugins_tasks.each{ |ext| load ext }
  24 +
  25 +
  26 +desc "Print out grape routes"
  27 +task :grape_routes => :environment do
  28 + #require 'api/api.rb'
  29 + Noosfero::API::API.routes.each do |route|
  30 + puts route
  31 + method = route.route_method
  32 + path = route.route_path
  33 + puts " #{method} #{path}"
  34 + end
18 35 end
... ...
app/controllers/admin/admin_panel_controller.rb
... ... @@ -71,22 +71,4 @@ class AdminPanelController &lt; AdminController
71 71 end
72 72 end
73 73 end
74   -
75   - def manage_organizations_status
76   - scope = environment.organizations
77   - @filter = params[:filter] || 'any'
78   - @title = "Organization profiles"
79   - @title = @title+" - "+@filter if @filter != 'any'
80   -
81   - if @filter == 'enabled'
82   - scope = scope.visible
83   - elsif @filter == 'disabled'
84   - scope = scope.disabled
85   - end
86   -
87   - scope = scope.order('name ASC')
88   -
89   - @q = params[:q]
90   - @collection = find_by_contents(:organizations, environment, scope, @q, {:per_page => 10, :page => params[:npage]})[:results]
91   - end
92 74 end
... ...
app/controllers/admin/environment_design_controller.rb
1 1 class EnvironmentDesignController < BoxOrganizerController
2   -
  2 +
3 3 protect 'edit_environment_design', :environment
4 4  
  5 + def filtered_available_blocks(blocks=nil)
  6 + filtered_available_blocks = []
  7 + blocks.each { |block| filtered_available_blocks << block unless @environment.disabled_blocks.include?(block.name) }
  8 + filtered_available_blocks
  9 + end
  10 +
5 11 def available_blocks
6 12 @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ]
7 13 @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment)
8 14 end
9 15  
  16 + def index
  17 + available_blocks
  18 + end
  19 +
10 20 end
... ...
app/controllers/admin/environment_email_templates_controller.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +class EnvironmentEmailTemplatesController < EmailTemplatesController
  2 +
  3 + protect 'manage_email_templates', :environment
  4 +
  5 + protected
  6 +
  7 + def owner
  8 + environment
  9 + end
  10 +
  11 + before_filter :only => :index do
  12 + @back_to = url_for(:controller => :admin_panel)
  13 + end
  14 +
  15 +end
... ...
app/controllers/admin/features_controller.rb
1 1 class FeaturesController < AdminController
  2 +
2 3 protect 'edit_environment_features', :environment
3   -
  4 +
4 5 def index
5 6 @features = Environment.available_features.sort_by{|k,v|v}
6 7 end
7 8  
  9 + def manage_blocks
  10 + @blocks = [ ArticleBlock,
  11 + TagsBlock,
  12 + RecentDocumentsBlock,
  13 + ProfileInfoBlock,
  14 + LinkListBlock,
  15 + MyNetworkBlock,
  16 + FeedReaderBlock,
  17 + ProfileImageBlock,
  18 + LocationBlock,
  19 + SlideshowBlock,
  20 + ProfileSearchBlock,
  21 + HighlightsBlock,
  22 + FriendsBlock,
  23 + FavoriteEnterprisesBlock,
  24 + CommunitiesBlock,
  25 + EnterprisesBlock,
  26 + MembersBlock,
  27 + DisabledEnterpriseMessageBlock,
  28 + ProductCategoriesBlock,
  29 + FeaturedProductsBlock,
  30 + FansBlock,
  31 + ProductsBlock ]
  32 +
  33 + @blocks += plugins.dispatch(:extra_blocks)
  34 + @blocks.sort_by! { |block| block.name }
  35 + end
  36 +
8 37 post_only :update
9 38 def update
10 39 if @environment.update_attributes(params[:environment])
... ... @@ -15,6 +44,17 @@ class FeaturesController &lt; AdminController
15 44 end
16 45 end
17 46  
  47 + post_only :update_blocks
  48 + def update_blocks
  49 + params[:environment].delete(:available_blocks)
  50 + if @environment.update_attributes(params[:environment])
  51 + session[:notice] = _('Blocks updated successfully.')
  52 + redirect_to :action => 'manage_blocks'
  53 + else
  54 + render :action => 'manage_blocks'
  55 + end
  56 + end
  57 +
18 58 def manage_fields
19 59 @person_fields = Person.fields
20 60 @enterprise_fields = Enterprise.fields
... ...
app/controllers/admin/organizations_controller.rb 0 → 100644
... ... @@ -0,0 +1,66 @@
  1 +class OrganizationsController < AdminController
  2 +
  3 + protect 'manage_environment_organizations', :environment
  4 +
  5 + def index
  6 + @filter = params[:filter] || 'any'
  7 + @title = _('Organization profiles')
  8 + @type = params[:type] || "any"
  9 + @types_filter = [[_('All'), 'any'], [_('Community'), 'Community'], [_('Enterprise'), 'Enterprise']]
  10 + @types_filter = @types_filter | @plugins.dispatch(:organization_types_filter_options)
  11 +
  12 + scope = @plugins.dispatch_first(:filter_manage_organization_scope, @type)
  13 + if scope.blank?
  14 + scope = environment.organizations
  15 + scope = scope.where(:type => @type) if @type != 'any'
  16 + end
  17 +
  18 + if @filter == 'enabled'
  19 + scope = scope.visible
  20 + elsif @filter == 'disabled'
  21 + scope = scope.disabled
  22 + end
  23 +
  24 + scope = scope.order('name ASC')
  25 +
  26 + @q = params[:q]
  27 + @collection = find_by_contents(:organizations, environment, scope, @q, {:per_page => per_page, :page => params[:npage]})[:results]
  28 + end
  29 +
  30 + def activate
  31 + organization = environment.organizations.find(params[:id])
  32 + if organization.enable
  33 + render :text => (_('%s enabled') % organization.name).to_json
  34 + else
  35 + render :text => (_('%s could not be enabled') % organization.name).to_json
  36 + end
  37 + end
  38 +
  39 + def deactivate
  40 + organization = environment.organizations.find(params[:id])
  41 + if organization.disable
  42 + render :text => (_('%s disabled') % organization.name).to_json
  43 + else
  44 + render :text => (_('%s could not be disable') % organization.name).to_json
  45 + end
  46 + end
  47 +
  48 + def destroy
  49 + if request.post?
  50 + organization = environment.organizations.find(params[:id])
  51 + if organization && organization.destroy
  52 + render :text => (_('%s removed') % organization.name).to_json
  53 + else
  54 + render :text => (_('%s could not be removed') % organization.name).to_json
  55 + end
  56 + else
  57 + render :nothing => true
  58 + end
  59 + end
  60 +
  61 + private
  62 +
  63 + def per_page
  64 + 10
  65 + end
  66 +end
... ...
app/controllers/admin/role_controller.rb
... ... @@ -2,7 +2,7 @@ class RoleController &lt; AdminController
2 2 protect 'manage_environment_roles', :environment
3 3  
4 4 def index
5   - @roles = environment.roles.find(:all)
  5 + @roles = environment.roles.find(:all, :conditions => {:profile_id => nil})
6 6 end
7 7  
8 8 def new
... ...
app/controllers/application_controller.rb
... ... @@ -7,8 +7,17 @@ class ApplicationController &lt; ActionController::Base
7 7 before_filter :detect_stuff_by_domain
8 8 before_filter :init_noosfero_plugins
9 9 before_filter :allow_cross_domain_access
  10 +
  11 + before_filter :login_from_cookie
10 12 before_filter :login_required, :if => :private_environment?
  13 +
11 14 before_filter :verify_members_whitelist, :if => [:private_environment?, :user]
  15 + before_filter :log_user
  16 +
  17 + def log_user
  18 + Rails.logger.info "Logged in: #{user.identifier}" if user
  19 + end
  20 + before_filter :redirect_to_current_user
12 21  
13 22 def verify_members_whitelist
14 23 render_access_denied unless user.is_admin? || environment.in_whitelist?(user)
... ... @@ -71,8 +80,8 @@ class ApplicationController &lt; ActionController::Base
71 80 FastGettext.available_locales = environment.available_locales
72 81 FastGettext.default_locale = environment.default_locale
73 82 FastGettext.locale = (params[:lang] || session[:lang] || environment.default_locale || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en')
74   - I18n.locale = FastGettext.locale
75   - I18n.default_locale = FastGettext.default_locale
  83 + I18n.locale = FastGettext.locale.to_s.gsub '_', '-'
  84 + I18n.default_locale = FastGettext.default_locale.to_s.gsub '_', '-'
76 85 if params[:lang]
77 86 session[:lang] = params[:lang]
78 87 end
... ... @@ -192,4 +201,15 @@ class ApplicationController &lt; ActionController::Base
192 201 def private_environment?
193 202 @environment.enabled?(:restrict_to_members)
194 203 end
  204 +
  205 + def redirect_to_current_user
  206 + if params[:profile] == '~'
  207 + if logged_in?
  208 + redirect_to params.merge(:profile => user.identifier)
  209 + else
  210 + render_not_found
  211 + end
  212 + end
  213 + end
  214 +
195 215 end
... ...
app/controllers/box_organizer_controller.rb
... ... @@ -3,12 +3,11 @@ class BoxOrganizerController &lt; ApplicationController
3 3 before_filter :login_required
4 4  
5 5 def index
  6 + @available_blocks = available_blocks.uniq.sort_by(&:pretty_name)
6 7 end
7 8  
8 9 def move_block
9   - @block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
10   -
11   - @source_box = @block.box
  10 + @block = params[:id] ? boxes_holder.blocks.find(params[:id].gsub(/^block-/, '')) : nil
12 11  
13 12 target_position = nil
14 13  
... ... @@ -20,9 +19,12 @@ class BoxOrganizerController &lt; ApplicationController
20 19 else
21 20 (params[:target] =~ /end-of-box-([0-9]+)/)
22 21  
23   - @target_box = boxes_holder.boxes.find($1)
  22 + @target_box = boxes_holder.boxes.find_by_id($1)
24 23 end
25 24  
  25 + @block = new_block(params[:type], @target_box) if @block.nil?
  26 + @source_box = @block.box
  27 +
26 28 if (@source_box != @target_box)
27 29 @block.remove_from_list
28 30 @block.box = @target_box
... ... @@ -58,23 +60,6 @@ class BoxOrganizerController &lt; ApplicationController
58 60 redirect_to :action => 'index'
59 61 end
60 62  
61   - def add_block
62   - type = params[:type]
63   - if ! type.blank?
64   - if available_blocks.map(&:name).include?(type)
65   - boxes_holder.boxes.find(params[:box_id]).blocks << type.constantize.new
66   - redirect_to :action => 'index'
67   - else
68   - raise ArgumentError.new("Type %s is not allowed. Go away." % type)
69   - end
70   - else
71   - @center_block_types = (Box.acceptable_center_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => 1)
72   - @side_block_types = (Box.acceptable_side_blocks & available_blocks) + plugins.dispatch(:extra_blocks, :type => boxes_holder.class, :position => [2,3])
73   - @boxes = boxes_holder.boxes.with_position
74   - render :action => 'add_block', :layout => false
75   - end
76   - end
77   -
78 63 def edit
79 64 @block = boxes_holder.blocks.find(params[:id])
80 65 render :action => 'edit', :layout => false
... ... @@ -98,8 +83,12 @@ class BoxOrganizerController &lt; ApplicationController
98 83  
99 84 def save
100 85 @block = boxes_holder.blocks.find(params[:id])
101   - @block.update_attributes(params[:block])
102   - redirect_to :action => 'index'
  86 + if @block.kind_of?(RawHTMLBlock) && !user.is_admin?(environment)
  87 + render_access_denied
  88 + else
  89 + @block.update_attributes(params[:block])
  90 + redirect_to :action => 'index'
  91 + end
103 92 end
104 93  
105 94 def boxes_editor?
... ... @@ -121,6 +110,27 @@ class BoxOrganizerController &lt; ApplicationController
121 110 redirect_to :action => 'index'
122 111 end
123 112  
  113 + def show_block_type_info
  114 + type = params[:type]
  115 + if type.blank? || !available_blocks.map(&:name).include?(type)
  116 + raise ArgumentError.new("Type %s is not allowed. Go away." % type)
  117 + end
  118 + @block = type.constantize.new
  119 + @block.box = Box.new(:owner => boxes_holder)
  120 + render :action => 'show_block_type_info', :layout => false
  121 + end
  122 +
124 123 protected :boxes_editor?
125 124  
  125 + protected
  126 +
  127 + def new_block(type, box)
  128 + if !available_blocks.map(&:name).include?(type)
  129 + raise ArgumentError.new("Type %s is not allowed. Go away." % type)
  130 + end
  131 + block = type.constantize.new
  132 + box.blocks << block
  133 + block
  134 + end
  135 +
126 136 end
... ...
app/controllers/email_templates_controller.rb 0 → 100644
... ... @@ -0,0 +1,62 @@
  1 +class EmailTemplatesController < ApplicationController
  2 +
  3 + def index
  4 + @email_templates = owner.email_templates
  5 + end
  6 +
  7 + def show
  8 + @email_template = owner.email_templates.find(params[:id])
  9 +
  10 + respond_to do |format|
  11 + format.html # show.html.erb
  12 + format.json { render json: @email_template }
  13 + end
  14 + end
  15 +
  16 + def show_parsed
  17 + @email_template = owner.email_templates.find(params[:id])
  18 + template_params = {:profile => owner, :environment => environment}
  19 + render json: {:parsed_body => @email_template.parsed_body(template_params), :parsed_subject => @email_template.parsed_subject(template_params)}
  20 + end
  21 +
  22 + def new
  23 + @email_template = owner.email_templates.build(:owner => owner)
  24 + end
  25 +
  26 + def edit
  27 + @email_template = owner.email_templates.find(params[:id])
  28 + end
  29 +
  30 + def create
  31 + @email_template = owner.email_templates.build(params[:email_template])
  32 + @email_template.owner = owner
  33 +
  34 + if @email_template.save
  35 + session[:notice] = _('Email template was successfully created.')
  36 + redirect_to url_for(:action => :index)
  37 + else
  38 + render action: "new"
  39 + end
  40 + end
  41 +
  42 + def update
  43 + @email_template = owner.email_templates.find(params[:id])
  44 +
  45 + if @email_template.update_attributes(params[:email_template])
  46 + session[:notice] = _('Email template was successfully updated.')
  47 + redirect_to url_for(:action => :index)
  48 + else
  49 + render action: "edit"
  50 + end
  51 + end
  52 +
  53 + def destroy
  54 + @email_template = owner.email_templates.find(params[:id])
  55 + @email_template.destroy
  56 +
  57 + respond_to do |format|
  58 + format.html { redirect_to url_for(:action => :index)}
  59 + format.json { head :no_content }
  60 + end
  61 + end
  62 +end
... ...
app/controllers/my_profile/cms_controller.rb
... ... @@ -6,7 +6,7 @@ class CmsController &lt; MyProfileController
6 6  
7 7 def search_tags
8 8 arg = params[:term].downcase
9   - result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
  9 + result = ActsAsTaggableOn::Tag.where('name ILIKE ?', "%#{arg}%").limit(10)
10 10 render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json'
11 11 end
12 12  
... ... @@ -27,20 +27,13 @@ class CmsController &lt; MyProfileController
27 27  
28 28 helper_method :file_types
29 29  
30   - protect_if :only => :upload_files do |c, user, profile|
31   - article_id = c.params[:parent_id]
32   - (!article_id.blank? && profile.articles.find(article_id).allow_create?(user)) ||
33   - (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)))
34   - end
35   -
36   - protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :publish_on_portal_community, :publish_on_communities, :search_communities_to_publish, :upload_files, :new] do |c, user, profile|
  30 + protect_if :except => [:suggest_an_article, :set_home_page, :edit, :destroy, :publish, :upload_files, :new] do |c, user, profile|
37 31 user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile))
38 32 end
39 33  
40   - protect_if :only => :new do |c, user, profile|
41   - article = profile.articles.find_by_id(c.params[:parent_id])
42   - (!article.nil? && (article.allow_create?(user) || article.parent.allow_create?(user))) ||
43   - (user && (user.has_permission?('post_content', profile) || user.has_permission?('publish_content', profile)))
  34 + protect_if :only => [:new, :upload_files] do |c, user, profile|
  35 + parent = profile.articles.find_by_id(c.params[:parent_id])
  36 + user && user.can_post_content?(profile, parent)
44 37 end
45 38  
46 39 protect_if :only => :destroy do |c, user, profile|
... ... @@ -101,6 +94,11 @@ class CmsController &lt; MyProfileController
101 94 record_coming
102 95 if request.post?
103 96 @article.image = nil if params[:remove_image] == 'true'
  97 + if @article.image.present? && params[:article][:image_builder] &&
  98 + params[:article][:image_builder][:label]
  99 + @article.image.label = params[:article][:image_builder][:label]
  100 + @article.image.save!
  101 + end
104 102 @article.last_changed_by = user
105 103 if @article.update_attributes(params[:article])
106 104 if !continue
... ... @@ -112,6 +110,11 @@ class CmsController &lt; MyProfileController
112 110 end
113 111 end
114 112 end
  113 +
  114 + unless @article.kind_of?(RssFeed)
  115 + @escaped_body = CGI::escapeHTML(@article.body || '')
  116 + @escaped_abstract = CGI::escapeHTML(@article.abstract || '')
  117 + end
115 118 end
116 119  
117 120 def new
... ... @@ -143,7 +146,14 @@ class CmsController &lt; MyProfileController
143 146 klass = @type.constantize
144 147 article_data = environment.enabled?('articles_dont_accept_comments_by_default') ? { :accept_comments => false } : {}
145 148 article_data.merge!(params[:article]) if params[:article]
146   - @article = klass.new(article_data)
  149 + article_data.merge!(:profile => profile) if profile
  150 +
  151 + @article = if params[:clone]
  152 + current_article = profile.articles.find(params[:id])
  153 + current_article.copy_without_save
  154 + else
  155 + klass.new(article_data)
  156 + end
147 157  
148 158 parent = check_parent(params[:parent_id])
149 159 if parent
... ... @@ -220,7 +230,7 @@ class CmsController &lt; MyProfileController
220 230 if @errors.any?
221 231 render :action => 'upload_files', :parent_id => @parent_id
222 232 else
223   - session[:notice] = _('File(s) successfully uploaded')
  233 + session[:notice] = _('File(s) successfully uploaded')
224 234 if @back_to
225 235 redirect_to @back_to
226 236 elsif @parent
... ... @@ -357,7 +367,8 @@ class CmsController &lt; MyProfileController
357 367 @task.ip_address = request.remote_ip
358 368 @task.user_agent = request.user_agent
359 369 @task.referrer = request.referrer
360   - if verify_recaptcha(:model => @task, :message => _('Please type the words correctly')) && @task.save
  370 + @task.requestor = current_person if logged_in?
  371 + if (logged_in? || verify_recaptcha(:model => @task, :message => _('Please type the words correctly'))) && @task.save
361 372 session[:notice] = _('Thanks for your suggestion. The community administrators were notified.')
362 373 redirect_to @back_to
363 374 end
... ... @@ -453,7 +464,8 @@ class CmsController &lt; MyProfileController
453 464 end
454 465  
455 466 def refuse_blocks
456   - if ['TinyMceArticle', 'TextileArticle', 'Event', 'EnterpriseHomepage'].include?(@type)
  467 + article_types = ['TinyMceArticle', 'TextileArticle', 'Event', 'EnterpriseHomepage'] + @plugins.dispatch(:content_types).map {|type| type.name}
  468 + if article_types.include?(@type)
457 469 @no_design_blocks = true
458 470 end
459 471 end
... ...
app/controllers/my_profile/enterprise_validation_controller.rb
1 1 class EnterpriseValidationController < MyProfileController
2 2  
3 3 protect 'validate_enterprise', :profile
4   -
  4 +
5 5 def index
6 6 @pending_validations = profile.pending_validations
7 7 end
... ... @@ -27,7 +27,7 @@ class EnterpriseValidationController &lt; MyProfileController
27 27 post_only :reject
28 28 def reject
29 29 @pending = profile.find_pending_validation(params[:id])
30   - if @pending
  30 + if @pending
31 31 @pending.reject_explanation = params[:reject_explanation]
32 32 begin
33 33 @pending.reject
... ...
app/controllers/my_profile/favorite_enterprises_controller.rb
1 1 class FavoriteEnterprisesController < MyProfileController
2   -
3   -# protect 'manage_favorite_enteprises', :profile
  2 +
  3 +# protect 'manage_favorite_enterprises', :profile
4 4  
5 5 requires_profile_class Person
6   -
  6 +
7 7 def index
8 8 @favorite_enterprises = profile.favorite_enterprises
9 9 end
... ... @@ -12,7 +12,7 @@ class FavoriteEnterprisesController &lt; MyProfileController
12 12 @favorite_enterprise = Enterprise.find(params[:id])
13 13 if request.post? && params[:confirmation]
14 14 profile.favorite_enterprises << @favorite_enterprise
15   - redirect_to :action => 'index'
  15 + redirect_to :action => 'index'
16 16 end
17 17 end
18 18  
... ...
app/controllers/my_profile/friends_controller.rb
1 1 class FriendsController < MyProfileController
2   -
  2 +
3 3 protect 'manage_friends', :profile
4   -
  4 +
5 5 def index
6   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  6 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
7 7 if is_cache_expired?(profile.manage_friends_cache_key(params))
8 8 @friends = profile.friends.paginate(:per_page => per_page, :page => params[:npage])
9 9 end
... ... @@ -18,7 +18,7 @@ class FriendsController &lt; MyProfileController
18 18 end
19 19  
20 20 def suggest
21   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  21 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
22 22 end
23 23  
24 24 def remove_suggestion
... ... @@ -26,13 +26,13 @@ class FriendsController &lt; MyProfileController
26 26 redirect_to :action => 'suggest' unless @person
27 27 if @person && request.post?
28 28 profile.remove_suggestion(@person)
29   - @suggestions = profile.profile_suggestions.of_person.enabled.includes(:suggestion).limit(per_page)
  29 + @suggestions = profile.suggested_profiles.of_person.enabled.includes(:suggestion).limit(per_page)
30 30 render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :friends_suggestions, :per_page => params[:per_page] || per_page }
31 31 end
32 32 end
33 33  
34 34 def connections
35   - @suggestion = profile.profile_suggestions.of_person.enabled.find_by_suggestion_id(params[:id])
  35 + @suggestion = profile.suggested_profiles.of_person.enabled.find_by_suggestion_id(params[:id])
36 36 if @suggestion
37 37 @tags = @suggestion.tag_connections
38 38 @profiles = @suggestion.profile_connections
... ...
app/controllers/my_profile/manage_products_controller.rb
... ... @@ -35,7 +35,7 @@ class ManageProductsController &lt; ApplicationController
35 35 end
36 36  
37 37 def categories_for_selection
38   - @category = Category.find(params[:category_id]) if params[:category_id]
  38 + @category = environment.categories.find_by_id params[:category_id]
39 39 @object_name = params[:object_name]
40 40 if @category
41 41 @categories = @category.children
... ... @@ -95,6 +95,20 @@ class ManageProductsController &lt; ApplicationController
95 95 end
96 96 end
97 97  
  98 + def show_category_tree
  99 + @category = environment.categories.find params[:category_id]
  100 + render :partial => 'selected_category_tree'
  101 + end
  102 +
  103 + def search_categories
  104 + @term = params[:term].downcase
  105 + conditions = ['LOWER(name) LIKE ? OR LOWER(name) LIKE ?', "#{@term}%", "% #{@term}%"]
  106 + @categories = ProductCategory.all :conditions => conditions, :limit => 10
  107 + render :json => (@categories.map do |category|
  108 + {:label => category.name, :value => category.id}
  109 + end)
  110 + end
  111 +
98 112 def add_input
99 113 @product = @profile.products.find(params[:id])
100 114 @input = @product.inputs.build
... ... @@ -192,7 +206,8 @@ class ManageProductsController &lt; ApplicationController
192 206 end
193 207  
194 208 def certifiers_for_selection
195   - @qualifier = Qualifier.exists?(params[:id]) ? Qualifier.find(params[:id]) : nil
  209 + # updated to use hash as argument to exists? to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  210 + @qualifier = Qualifier.exists?(:id => params[:id]) ? Qualifier.find(params[:id]) : nil
196 211 render :update do |page|
197 212 page.replace_html params[:certifier_area], :partial => 'certifiers_for_selection'
198 213 end
... ...
app/controllers/my_profile/maps_controller.rb
... ... @@ -16,6 +16,7 @@ class MapsController &lt; MyProfileController
16 16  
17 17 Profile.transaction do
18 18 if profile.update_attributes!(params[:profile_data])
  19 + BlockSweeper.expire_blocks profile.blocks.select{ |b| b.class == LocationBlock }
19 20 session[:notice] = _('Address was updated successfully!')
20 21 redirect_to :action => 'edit_location'
21 22 end
... ...
app/controllers/my_profile/memberships_controller.rb
... ... @@ -40,7 +40,7 @@ class MembershipsController &lt; MyProfileController
40 40 end
41 41  
42 42 def suggest
43   - @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(per_page)
  43 + @suggestions = profile.suggested_profiles.of_community.enabled.includes(:suggestion).limit(per_page)
44 44 end
45 45  
46 46 def remove_suggestion
... ... @@ -49,13 +49,13 @@ class MembershipsController &lt; MyProfileController
49 49 redirect_to :action => 'suggest' unless @community
50 50 if @community && request.post?
51 51 profile.remove_suggestion(@community)
52   - @suggestions = profile.profile_suggestions.of_community.enabled.includes(:suggestion).limit(custom_per_page)
  52 + @suggestions = profile.suggested_profiles.of_community.enabled.includes(:suggestion).limit(custom_per_page)
53 53 render :partial => 'shared/profile_suggestions_list', :locals => { :suggestions => @suggestions, :collection => :communities_suggestions, :per_page => custom_per_page}
54 54 end
55 55 end
56 56  
57 57 def connections
58   - @suggestion = profile.profile_suggestions.of_community.enabled.find_by_suggestion_id(params[:id])
  58 + @suggestion = profile.suggested_profiles.of_community.enabled.find_by_suggestion_id(params[:id])
59 59 if @suggestion
60 60 @tags = @suggestion.tag_connections
61 61 @profiles = @suggestion.profile_connections
... ...
app/controllers/my_profile/profile_design_controller.rb
... ... @@ -4,11 +4,20 @@ class ProfileDesignController &lt; BoxOrganizerController
4 4  
5 5 protect 'edit_profile_design', :profile
6 6  
7   - before_filter :protect_fixed_block, :only => [:save, :move_block]
  7 + before_filter :protect_uneditable_block, :only => [:save]
  8 + before_filter :protect_fixed_block, :only => [:move_block]
  9 +
  10 + def protect_uneditable_block
  11 + block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
  12 + if !current_person.is_admin? && !block.editable?
  13 + render_access_denied
  14 + end
  15 + end
8 16  
9 17 def protect_fixed_block
  18 + return if params[:id].blank?
10 19 block = boxes_holder.blocks.find(params[:id].gsub(/^block-/, ''))
11   - if block.fixed && !current_person.is_admin?
  20 + if block.present? && !current_person.is_admin? && !block.movable?
12 21 render_access_denied
13 22 end
14 23 end
... ...
app/controllers/my_profile/profile_editor_controller.rb
... ... @@ -5,6 +5,7 @@ class ProfileEditorController &lt; MyProfileController
5 5  
6 6 before_filter :access_welcome_page, :only => [:welcome_page]
7 7 before_filter :back_to
  8 + before_filter :forbid_destroy_profile, :only => [:destroy_profile]
8 9 helper_method :has_welcome_page
9 10  
10 11 def index
... ... @@ -18,7 +19,10 @@ class ProfileEditorController &lt; MyProfileController
18 19 @profile_data = profile
19 20 @possible_domains = profile.possible_domains
20 21 if request.post?
21   - params[:profile_data][:fields_privacy] ||= {} if profile.person? && params[:profile_data].is_a?(Hash)
  22 + if profile.person? && params[:profile_data].is_a?(Hash)
  23 + params[:profile_data][:fields_privacy] ||= {}
  24 + params[:profile_data][:custom_fields] ||= {}
  25 + end
22 26 Profile.transaction do
23 27 Image.transaction do
24 28 begin
... ... @@ -109,7 +113,7 @@ class ProfileEditorController &lt; MyProfileController
109 113 profile = environment.profiles.find(params[:id])
110 114 if profile.disable
111 115 profile.save
112   - session[:notice] = _("The profile '#{profile.name}' was deactivated.")
  116 + session[:notice] = _("The profile '%s' was deactivated.") % profile.name
113 117 else
114 118 session[:notice] = _('Could not deactivate profile.')
115 119 end
... ... @@ -123,7 +127,7 @@ class ProfileEditorController &lt; MyProfileController
123 127 profile = environment.profiles.find(params[:id])
124 128  
125 129 if profile.enable
126   - session[:notice] = _("The profile '#{profile.name}' was activated.")
  130 + session[:notice] = _("The profile '%s' was activated.") % profile.name
127 131 else
128 132 session[:notice] = _('Could not activate the profile.')
129 133 end
... ... @@ -155,4 +159,10 @@ class ProfileEditorController &lt; MyProfileController
155 159 end
156 160 end
157 161  
  162 + def forbid_destroy_profile
  163 + if environment.enabled?('forbid_destroy_profile') && !current_person.is_admin?(environment)
  164 + session[:notice] = _('You can not destroy the profile.')
  165 + redirect_to_previous_location
  166 + end
  167 + end
158 168 end
... ...
app/controllers/my_profile/profile_email_templates_controller.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +class ProfileEmailTemplatesController < EmailTemplatesController
  2 +
  3 + needs_profile
  4 + protect 'manage_email_templates', :profile
  5 +
  6 + protected
  7 +
  8 + def owner
  9 + profile
  10 + end
  11 +
  12 + before_filter :only => :index do
  13 + @back_to = url_for(:controller => :profile_editor)
  14 + end
  15 +
  16 +end
... ...
app/controllers/my_profile/profile_members_controller.rb
... ... @@ -58,6 +58,7 @@ class ProfileMembersController &lt; MyProfileController
58 58  
59 59 def change_role
60 60 @roles = Profile::Roles.organization_member_roles(environment.id)
  61 + @custom_roles = profile.custom_roles
61 62 begin
62 63 @member = profile.members.find(params[:id])
63 64 rescue ActiveRecord::RecordNotFound
... ...
app/controllers/my_profile/profile_roles_controller.rb 0 → 100644
... ... @@ -0,0 +1,116 @@
  1 +class ProfileRolesController < MyProfileController
  2 +
  3 + protect 'manage_custom_roles', :profile
  4 +
  5 + def index
  6 + @roles = profile.custom_roles
  7 + end
  8 +
  9 + def new
  10 + @role = Role.new
  11 + end
  12 +
  13 + def create
  14 + @role = Role.new({:name => params[:role][:name], :permissions => params[:role][:permissions], :environment => environment }, :without_protection => true)
  15 + if @role.save
  16 + profile.custom_roles << @role
  17 + redirect_to :action => 'show', :id => @role
  18 + else
  19 + session[:notice] = _('Failed to create role')
  20 + render :action => 'new'
  21 + end
  22 + end
  23 +
  24 + def show
  25 + @role = environment.roles.find(params[:id])
  26 + end
  27 +
  28 + def edit
  29 + @role = environment.roles.find(params[:id])
  30 + end
  31 +
  32 + def assign_role_by_members
  33 + return redirect_to "/" if params[:q].nil? or !request.xhr?
  34 + arg = params[:q].downcase
  35 + result = find_by_contents(:people, environment, profile.members, params[:q])[:results]
  36 + render :text => prepare_to_token_input(result).to_json
  37 + end
  38 +
  39 + def destroy
  40 + @role = environment.roles.find(params[:id])
  41 + @members = profile.members_by_role(@role)
  42 + @roles_list = all_roles(environment, profile)
  43 + @roles_list.delete(@role)
  44 + end
  45 +
  46 + def remove
  47 + @role = environment.roles.find(params[:id])
  48 + @members = profile.members_by_role(@role)
  49 + member_roles = params[:roles] ? environment.roles.find(params[:roles].select{|r|!r.to_i.zero?}) : []
  50 + append_roles(@members, member_roles, profile)
  51 + if @role.destroy
  52 + session[:notice] = _('Role successfuly removed!')
  53 + else
  54 + session[:notice] = _('Failed to remove role!')
  55 + end
  56 + redirect_to :action => 'index'
  57 + end
  58 +
  59 + def update
  60 + @role = environment.roles.find(params[:id])
  61 + if @role.update_attributes(params[:role])
  62 + redirect_to :action => 'show', :id => @role
  63 + else
  64 + session[:notice] = _('Failed to edit role')
  65 + render :action => 'edit'
  66 + end
  67 + end
  68 +
  69 + def assign
  70 + @role = environment.roles.find(params[:id])
  71 + @roles_list = all_roles(environment, profile)
  72 + @roles_list.delete(@role)
  73 + end
  74 +
  75 + def define
  76 + @role = environment.roles.find(params[:id])
  77 + selected_role = params[:selected_role] ? environment.roles.find(params[:selected_role].to_i) : nil
  78 + if params[:assign_role_by].eql? "members"
  79 + members_list = params[:person_id].split(',').collect {|id| environment.profiles.find(id.to_i)}
  80 + members_list.collect{|person| person.add_role(@role, profile)}
  81 + elsif params[:assign_role_by].eql? "roles"
  82 + members = profile.members_by_role(selected_role)
  83 + replace_role(members, selected_role, @role, profile)
  84 + else
  85 + session[:notice] = _("Error")
  86 + end
  87 + redirect_to :action => 'index'
  88 + end
  89 +
  90 + protected
  91 +
  92 + def append_roles(members, roles, profile)
  93 + members.each do |person|
  94 + all_roles = person.find_roles(profile).map(&:role) + roles
  95 + person.define_roles(all_roles, profile)
  96 + end
  97 + end
  98 +
  99 + def all_roles(environment, profile)
  100 + Profile::Roles.organization_member_roles(environment.id) + profile.custom_roles
  101 + end
  102 +
  103 + def replace_roles(members, roles, profile)
  104 + members.each do |person|
  105 + person.define_roles(roles, profile)
  106 + end
  107 + end
  108 +
  109 + def replace_role(members, role, new_role, profile)
  110 + members.each do |person|
  111 + person.remove_role(role, profile)
  112 + person.add_role(new_role, profile)
  113 + end
  114 + end
  115 +
  116 +end
... ...
app/controllers/my_profile/tasks_controller.rb
1 1 class TasksController < MyProfileController
2 2  
3   - protect 'perform_task', :profile
4   -
  3 + protect [:perform_task, :view_tasks], :profile, :only => [:index, :save_tags, :search_tags]
  4 + protect :perform_task, :profile, :only => [:processed, :change_responsible, :close, :new, :list_requested, :ticket_details, :search_tags]
  5 +
5 6 def index
6   - @filter = params[:filter_type].blank? ? nil : params[:filter_type]
  7 + @rejection_email_templates = profile.email_templates.find_all_by_template_type(:task_rejection)
  8 + @acceptance_email_templates = profile.email_templates.find_all_by_template_type(:task_acceptance)
  9 +
  10 + @filter_type = params[:filter_type].presence
  11 + @filter_text = params[:filter_text].presence
  12 + @filter_responsible = params[:filter_responsible]
  13 + @filter_tags = params[:filter_tags]
  14 +
7 15 @task_types = Task.pending_types_for(profile)
8   - @tasks = Task.to(profile).without_spam.pending.of(@filter).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page])
  16 + @task_tags = [OpenStruct.new(:name => _('All'), :id => nil) ] + Task.all_tags
  17 +
  18 + @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc')
  19 + @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present?
  20 + @tasks = @tasks.tagged_with(@filter_tags, any: true) if @filter_tags.present?
  21 + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
  22 +
9 23 @failed = params ? params[:failed] : {}
  24 +
  25 + @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task') && !r.has_permission?('view_tasks')}) if profile.organization?
  26 +
  27 + @view_only = !current_person.has_permission?(:perform_task, profile)
10 28 end
11 29  
12 30 def processed
13   - @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at)
  31 + @tasks = Task.to(profile).without_spam.closed.order('tasks.created_at DESC')
  32 + @filter = params[:filter] || {}
  33 + @tasks = filter_tasks(@filter, @tasks)
  34 + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page])
  35 + @task_types = Task.closed_types_for(profile)
  36 + end
  37 +
  38 + def change_responsible
  39 + task = profile.tasks.find(params[:task_id])
  40 +
  41 + if task.responsible.present? && task.responsible.id != params[:old_responsible_id].to_i
  42 + return render :json => {:notice => _('Task already assigned!'), :success => false, :current_responsible => task.responsible.id}
  43 + end
  44 +
  45 + responsible = profile.members.find(params[:responsible_id]) if params[:responsible_id].present?
  46 + task.responsible = responsible
  47 + task.save!
  48 + render :json => {:notice => _('Task responsible successfully updated!'), :success => true, :new_responsible => {:id => responsible.present? ? responsible.id : nil}}
14 49 end
15 50  
16 51 VALID_DECISIONS = [ 'finish', 'cancel', 'skip' ]
17 52  
18 53 def close
19 54 failed = {}
  55 + save = false
20 56  
21 57 if params[:tasks]
22 58 params[:tasks].each do |id, value|
23 59 decision = value[:decision]
24   - if request.post? && VALID_DECISIONS.include?(decision) && id && decision != 'skip'
  60 +
  61 + if value[:task].is_a?(Hash) && value[:task][:tag_list]
  62 +
25 63 task = profile.find_in_all_tasks(id)
26   - begin
27   - task.update_attributes(value[:task])
28   - task.send(decision)
29   - rescue Exception => ex
30   - message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
31   - failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
  64 + task.tag_list = value[:task][:tag_list]
  65 + value[:task].delete('tag_list')
  66 +
  67 + save = true
  68 + end
  69 +
  70 + if request.post?
  71 + if VALID_DECISIONS.include?(decision) && id && decision != 'skip'
  72 + task ||= profile.find_in_all_tasks(id)
  73 + begin
  74 + task.update_attributes(value[:task])
  75 + task.send(decision, current_person)
  76 + rescue Exception => ex
  77 + message = "#{task.title} (#{task.requestor ? task.requestor.name : task.author_name})"
  78 + failed[ex.message] ? failed[ex.message] << message : failed[ex.message] = [message]
  79 + end
  80 + elsif save
  81 + task.save!
32 82 end
33 83 end
34 84 end
35 85 end
36 86  
37 87 url = { :action => 'index' }
  88 +
38 89 if failed.blank?
39 90 session[:notice] = _("All decisions were applied successfully.")
40 91 else
... ... @@ -65,4 +116,79 @@ class TasksController &lt; MyProfileController
65 116 @ticket = Ticket.find(:first, :conditions => ['(requestor_id = ? or target_id = ?) and id = ?', profile.id, profile.id, params[:id]])
66 117 end
67 118  
  119 + def search_tasks
  120 + filter_type = params[:filter_type].presence
  121 + filter_text = params[:filter_text].presence
  122 + result = Task.pending_all(profile,filter_type, filter_text)
  123 +
  124 + render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} }
  125 + end
  126 +
  127 + def save_tags
  128 + if request.post? && params[:tag_list]
  129 + result = {
  130 + success: false,
  131 + message: _('Error to save tags. Please, contact the system admin')
  132 + }
  133 +
  134 + ActsAsTaggableOn.remove_unused_tags = true
  135 +
  136 + task = profile.tasks.find_by_id(params[:task_id])
  137 +
  138 + if task && task.update_attributes(:tag_list => params[:tag_list])
  139 + result[:success] = true
  140 + end
  141 + end
  142 +
  143 + render json: result
  144 + end
  145 +
  146 + # FIXME make this test
  147 + # Should not search for article tasks
  148 + # Should not search for other profile tags
  149 + # Should search only task tags
  150 + # Should check the permissions
  151 +
  152 + def search_tags
  153 +
  154 + arg = params[:term].downcase
  155 +
  156 + result = ActsAsTaggableOn::Tag.find(:all, :conditions => ['LOWER(name) LIKE ?', "%#{arg}%"])
  157 +
  158 + render :text => prepare_to_token_input_by_label(result).to_json, :content_type => 'application/json'
  159 + end
  160 +
  161 + protected
  162 +
  163 + def filter_by_closed_date(filter, tasks)
  164 + filter[:closed_from] = Date.parse(filter[:closed_from]) unless filter[:closed_from].blank?
  165 + filter[:closed_until] = Date.parse(filter[:closed_until]) unless filter[:closed_until].blank?
  166 +
  167 + tasks = tasks.where('tasks.end_date >= ?', filter[:closed_from].beginning_of_day) unless filter[:closed_from].blank?
  168 + tasks = tasks.where('tasks.end_date <= ?', filter[:closed_until].end_of_day) unless filter[:closed_until].blank?
  169 + tasks
  170 + end
  171 +
  172 + def filter_by_creation_date(filter, tasks)
  173 + filter[:created_from] = Date.parse(filter[:created_from]) unless filter[:created_from].blank?
  174 + filter[:created_until] = Date.parse(filter[:created_until]) unless filter[:created_until].blank?
  175 +
  176 + tasks = tasks.where('tasks.created_at >= ?', filter[:created_from].beginning_of_day) unless filter[:created_from].blank?
  177 + tasks = tasks.where('tasks.created_at <= ?', filter[:created_until].end_of_day) unless filter[:created_until].blank?
  178 + tasks
  179 + end
  180 +
  181 + def filter_tasks(filter, tasks)
  182 + tasks = tasks.includes(:requestor, :closed_by)
  183 + tasks = tasks.of(filter[:type].presence)
  184 + tasks = tasks.where(:status => filter[:status]) unless filter[:status].blank?
  185 + tasks = filter_by_creation_date(filter, tasks)
  186 + tasks = filter_by_closed_date(filter, tasks)
  187 +
  188 + tasks = tasks.like('profiles.name', filter[:requestor]) unless filter[:requestor].blank?
  189 + tasks = tasks.like('closed_bies_tasks.name', filter[:closed_by]) unless filter[:closed_by].blank?
  190 + tasks = tasks.like('tasks.data', filter[:text]) unless filter[:text].blank?
  191 + tasks
  192 + end
  193 +
68 194 end
... ...
app/controllers/public/account_controller.rb
... ... @@ -16,7 +16,7 @@ class AccountController &lt; ApplicationController
16 16 def activate
17 17 @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code]
18 18 if @user
19   - unless @user.environment.enabled?('admin_must_approve_new_users')
  19 + unless @user.environment.enabled?('admin_must_approve_new_users')
20 20 if @user.activate
21 21 @message = _("Your account has been activated, now you can log in!")
22 22 check_redirection
... ... @@ -30,7 +30,7 @@ class AccountController &lt; ApplicationController
30 30 @user.activation_code = nil
31 31 @user.save!
32 32 redirect_to :controller => :home
33   - end
  33 + end
34 34 end
35 35 else
36 36 session[:notice] = _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
... ... @@ -50,10 +50,12 @@ class AccountController &lt; ApplicationController
50 50  
51 51 if logged_in?
52 52 check_join_in_community(self.current_user)
  53 +
53 54 if params[:remember_me] == "1"
54 55 self.current_user.remember_me
55   - cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
  56 + cookies[:auth_token] = {value: self.current_user.remember_token, expires: self.current_user.remember_token_expires_at}
56 57 end
  58 +
57 59 if redirect?
58 60 go_to_initial_page
59 61 session[:notice] = _("Logged in successfully")
... ... @@ -77,6 +79,13 @@ class AccountController &lt; ApplicationController
77 79 render :text => { :ok=>true, :key=>key }.to_json
78 80 end
79 81  
  82 + def custom_fields_for_template
  83 + custom_fields ||= environment.people.templates.find(params[:template_id]).custom_fields.map { |k,v|
  84 + { :name => k, :title => v[:title] } if v['signup']
  85 + }.compact
  86 + render :text => {:ok => true, :custom_fields => custom_fields}.to_json
  87 + end
  88 +
80 89 # action to register an user to the application
81 90 def signup
82 91 if @plugins.dispatch(:allow_user_registration).include?(false)
... ... @@ -92,6 +101,7 @@ class AccountController &lt; ApplicationController
92 101 @invitation_code = params[:invitation_code]
93 102 begin
94 103 @user = User.new(params[:user])
  104 + @user.session = session
95 105 @user.terms_of_use = environment.terms_of_use
96 106 @user.environment = environment
97 107 @terms_of_use = environment.terms_of_use
... ... @@ -358,11 +368,11 @@ class AccountController &lt; ApplicationController
358 368 end
359 369  
360 370 def get_signup_start_time
361   - Rails.cache.read params[:signup_time_key]
  371 + Rails.cache.read params[:signup_time_key] if params[:signup_time_key].present?
362 372 end
363 373  
364 374 def clear_signup_start_time
365   - Rails.cache.delete params[:signup_time_key] if params[:signup_time_key]
  375 + Rails.cache.delete params[:signup_time_key] if params[:signup_time_key].present?
366 376 end
367 377  
368 378 def may_be_a_bot
... ... @@ -435,7 +445,7 @@ class AccountController &lt; ApplicationController
435 445 end
436 446  
437 447 def go_to_signup_initial_page
438   - check_redirection_options(user, user.environment.redirection_after_signup, user.url)
  448 + check_redirection_options user, user.environment.redirection_after_signup, user.url, signup: true
439 449 end
440 450  
441 451 def redirect_if_logged_in
... ... @@ -455,8 +465,11 @@ class AccountController &lt; ApplicationController
455 465  
456 466 protected
457 467  
458   - def check_redirection_options(user, condition, default)
459   - case condition
  468 + def check_redirection_options user, condition, default, options={}
  469 + if options[:signup] and target = session.delete(:after_signup_redirect_to)
  470 + redirect_to target
  471 + else
  472 + case condition
460 473 when 'keep_on_same_page'
461 474 redirect_back_or_default(user.admin_url)
462 475 when 'site_homepage'
... ... @@ -469,8 +482,11 @@ class AccountController &lt; ApplicationController
469 482 redirect_to user.admin_url
470 483 when 'welcome_page'
471 484 redirect_to :controller => :home, :action => :welcome, :template_id => (user.template && user.template.id)
472   - else
473   - redirect_back_or_default(default)
  485 + when 'custom_url'
  486 + if (url = user.custom_url_redirection).present? then redirect_to url else redirect_back_or_default default end
  487 + else
  488 + redirect_back_or_default(default)
  489 + end
474 490 end
475 491 end
476 492  
... ...
app/controllers/public/api_controller.rb 0 → 100644
... ... @@ -0,0 +1,19 @@
  1 +class ApiController < PublicController
  2 +
  3 + no_design_blocks
  4 +
  5 + helper_method :endpoints
  6 +
  7 + def index
  8 + end
  9 +
  10 + def playground
  11 + end
  12 +
  13 + private
  14 +
  15 + def endpoints
  16 + Noosfero::API::API.endpoints(environment)
  17 + end
  18 +
  19 +end
... ...
app/controllers/public/chat_controller.rb
... ... @@ -2,6 +2,7 @@ class ChatController &lt; PublicController
2 2  
3 3 before_filter :login_required
4 4 before_filter :check_environment_feature
  5 + before_filter :can_send_message, :only => :register_message
5 6  
6 7 def start_session
7 8 login = user.jid
... ... @@ -54,6 +55,16 @@ class ChatController &lt; PublicController
54 55 end
55 56 end
56 57  
  58 + def avatars
  59 + profiles = environment.profiles.where(:identifier => params[:profiles])
  60 + avatar_map = profiles.inject({}) do |result, profile|
  61 + result[profile.identifier] = profile_icon(profile, :minor)
  62 + result
  63 + end
  64 +
  65 + render_json avatar_map
  66 + end
  67 +
57 68 def update_presence_status
58 69 if request.xhr?
59 70 current_user.update_attributes({:chat_status_at => DateTime.now}.merge(params[:status] || {}))
... ... @@ -62,11 +73,17 @@ class ChatController &lt; PublicController
62 73 end
63 74  
64 75 def save_message
65   - to = environment.profiles.find_by_identifier(params[:to])
66   - body = params[:body]
67   -
68   - ChatMessage.create!(:to => to, :from => user, :body => body)
69   - render :text => 'ok'
  76 + if request.post?
  77 + to = environment.profiles.where(:identifier => params[:to]).first
  78 + body = params[:body]
  79 +
  80 + begin
  81 + ChatMessage.create!(:to => to, :from => user, :body => body)
  82 + return render_json({:status => 0})
  83 + rescue Exception => exception
  84 + return render_json({:status => 3, :message => exception.to_s, :backtrace => exception.backtrace})
  85 + end
  86 + end
70 87 end
71 88  
72 89 def recent_messages
... ... @@ -90,8 +107,9 @@ class ChatController &lt; PublicController
90 107 end
91 108  
92 109 def recent_conversations
93   - conversations_order = ActiveRecord::Base.connection.execute("select profiles.identifier from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc").entries.map {|e| e['identifier']}
94   - render :json => {:order => conversations_order.reverse, :domain => environment.default_hostname.gsub('.','-')}.to_json
  110 + profiles = Profile.find_by_sql("select profiles.* from profiles inner join (select distinct r.id as id, MAX(r.created_at) as created_at from (select from_id, to_id, created_at, (case when from_id=#{user.id} then to_id else from_id end) as id from chat_messages where from_id=#{user.id} or to_id=#{user.id}) as r group by id order by created_at desc, id) as t on profiles.id=t.id order by t.created_at desc")
  111 + jids = profiles.map(&:jid).reverse
  112 + render :json => jids.to_json
95 113 end
96 114  
97 115 #TODO Ideally this is done through roster table on ejabberd.
... ... @@ -108,4 +126,14 @@ class ChatController &lt; PublicController
108 126 end
109 127 end
110 128  
  129 + def can_send_message
  130 + return render_json({:status => 1, :message => 'Missing parameters!'}) if params[:from].nil? || params[:to].nil? || params[:message].nil?
  131 + return render_json({:status => 2, :message => 'You can not send message as another user!'}) if params[:from] != user.jid
  132 + # TODO Maybe register the jid in a table someday to avoid this below
  133 + return render_json({:status => 3, :messsage => 'You can not send messages to strangers!'}) if user.friends.where(:identifier => params[:to].split('@').first).blank?
  134 + end
  135 +
  136 + def render_json(result)
  137 + render :text => result.to_json
  138 + end
111 139 end
... ...
app/controllers/public/contact_controller.rb
... ... @@ -6,8 +6,9 @@ class ContactController &lt; PublicController
6 6 def new
7 7 @contact = build_contact
8 8 if request.post? && params[:confirm] == 'true'
9   - @contact.city = (!params[:city].blank? && City.exists?(params[:city])) ? City.find(params[:city]).name : nil
10   - @contact.state = (!params[:state].blank? && State.exists?(params[:state])) ? State.find(params[:state]).name : nil
  9 + # updated to use hash as argument to exists? to avoid sql injection vunerabillity (http://brakemanscanner.org/docs/warning_types/sql_injection/)
  10 + @contact.city = (!params[:city].blank? && City.exists?(:id => params[:city])) ? City.find(params[:city]).name : nil
  11 + @contact.state = (!params[:state].blank? && State.exists?(:id => params[:state])) ? State.find(params[:state]).name : nil
11 12 if @contact.deliver
12 13 session[:notice] = _('Contact successfully sent')
13 14 redirect_to :action => 'new'
... ...
app/controllers/public/content_viewer_controller.rb
... ... @@ -15,9 +15,10 @@ class ContentViewerController &lt; ApplicationController
15 15 path = get_path(params[:page], params[:format])
16 16  
17 17 @version = params[:version].to_i
  18 + @npage = params[:npage] || '1'
18 19  
19 20 if path.blank?
20   - @page = profile.home_page
  21 + @page = profile.home_page
21 22 return if redirected_to_profile_index
22 23 else
23 24 @page = profile.articles.find_by_path(path)
... ... @@ -74,7 +75,7 @@ class ContentViewerController &lt; ApplicationController
74 75 render :action => 'slideshow', :layout => 'slideshow'
75 76 return
76 77 end
77   - render :view_page, :formats => [:html]
  78 + render @page.view_page, :formats => [:html]
78 79 end
79 80  
80 81 def versions_diff
... ... @@ -125,21 +126,23 @@ class ContentViewerController &lt; ApplicationController
125 126 helper_method :pass_without_comment_captcha?
126 127  
127 128 def allow_access_to_page(path)
128   - allowed = true
129 129 if @page.nil? # page not found, give error
130 130 render_not_found(path)
131   - allowed = false
132   - elsif !@page.display_to?(user)
133   - if !profile.public?
  131 + return false
  132 + end
  133 +
  134 + unless @page.display_to?(user)
  135 + if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank?
  136 + render_access_denied
  137 + else #!profile.public?
134 138 private_profile_partial_parameters
135 139 render :template => 'profile/_private_profile', :status => 403, :formats => [:html]
136   - allowed = false
137   - else #if !profile.visible?
138   - render_access_denied
139   - allowed = false
140 140 end
  141 +
  142 + return false
141 143 end
142   - allowed
  144 +
  145 + return true
143 146 end
144 147  
145 148 def user_is_a_bot?
... ... @@ -184,7 +187,7 @@ class ContentViewerController &lt; ApplicationController
184 187 if @page.forum? && @page.has_terms_of_use && terms_accepted == "true"
185 188 @page.add_agreed_user(user)
186 189 end
187   - end
  190 + end
188 191  
189 192 def is_a_forum_topic? (page)
190 193 return (!@page.parent.nil? && @page.parent.forum?)
... ...
app/controllers/public/home_controller.rb
... ... @@ -12,6 +12,7 @@ class HomeController &lt; PublicController
12 12 @area_news = environment.portal_folders
13 13 end
14 14 end
  15 + render :file => 'home/index', :formats => [:html]
15 16 end
16 17  
17 18 def terms
... ...
app/controllers/public/invite_controller.rb
... ... @@ -62,20 +62,36 @@ class InviteController &lt; PublicController
62 62 redirect_to :action => 'invite_friends'
63 63 end
64 64  
  65 + #Invite or add member without create a task
  66 + #if logged user is admin of environment
65 67 def invite_registered_friend
  68 +
  69 + if !params['q'].present? || !request.post?
  70 +
  71 + redirect_to :action => 'invite_friends'
  72 + session[:notice] = _('Please enter a valid profile.')
  73 +
  74 + return
  75 + end
  76 +
66 77 contacts_to_invite = params['q'].split(',')
67   - if !contacts_to_invite.empty? && request.post?
  78 +
  79 + if user.is_admin? && profile.community?
  80 +
  81 + Delayed::Job.enqueue AddMembersJob.new contacts_to_invite, profile.id, locale
  82 +
  83 + session[:notice] = _('This friends was added!')
  84 + else
68 85 Delayed::Job.enqueue InvitationJob.new(user.id, contacts_to_invite, '', profile.id, nil, locale)
69 86 session[:notice] = _('Your invitations are being sent.')
70   - if profile.person?
71   - redirect_to :controller => 'profile', :action => 'friends'
72   - else
73   - redirect_to :controller => 'profile', :action => 'members'
74   - end
  87 + end
  88 +
  89 + if profile.person?
  90 + redirect_to :controller => 'profile', :action => 'friends'
75 91 else
76   - redirect_to :action => 'invite_friends'
77   - session[:notice] = _('Please enter a valid profile.')
  92 + redirect_to :controller => 'profile', :action => 'members'
78 93 end
  94 +
79 95 end
80 96  
81 97 def search
... ...
app/controllers/public/profile_controller.rb
... ... @@ -6,6 +6,7 @@ class ProfileController &lt; PublicController
6 6 before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail]
7 7  
8 8 helper TagsHelper
  9 + helper ActionTrackerHelper
9 10  
10 11 protect 'send_mail_to_members', :profile, :only => [:send_mail]
11 12  
... ... @@ -201,7 +202,10 @@ class ProfileController &lt; PublicController
201 202  
202 203 def more_comments
203 204 profile_filter = @profile.person? ? {:user_id => @profile} : {:target_id => @profile}
204   - activity = ActionTracker::Record.find(:first, :conditions => {:id => params[:activity]}.merge(profile_filter))
  205 + activity = ActionTracker::Record.where(:id => params[:activity])
  206 + activity = activity.where(profile_filter) if !logged_in? || !current_person.follows?(@profile)
  207 + activity = activity.first
  208 +
205 209 comments_count = activity.comments.count
206 210 comment_page = (params[:comment_page] || 1).to_i
207 211 comments_per_page = 5
... ... @@ -353,6 +357,7 @@ class ProfileController &lt; PublicController
353 357  
354 358 def send_mail
355 359 @mailing = profile.mailings.build(params[:mailing])
  360 + @email_templates = profile.email_templates.find_all_by_template_type(:organization_members)
356 361 if request.post?
357 362 @mailing.locale = locale
358 363 @mailing.person = user
... ...
app/controllers/public/search_controller.rb
... ... @@ -95,10 +95,10 @@ class SearchController &lt; PublicController
95 95  
96 96 def events
97 97 if params[:year].blank? && params[:year].blank? && params[:day].blank?
98   - @date = Date.today
  98 + @date = DateTime.now
99 99 else
100   - year = (params[:year] ? params[:year].to_i : Date.today.year)
101   - month = (params[:month] ? params[:month].to_i : Date.today.month)
  100 + year = (params[:year] ? params[:year].to_i : DateTime.now.year)
  101 + month = (params[:month] ? params[:month].to_i : DateTime.now.month)
102 102 day = (params[:day] ? params[:day].to_i : 1)
103 103 @date = build_date(year, month, day)
104 104 end
... ... @@ -109,9 +109,7 @@ class SearchController &lt; PublicController
109 109 @events = @category ?
110 110 environment.events.by_day(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
111 111 environment.events.by_day(@date).paginate(:per_page => per_page, :page => params[:page])
112   - end
113   -
114   - if params[:year] || params[:month]
  112 + elsif params[:year] || params[:month]
115 113 @events = @category ?
116 114 environment.events.by_month(@date).in_category(Category.find(@category_id)).paginate(:per_page => per_page, :page => params[:page]) :
117 115 environment.events.by_month(@date).paginate(:per_page => per_page, :page => params[:page])
... ...
app/controllers/public_controller.rb
... ... @@ -3,7 +3,7 @@ class PublicController &lt; ApplicationController
3 3  
4 4 def allow_access_to_page
5 5 unless profile.display_info_to?(user)
6   - if profile.visible?
  6 + if profile.visible? && !profile.secret
7 7 private_profile
8 8 else
9 9 invisible_profile
... ...
app/helpers/action_tracker_helper.rb 0 → 100644
... ... @@ -0,0 +1,94 @@
  1 +module ActionTrackerHelper
  2 +
  3 + def create_article_description ta
  4 + _('published an article: %{title}') % { title: link_to(truncate(ta.get_name), ta.get_url) }
  5 + end
  6 +
  7 + def new_friendship_description ta
  8 + n_('has made 1 new friend:<br />%{name}', 'has made %{num} new friends:<br />%{name}', ta.get_friend_name.size) % {
  9 + num: ta.get_friend_name.size,
  10 + name: ta.collect_group_with_index(:friend_name) do |n,i|
  11 + link_to image_tag(ta.get_friend_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")),
  12 + ta.get_friend_url[i], title: n
  13 + end.join
  14 + }
  15 + end
  16 +
  17 + def join_community_description ta
  18 + n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size) % {
  19 + num: ta.get_resource_name.size,
  20 + name: ta.collect_group_with_index(:resource_name) do |n,i|
  21 + link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")),
  22 + ta.get_resource_url[i], title: n
  23 + end.join
  24 + }
  25 + end
  26 +
  27 + def add_member_in_community_description ta
  28 + _('has joined the community.')
  29 + end
  30 +
  31 + def upload_image_description ta
  32 + total = ta.get_view_url.size
  33 + (n_('uploaded 1 image', 'uploaded %d images', total) % total) +
  34 + tag(:br) +
  35 + ta.collect_group_with_index(:thumbnail_path) do |t,i|
  36 + if total == 1
  37 + link_to image_tag(t), ta.get_view_url[i], class: 'upimg'
  38 + else
  39 + pos = total-i;
  40 + morethen2 = pos>2 ? 'morethen2' : ''
  41 + morethen5 = pos>5 ? 'morethen5' : ''
  42 + t = t.gsub(/(.*)(display)(.*)/, '\\1thumb\\3')
  43 +
  44 + link_to '&nbsp;'.html_safe, ta.get_view_url[i],
  45 + style: "background-image:url(#{t})",
  46 + class: "upimg pos#{pos} #{morethen2} #{morethen5}"
  47 + end
  48 + end.reverse.join +
  49 + if total <= 5 then ''.html_safe else content_tag :span, '&hellip;'.html_safe,
  50 + class: 'more', onclick: "this.parentNode.className+=' show-all'" end +
  51 + tag(:br, style: 'clear: both')
  52 + end
  53 +
  54 + def reply_scrap_description ta
  55 + _('sent a message to %{receiver}: <br /> "%{message}"') % {
  56 + receiver: link_to(ta.get_receiver_name, ta.get_receiver_url),
  57 + message: auto_link_urls(ta.get_content)
  58 + }
  59 + end
  60 +
  61 + alias :leave_scrap_description :reply_scrap_description
  62 + alias :reply_scrap_on_self_description :reply_scrap_description
  63 +
  64 + def leave_scrap_to_self_description ta
  65 + _('wrote: <br /> "%{text}"') % {
  66 + text: auto_link_urls(ta.get_content)
  67 + }
  68 + end
  69 +
  70 + def create_product_description
  71 + _('created the product %{title}') % {
  72 + title: link_to(truncate(ta.get_name), ta.get_url),
  73 + }
  74 + end
  75 +
  76 + def update_product_description
  77 + _('updated the product %{title}') % {
  78 + title: link_to(truncate(ta.get_name), ta.get_url),
  79 + }
  80 + end
  81 +
  82 + def remove_product_description
  83 + _('removed the product %{title}') % {
  84 + title: truncate(ta.get_name),
  85 + }
  86 + end
  87 +
  88 + def favorite_enterprise_description ta
  89 + _('favorited enterprise %{title}') % {
  90 + title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url),
  91 + }
  92 + end
  93 +
  94 +end
... ...
app/helpers/application_helper.rb
... ... @@ -44,6 +44,8 @@ module ApplicationHelper
44 44  
45 45 include PluginsHelper
46 46  
  47 + include TaskHelper
  48 +
47 49 def locale
48 50 (@page && !@page.language.blank?) ? @page.language : FastGettext.locale
49 51 end
... ... @@ -707,6 +709,24 @@ module ApplicationHelper
707 709 javascript_include_tag script if script
708 710 end
709 711  
  712 + def template_path
  713 + if profile.nil?
  714 + "/designs/templates/#{environment.layout_template}"
  715 + else
  716 + "/designs/templates/#{profile.layout_template}"
  717 + end
  718 + end
  719 +
  720 + def template_javascript_src
  721 + script = File.join template_path, '/javascripts/template.js'
  722 + script if File.exists? File.join(Rails.root, 'public', script)
  723 + end
  724 +
  725 + def templete_javascript_ng
  726 + script = template_javascript_src
  727 + javascript_include_tag script if script
  728 + end
  729 +
710 730 def file_field_or_thumbnail(label, image, i)
711 731 display_form_field label, (
712 732 render :partial => (image && image.valid? ? 'shared/show_thumbnail' : 'shared/change_image'),
... ... @@ -853,7 +873,7 @@ module ApplicationHelper
853 873 field_html += capture(&block)
854 874 end
855 875  
856   - if controller.action_name == 'signup' || controller.action_name == 'new_community' || (controller.controller_name == "enterprise_registration" && controller.action_name == 'index')
  876 + if controller.action_name == 'signup' || controller.action_name == 'new_community' || (controller.controller_name == "enterprise_registration" && controller.action_name == 'index') || (controller.controller_name == 'home' && controller.action_name == 'index' && user.nil?)
857 877 if profile.signup_fields.include?(name)
858 878 result = field_html
859 879 end
... ... @@ -913,6 +933,19 @@ module ApplicationHelper
913 933 article_helper.cms_label_for_edit
914 934 end
915 935  
  936 + def label_for_clone_article(article)
  937 + translated_types = {
  938 + Folder => _('Folder'),
  939 + Blog => _('Blog'),
  940 + Event => _('Event'),
  941 + Forum => _('Forum')
  942 + }
  943 +
  944 + translated_type = translated_types[article.class] || _('Article')
  945 +
  946 + _('Clone %s') % translated_type
  947 + end
  948 +
916 949 def add_rss_feed_to_head(title, url)
917 950 content_for :feeds do
918 951 tag(:link, :rel => 'alternate', :type => 'application/rss+xml', :title => title, :href => url_for(url))
... ... @@ -1151,10 +1184,10 @@ module ApplicationHelper
1151 1184 pending_tasks_count = ''
1152 1185 count = user ? Task.to(user).pending.count : -1
1153 1186 if count > 0
1154   - pending_tasks_count = link_to(count.to_s, user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
  1187 + pending_tasks_count = link_to("<i class=\"icon-menu-tasks\"></i><span class=\"task-count\">#{count}</span>", user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks"))
1155 1188 end
1156 1189  
1157   - (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage'))) +
  1190 + (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.url, :id => "homepage-link", :title => _('Go to your homepage'))) +
1158 1191 render_environment_features(:usermenu) +
1159 1192 admin_link +
1160 1193 manage_enterprises +
... ... @@ -1173,7 +1206,8 @@ module ApplicationHelper
1173 1206 end
1174 1207  
1175 1208 def expandable_text_area(object_name, method, text_area_id, options = {})
1176   - text_area(object_name, method, { :id => text_area_id, :onkeyup => "grow_text_area('#{text_area_id}')" }.merge(options))
  1209 + options[:class] = (options[:class] || '') + ' autogrow'
  1210 + text_area(object_name, method, { :id => text_area_id }.merge(options))
1177 1211 end
1178 1212  
1179 1213 def pluralize_without_count(count, singular, plural = nil)
... ... @@ -1184,35 +1218,6 @@ module ApplicationHelper
1184 1218 list.sort.inject(Hash.new(0)){|h,i| h[i] += 1; h }.collect{ |x, n| [n, connector, x].join(" ") }.sort
1185 1219 end
1186 1220  
1187   - #FIXME Use time_ago_in_words instead of this method if you're using Rails 2.2+
1188   - def time_ago_as_sentence(from_time, include_seconds = false)
1189   - to_time = Time.now
1190   - from_time = Time.parse(from_time.to_s)
1191   - from_time = from_time.to_time if from_time.respond_to?(:to_time)
1192   - to_time = to_time.to_time if to_time.respond_to?(:to_time)
1193   - distance_in_minutes = (((to_time - from_time).abs)/60).round
1194   - distance_in_seconds = ((to_time - from_time).abs).round
1195   - case distance_in_minutes
1196   - when 0..1
1197   - return (distance_in_minutes == 0) ? _('less than a minute') : _('1 minute') unless include_seconds
1198   - case distance_in_seconds
1199   - when 0..4 then _('less than 5 seconds')
1200   - when 5..9 then _('less than 10 seconds')
1201   - when 10..19 then _('less than 20 seconds')
1202   - when 20..39 then _('half a minute')
1203   - when 40..59 then _('less than a minute')
1204   - else _('1 minute')
1205   - end
1206   -
1207   - when 2..44 then _('%{distance} minutes ago') % { :distance => distance_in_minutes }
1208   - when 45..89 then _('about 1 hour ago')
1209   - when 90..1439 then _('about %{distance} hours ago') % { :distance => (distance_in_minutes.to_f / 60.0).round }
1210   - when 1440..2879 then _('1 day ago')
1211   - when 2880..10079 then _('%{distance} days ago') % { :distance => (distance_in_minutes / 1440).round }
1212   - else show_time(from_time)
1213   - end
1214   - end
1215   -
1216 1221 def comment_balloon(options = {}, &block)
1217 1222 wrapper = content_tag(:div, capture(&block), :class => 'comment-balloon-content')
1218 1223 (1..8).to_a.reverse.each { |i| wrapper = content_tag(:div, wrapper, :class => "comment-wrapper-#{i}") }
... ... @@ -1231,7 +1236,7 @@ module ApplicationHelper
1231 1236  
1232 1237 def task_information(task)
1233 1238 values = {}
1234   - values.merge!({:requestor => link_to(task.requestor.name, task.requestor.public_profile_url)}) if task.requestor
  1239 + values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor
1235 1240 values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject
1236 1241 values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject
1237 1242 values.merge!(task.information[:variables]) if task.information[:variables]
... ... @@ -1336,18 +1341,29 @@ module ApplicationHelper
1336 1341 def template_options(kind, field_name)
1337 1342 templates = environment.send(kind).templates
1338 1343 return '' if templates.count == 0
1339   - return hidden_field_tag("#{field_name}[template_id]", templates.first.id) if templates.count == 1
1340   -
1341   - radios = templates.map do |template|
1342   - content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template)))
1343   - end.join("\n")
1344   -
1345   - content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') +
1346   - content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') +
1347   - content_tag('ul', radios, :style => 'list-style: none; padding-left: 20px; margin-top: 0.5em;'),
1348   - :id => 'template-options',
1349   - :style => 'margin-top: 1em'
1350   - )
  1344 + if templates.count == 1
  1345 + if templates.first.custom_fields == {}
  1346 + return hidden_field_tag("#{field_name}[template_id]", templates.first.id)
  1347 + else
  1348 + custom_fields = ""
  1349 + templates.first.custom_fields.each { |field, value|
  1350 + custom_fields += content_tag('div', content_tag('label', value[:title].capitalize, :class => 'formlabel') +
  1351 + content_tag('div', text_field_tag( "profile_data[custom_fields][#{field}][title]", ''), :class => 'formfield type-text'), :class => "formfieldline" ) if value[:signup] == 'on'
  1352 + }
  1353 + content_tag('div', custom_fields)
  1354 + end
  1355 + else
  1356 + radios = templates.map do |template|
  1357 + content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template), :onchange => 'show_fields_for_template(this);'))
  1358 + end.join("\n")
  1359 +
  1360 + content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') +
  1361 + content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') +
  1362 + content_tag('ul', radios, :style => 'list-style: none; padding-left: 20px; margin-top: 0.5em;'),
  1363 + :id => 'template-options',
  1364 + :style => 'margin-top: 1em'
  1365 + )
  1366 + end
1351 1367 end
1352 1368  
1353 1369 def expirable_content_reference(content, action, text, url, options = {})
... ... @@ -1480,4 +1496,26 @@ module ApplicationHelper
1480 1496 text_field(object_name, method, options.merge(:class => 'colorpicker_field'))
1481 1497 end
1482 1498  
  1499 + def fullscreen_buttons(itemId)
  1500 + content="
  1501 + <script>fullscreenPageLoad('#{itemId}')</script>
  1502 + "
  1503 + content+=content_tag('a', content_tag('span',_("Full screen")),
  1504 + { :id=>"fullscreen-btn",
  1505 + :onClick=>"toggle_fullwidth('#{itemId}')",
  1506 + :class=>"button with-text icon-fullscreen",
  1507 + :href=>"#",
  1508 + :title=>_("Go to full screen mode")
  1509 + })
  1510 +
  1511 + content+=content_tag('a', content_tag('span',_("Exit full screen")),
  1512 + { :style=>"display: none;",
  1513 + :id=>"exit-fullscreen-btn",
  1514 + :onClick=>"toggle_fullwidth('#{itemId}')",
  1515 + :class=>"button with-text icon-fullscreen",
  1516 + :href=>"#",
  1517 + :title=>_("Exit full screen mode")
  1518 + })
  1519 + end
  1520 +
1483 1521 end
... ...
app/helpers/article_helper.rb
... ... @@ -12,6 +12,7 @@ module ArticleHelper
12 12 @article = article
13 13  
14 14 visibility_options(@article, tokenized_children) +
  15 + topic_creation(@article) +
15 16 content_tag('h4', _('Options')) +
16 17 content_tag('div',
17 18 (article.profile.has_members? ?
... ... @@ -55,14 +56,7 @@ module ArticleHelper
55 56 'div',
56 57 check_box(:article, :display_versions) +
57 58 content_tag('label', _('I want this article to display a link to older versions'), :for => 'article_display_versions')
58   - ) : '') +
59   -
60   - (article.forum? && article.profile.community? ?
61   - content_tag(
62   - 'div',
63   - check_box(:article, :allows_members_to_create_topics) +
64   - content_tag('label', _('Allow members to create topics'), :for => 'article_allows_members_to_create_topics')
65   - ) : '')
  59 + ) : '')
66 60 )
67 61 end
68 62  
... ... @@ -81,6 +75,22 @@ module ArticleHelper
81 75 )
82 76 end
83 77  
  78 + def topic_creation(article)
  79 + return '' unless article.forum?
  80 +
  81 + general_options = Forum::TopicCreation.general_options(article)
  82 + slider_options = {:id => 'topic-creation-slider'}
  83 + slider_options = general_options.keys.inject(slider_options) do |result, option|
  84 + result.merge!({'data-'+option => general_options[option]})
  85 + end
  86 +
  87 + content_tag('h4', _('Topic creation')) +
  88 + content_tag( 'small', _('Who will be able to create new topics on this forum?')) +
  89 + content_tag('div', '', slider_options) +
  90 + hidden_field_tag('article[topic_creation]', article.topic_creation) +
  91 + javascript_include_tag('topic-creation-config')
  92 + end
  93 +
84 94 def privacity_exceptions(article, tokenized_children)
85 95 content_tag('div',
86 96 content_tag('div',
... ...
app/helpers/blog_helper.rb
... ... @@ -22,7 +22,9 @@ module BlogHelper
22 22 :param_name => 'npage',
23 23 :previous_label => _('&laquo; Newer posts'),
24 24 :next_label => _('Older posts &raquo;'),
25   - :params => {:action=>"view_page", :page=>articles.first.parent.path.split('/'), :controller=>"content_viewer"}
  25 + :params => {:action=>"view_page",
  26 + :page=>articles.first.parent.path.split('/'),
  27 + :controller=>"content_viewer"}
26 28 }) if articles.present? && conf[:paginate]
27 29 content = []
28 30 artic_len = articles.length
... ... @@ -44,7 +46,7 @@ module BlogHelper
44 46 end
45 47  
46 48 def display_post(article, format = 'full')
47   - no_comments = (format == 'full') ? false : true
  49 + no_comments = (format == 'full' || format == 'compact' ) ? false : true
48 50 title = article_title(article, :no_comments => no_comments)
49 51 method = "display_#{format.split('+')[0]}_format"
50 52 html = send(method, FilePresenter.for(article)).html_safe
... ... @@ -55,8 +57,12 @@ module BlogHelper
55 57 else
56 58 '<div class="post-pic" style="background-image:url('+img+')"></div>'
57 59 end
58   - end.to_s +
59   - title + html
  60 + end.to_s + title + html
  61 + end
  62 +
  63 + def display_compact_format(article)
  64 + render :file => 'content_viewer/_display_compact_format',
  65 + :locals => { :article => article, :format => "compact" }
60 66 end
61 67  
62 68 def display_full_format(article)
... ...
app/helpers/box_organizer_helper.rb
1 1 module BoxOrganizerHelper
2 2  
  3 + def display_icon(block)
  4 + image_path = nil
  5 + plugin = @plugins.fetch_first_plugin(:has_block?, block)
  6 +
  7 + theme = Theme.new(environment.theme) # remove this
  8 + if File.exists?(File.join(theme.filesystem_path, 'images', block.icon_path))
  9 + image_path = File.join(theme.public_path, 'images', block.icon_path)
  10 + elsif plugin && File.exists?(File.join(Rails.root, 'public', plugin.public_path, 'images', block.icon_path))
  11 + image_path = File.join('/', plugin.public_path, 'images', block.icon_path)
  12 + elsif File.exists?(File.join(Rails.root, 'public', 'images', block.icon_path))
  13 + image_path = File.join('images', block.icon_path)
  14 + else
  15 + image_path = File.join('images', block.default_icon_path)
  16 + end
  17 +
  18 + image_tag(image_path, height: '48', width: '48', class: 'block-type-icon', alt: '' )
  19 + end
  20 +
  21 + def display_previews(block)
  22 + images_path = nil
  23 + plugin = @plugins.fetch_first_plugin(:has_block?, block)
  24 +
  25 + theme = Theme.new(environment.theme) # remove this
  26 +
  27 + images_path = Dir.glob(File.join(theme.filesystem_path, 'images', block.preview_path, '*'))
  28 + images_path = images_path.map{|path| path.gsub(theme.filesystem_path, theme.public_path) } unless images_path.empty?
  29 +
  30 + images_path = Dir.glob(File.join(Rails.root, 'public', plugin.public_path, 'images', block.preview_path, '*')) if plugin && images_path.empty?
  31 + images_path = images_path.map{|path| path.gsub(File.join(Rails.root, 'public'), '') } unless images_path.empty?
  32 +
  33 + images_path = Dir.glob(File.join(Rails.root, 'public', 'images', block.preview_path, '*')) if images_path.empty?
  34 + images_path = images_path.map{|path| path.gsub(File.join(Rails.root, 'public'), '') } unless images_path.empty?
  35 +
  36 + images_path = 1.upto(3).map{File.join('images', block.default_preview_path)} if images_path.empty?
  37 +
  38 + content_tag(:ul,
  39 + images_path.map do |preview|
  40 + content_tag(:li, image_tag(preview, height: '240', alt: ''))
  41 + end.join("\n")
  42 + )
  43 + end
  44 +
3 45 def icon_selector(icon = 'no-ico')
4 46 render :partial => 'icon_selector', :locals => { :icon => icon }
5 47 end
... ... @@ -10,4 +52,4 @@ module BoxOrganizerHelper
10 52 end
11 53 end
12 54  
13   -end
14 55 \ No newline at end of file
  56 +end
... ...
app/helpers/boxes_helper.rb
... ... @@ -122,7 +122,7 @@ module BoxesHelper
122 122 end
123 123  
124 124 def wrap_main_content(content)
125   - (1..8).to_a.reverse.inject(content) { |acc,n| content_tag('div', acc, :id => 'main-content-wrapper-' + n.to_s) }
  125 + content_tag('div', content, :class => 'main-content')
126 126 end
127 127  
128 128 def extract_block_content(content)
... ... @@ -190,8 +190,9 @@ module BoxesHelper
190 190 else
191 191 "before-block-#{block.id}"
192 192 end
193   - if block.nil? or modifiable?(block)
194   - content_tag('div', '&nbsp;', :id => id, :class => 'block-target' ) + drop_receiving_element(id, :url => { :action => 'move_block', :target => id }, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover')
  193 + if block.nil? || movable?(block)
  194 + url = url_for(:action => 'move_block', :target => id)
  195 + content_tag('div', _('Drop Here'), :id => id, :class => 'block-target' ) + drop_receiving_element(id, :accept => box.acceptable_blocks, :hoverclass => 'block-target-hover', :activeClass => 'block-target-active', :tolerance => 'pointer', :onDrop => "function(ev, ui) { dropBlock('#{url}', '#{_('loading...')}', ev, ui);}")
195 196 else
196 197 ""
197 198 end
... ... @@ -199,14 +200,32 @@ module BoxesHelper
199 200  
200 201 # makes the given block draggable so it can be moved away.
201 202 def block_handle(block)
202   - modifiable?(block) ? draggable_element("block-#{block.id}", :revert => true) : ""
  203 + return "" unless movable?(block)
  204 + icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>"
  205 + block_draggable("block-#{block.id}",
  206 + :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}")
  207 + end
  208 +
  209 + def block_draggable(element_id, options={})
  210 + draggable_options = {
  211 + :revert => "'invalid'",
  212 + :appendTo => "'#block-store-draggables'",
  213 + :helper => '"clone"',
  214 + :revertDuration => 200,
  215 + :scroll => false,
  216 + :start => "startDragBlock",
  217 + :stop => "stopDragBlock",
  218 + :cursor => "'move'",
  219 + :cursorAt => '{ left: 0, top:0, right:0, bottom:0 }',
  220 + }.merge(options)
  221 + draggable_element(element_id, draggable_options)
203 222 end
204 223  
205 224 def block_edit_buttons(block)
206 225 buttons = []
207 226 nowhere = 'javascript: return false;'
208 227  
209   - if modifiable?(block)
  228 + if movable?(block)
210 229 if block.first?
211 230 buttons << icon_button('up-disabled', _("Can't move up anymore."), nowhere)
212 231 else
... ... @@ -229,15 +248,15 @@ module BoxesHelper
229 248 buttons << icon_button('left', _('Move to the opposite side'), { :action => 'move_block', :target => 'end-of-box-' + holder.boxes[1].id.to_s, :id => block.id }, :method => 'post' )
230 249 end
231 250 end
  251 + end
232 252  
233   - if block.editable?
234   - buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
235   - end
  253 + if editable?(block)
  254 + buttons << modal_icon_button(:edit, _('Edit'), { :action => 'edit', :id => block.id })
  255 + end
236 256  
237   - if !block.main?
238   - buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})
239   - buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })
240   - end
  257 + if movable?(block) && !block.main?
  258 + buttons << icon_button(:delete, _('Remove block'), { :action => 'remove', :id => block.id }, { :method => 'post', :confirm => _('Are you sure you want to remove this block?')})
  259 + buttons << icon_button(:clone, _('Clone'), { :action => 'clone_block', :id => block.id }, { :method => 'post' })
241 260 end
242 261  
243 262 if block.respond_to?(:help)
... ... @@ -273,7 +292,11 @@ module BoxesHelper
273 292 classes
274 293 end
275 294  
276   - def modifiable?(block)
277   - return !block.fixed || environment.admins.include?(user)
  295 + def movable?(block)
  296 + return block.movable? || user.is_admin?
  297 + end
  298 +
  299 + def editable?(block)
  300 + return block.editable? || user.is_admin?
278 301 end
279 302 end
... ...
app/helpers/chat_helper.rb
... ... @@ -9,12 +9,12 @@ module ChatHelper
9 9 avatar = profile_image(user, :portrait, :class => 'avatar')
10 10 content_tag('span',
11 11 link_to(avatar + content_tag('span', user.name) + ui_icon('ui-icon-triangle-1-s'),
12   - '#',
  12 + '',
13 13 :onclick => 'toggleMenu(this); return false',
14 14 :class => icon_class + ' simplemenu-trigger'
15 15 ) +
16 16 content_tag('ul',
17   - links.map{|link| content_tag('li', link_to(link[1], '#', :class => link[0], :id => link[2], 'data-jid' => user.jid), :class => 'simplemenu-item') }.join("\n"),
  17 + links.map{|link| content_tag('li', link_to(link[1], '', :class => link[0], :id => link[2], 'data-jid' => user.jid), :class => 'simplemenu-item') }.join("\n"),
18 18 :style => 'display: none; z-index: 100',
19 19 :class => 'simplemenu-submenu'
20 20 ),
... ...
app/helpers/comment_helper.rb
1 1 module CommentHelper
  2 + include DatesHelper
2 3  
3 4 def article_title(article, args = {})
4 5 title = article.title
... ... @@ -15,7 +16,7 @@ module CommentHelper
15 16 content_tag('span', show_date(article.published_at), :class => 'date') +
16 17 content_tag('span', [_(", by %s") % link_to(article.author_name, article.author_url)], :class => 'author') +
17 18 content_tag('span', comments, :class => 'comments'),
18   - :class => 'created-at'
  19 + :class => 'publishing-info'
19 20 )
20 21 end
21 22 title
... ...
app/helpers/content_viewer_helper.rb
... ... @@ -2,6 +2,7 @@ module ContentViewerHelper
2 2  
3 3 include BlogHelper
4 4 include ForumHelper
  5 + include DatesHelper
5 6  
6 7 def display_number_of_comments(n)
7 8 base_str = "<span class='comment-count hide'>#{n}</span>"
... ... @@ -24,16 +25,35 @@ module ContentViewerHelper
24 25 unless args[:no_comments] || !article.accept_comments
25 26 comments = (" - %s") % link_to_comments(article)
26 27 end
  28 + date_format = show_with_right_format_date article
27 29 title << content_tag('span',
28   - content_tag('span', show_date(article.published_at), :class => 'date') +
  30 + date_format +
29 31 content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') +
30 32 content_tag('span', comments, :class => 'comments'),
31   - :class => 'created-at'
  33 + :class => 'publishing-info'
32 34 )
33 35 end
34 36 title
35 37 end
36 38  
  39 + def show_with_right_format_date article
  40 + date_format = article.environment.date_format
  41 + use_numbers = false
  42 + year = true
  43 + left_time = false
  44 + if date_format == 'numbers_with_year'
  45 + use_numbers = true
  46 + elsif date_format == 'numbers'
  47 + use_numbers = true
  48 + year = false
  49 + elsif date_format == 'month_name'
  50 + year = false
  51 + elsif date_format == 'past_time'
  52 + left_time = true
  53 + end
  54 + content_tag('span', show_time(article.published_at, use_numbers , year, left_time), :class => 'date')
  55 + end
  56 +
37 57 def link_to_comments(article, args = {})
38 58 return '' unless article.accept_comments?
39 59 reference_to_article number_of_comments(article), article, 'comments_list'
... ...
app/helpers/dates_helper.rb
... ... @@ -2,6 +2,7 @@ require &#39;noosfero/i18n&#39;
2 2  
3 3 module DatesHelper
4 4  
  5 + include ActionView::Helpers::DateHelper
5 6 def months
6 7 I18n.t('date.month_names')
7 8 end
... ... @@ -15,10 +16,12 @@ module DatesHelper
15 16 end
16 17  
17 18 # formats a date for displaying.
18   - def show_date(date, use_numbers = false, year=true)
  19 + def show_date(date, use_numbers = false, year = true, left_time = false)
19 20 if date && use_numbers
20 21 date_format = year ? _('%{month}/%{day}/%{year}') : _('%{month}/%{day}')
21 22 date_format % { :day => date.day, :month => date.month, :year => date.year }
  23 + elsif date && left_time
  24 + date_format = time_ago_in_words(date)
22 25 elsif date
23 26 date_format = year ? _('%{month_name} %{day}, %{year}') : _('%{month_name} %{day}')
24 27 date_format % { :day => date.day, :month_name => month_name(date.month), :year => date.year }
... ... @@ -40,9 +43,14 @@ module DatesHelper
40 43 end
41 44  
42 45 # formats a datetime for displaying.
43   - def show_time(time)
44   - if time
45   - _('%{day} %{month} %{year}, %{hour}:%{minutes}') % { :year => time.year, :month => month_name(time.month), :day => time.day, :hour => time.hour, :minutes => time.strftime("%M") }
  46 + def show_time(time, use_numbers = false, year = true, left_time = false)
  47 + if time && use_numbers
  48 + _('%{month}/%{day}/%{year}, %{hour}:%{minutes}') % { :year => (year ? time.year : ''), :month => time.month, :day => time.day, :hour => time.hour, :minutes => time.strftime("%M") }
  49 + elsif time && left_time
  50 + date_format = time_ago_in_words(time)
  51 + elsif time
  52 + date_format = year ? _('%{month_name} %{day}, %{year} %{hour}:%{minutes}') : _('%{month_name} %{day} %{hour}:%{minutes}')
  53 + date_format % { :day => time.day, :month_name => month_name(time.month), :year => time.year, :hour => time.hour, :minutes => time.strftime("%M") }
46 54 else
47 55 ''
48 56 end
... ... @@ -50,7 +58,7 @@ module DatesHelper
50 58  
51 59 def show_period(date1, date2 = nil, use_numbers = false)
52 60 if (date1 == date2) || (date2.nil?)
53   - show_date(date1, use_numbers)
  61 + show_time(date1, use_numbers)
54 62 else
55 63 if date1.year == date2.year
56 64 if date1.month == date2.month
... ... @@ -69,8 +77,8 @@ module DatesHelper
69 77 end
70 78 else
71 79 _('from %{date1} to %{date2}') % {
72   - :date1 => show_date(date1, use_numbers),
73   - :date2 => show_date(date2, use_numbers)
  80 + :date1 => show_time(date1, use_numbers),
  81 + :date2 => show_time(date2, use_numbers)
74 82 }
75 83 end
76 84 end
... ... @@ -103,18 +111,18 @@ module DatesHelper
103 111  
104 112 def build_date(year, month, day = 1)
105 113 if year.blank? and month.blank? and day.blank?
106   - Date.today
  114 + DateTime.now
107 115 else
108 116 if year.blank?
109   - year = Date.today.year
  117 + year = DateTime.now.year
110 118 end
111 119 if month.blank?
112   - month = Date.today.month
  120 + month = DateTime.now.month
113 121 end
114 122 if day.blank?
115 123 day = 1
116 124 end
117   - Date.new(year.to_i, month.to_i, day.to_i)
  125 + DateTime.new(year.to_i, month.to_i, day.to_i)
118 126 end
119 127 end
120 128  
... ...
app/helpers/email_template_helper.rb 0 → 100644
... ... @@ -0,0 +1,12 @@
  1 +module EmailTemplateHelper
  2 +
  3 + def mail_with_template(params={})
  4 + if params[:email_template].present?
  5 + params[:body] = params[:email_template].parsed_body(params[:template_params])
  6 + params[:subject] = params[:email_template].parsed_subject(params[:template_params])
  7 + params[:content_type] = "text/html"
  8 + end
  9 + mail(params.except(:email_template))
  10 + end
  11 +
  12 +end
... ...
app/helpers/events_helper.rb
1 1 module EventsHelper
2 2  
  3 + include DatesHelper
3 4 def list_events(date, events)
4 5 title = _('Events for %s') % show_date_month(date)
5 6 content_tag('h2', title) +
... ... @@ -15,7 +16,7 @@ module EventsHelper
15 16  
16 17 content_tag( 'tr',
17 18 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', show_time(article.start_date) + ( article.end_date.nil? ? '' : (_(" to ") + show_time(article.end_date))),:class => 'event-date' ) +
19 20 content_tag('div',link_to(article.name,article.url),:class => 'event-title') +
20 21 content_tag('div',(article.address.nil? or article.address == '') ? '' : (_('Place: ') + article.address),:class => 'event-place')
21 22 )
... ... @@ -29,7 +30,7 @@ module EventsHelper
29 30 # the day itself
30 31 date,
31 32 # is there any events in this date?
32   - events.any? {|event| event.date_range.include?(date)},
  33 + events.any? {|event| event.date_range.cover?(date)},
33 34 # is this date in the current month?
34 35 true
35 36 ]
... ...
app/helpers/folder_helper.rb
1   -require 'short_filename'
2   -
3 1 module FolderHelper
4 2  
5   - include ShortFilename
6 3 include ArticleHelper
7 4  
8 5 def list_contents(configure={})
... ... @@ -10,8 +7,8 @@ module FolderHelper
10 7 configure[:list_type] ||= :folder
11 8 if !configure[:contents].blank?
12 9 configure[:contents] = configure[:contents].paginate(
13   - :order => "updated_at DESC",
14   - :per_page => 10,
  10 + :order => "name ASC",
  11 + :per_page => 30,
15 12 :page => params[:npage]
16 13 )
17 14  
... ... @@ -25,49 +22,32 @@ module FolderHelper
25 22 articles.select {|article| article.display_to?(user)}
26 23 end
27 24  
28   - def display_content_in_listing(configure={})
29   - recursive = configure[:recursive] || false
30   - list_type = configure[:list_type] || :folder
31   - level = configure[:level] || 0
32   - content = FilePresenter.for configure[:content]
  25 + def display_content_icon(content_item)
  26 + content = FilePresenter.for content_item
33 27 content_link = if content.image?
34   - link_to('&nbsp;' * (level * 4) +
35   - image_tag(icon_for_article(content)) + short_filename(content.name),
  28 + link_to(
  29 + image_tag(icon_for_article(content, :bigicon)),
36 30 content.url.merge(:view => true)
37 31 )
38 32 else
39   - link_to('&nbsp;' * (level * 4) +
40   - short_filename(content.name),
41   - content.url.merge(:view => true), :class => icon_for_article(content)
  33 + link_to('',
  34 + content.url.merge(:view => true),
  35 + :class => icon_for_article(content, :bigicon)
42 36 )
43 37 end
44   - result = content_tag(
45   - 'tr',
46   - content_tag('td', content_link ) +
47   - content_tag('td', show_date(content.updated_at), :class => 'last-update'),
48   - :class => "#{list_type}-item"
49   - )
50   - if recursive
51   - result + content.children.map {|item|
52   - display_content_in_listing :content=>item, :recursive=>recursive,
53   - :list_type=>list_type, :level=>level+1
54   - }.join("\n")
55   - else
56   - result
57   - end
58 38 end
59 39  
60   - def icon_for_article(article)
  40 + def icon_for_article(article, size = 'icon')
61 41 article = FilePresenter.for article
62   - icon = article.respond_to?(:icon_name) ?
63   - article.icon_name :
64   - article.class.icon_name(article)
65   - if (icon =~ /\//)
66   - icon
  42 + if article.respond_to?(:sized_icon)
  43 + article.sized_icon(size)
67 44 else
68   - klasses = 'icon ' + [icon].flatten.map{|name| 'icon-'+name}.join(' ')
  45 + icon = article.respond_to?(:icon_name) ?
  46 + article.icon_name :
  47 + article.class.icon_name(article)
  48 + klasses = "#{size} " + [icon].flatten.map{|name| "#{size}-"+name}.join(' ')
69 49 if article.kind_of?(UploadedFile) || article.kind_of?(FilePresenter)
70   - klasses += ' icon-upload-file'
  50 + klasses += " #{size}-upload-file"
71 51 end
72 52 klasses
73 53 end
... ...
app/helpers/forms_helper.rb
... ... @@ -151,7 +151,7 @@ module FormsHelper
151 151 datepicker_options[:close_text] ||= _('Done')
152 152 datepicker_options[:constrain_input] ||= true
153 153 datepicker_options[:current_text] ||= _('Today')
154   - datepicker_options[:date_format] ||= 'mm/dd/yy'
  154 + datepicker_options[:date_format] ||= 'yy/mm/dd'
155 155 datepicker_options[:day_names] ||= [_('Sunday'), _('Monday'), _('Tuesday'), _('Wednesday'), _('Thursday'), _('Friday'), _('Saturday')]
156 156 datepicker_options[:day_names_min] ||= [_('Su'), _('Mo'), _('Tu'), _('We'), _('Th'), _('Fr'), _('Sa')]
157 157 datepicker_options[:day_names_short] ||= [_('Sun'), _('Mon'), _('Tue'), _('Wed'), _('Thu'), _('Fri'), _('Sat')]
... ... @@ -236,7 +236,7 @@ module FormsHelper
236 236 weekHeader: #{datepicker_options[:week_header].to_json},
237 237 yearRange: #{datepicker_options[:year_range].to_json},
238 238 yearSuffix: #{datepicker_options[:year_suffix].to_json}
239   - })
  239 + }).datepicker('setDate', new Date('#{value}'))
240 240 </script>
241 241 ".html_safe
242 242 result
... ...
app/helpers/forum_helper.rb
1 1 module ForumHelper
  2 + include ActionView::Helpers::DateHelper
2 3  
3 4 def cms_label_for_new_children
4 5 _('New discussion topic')
... ... @@ -42,9 +43,9 @@ module ForumHelper
42 43 def last_topic_update(article)
43 44 info = article.info_from_last_update
44 45 if info[:author_url]
45   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
  46 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + link_to(info[:author_name], info[:author_url])
46 47 else
47   - time_ago_as_sentence(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
  48 + time_ago_in_words(info[:date]) + ' ' + _('by') + ' ' + info[:author_name]
48 49 end
49 50 end
50 51  
... ...
app/helpers/layout_helper.rb
... ... @@ -28,7 +28,7 @@ module LayoutHelper
28 28 end
29 29  
30 30 def noosfero_javascript
31   - plugins_javascripts = @plugins.flat_map{ |plugin| plugin.js_files.map{ |js| plugin.class.public_path(js, true) } }.flatten
  31 + plugins_javascripts = @plugins.flat_map{ |plugin| Array.wrap(plugin.js_files).map{ |js| plugin.class.public_path(js, true) } }.flatten
32 32  
33 33 output = ''
34 34 output += render 'layouts/javascript'
... ... @@ -38,6 +38,8 @@ module LayoutHelper
38 38 output += theme_javascript_ng.to_s
39 39 output += javascript_tag 'render_all_jquery_ui_widgets()'
40 40  
  41 + output += templete_javascript_ng.to_s
  42 +
41 43 output
42 44 end
43 45  
... ... @@ -70,24 +72,13 @@ module LayoutHelper
70 72 end
71 73  
72 74 def template_stylesheet_path
73   - if profile.nil?
74   - "/designs/templates/#{environment.layout_template}/stylesheets/style.css"
75   - else
76   - "/designs/templates/#{profile.layout_template}/stylesheets/style.css"
77   - end
  75 + File.join template_path, "/stylesheets/style.css"
78 76 end
79 77  
80 78  
81 79 def icon_theme_stylesheet_path
82   - icon_themes = []
83 80 theme_icon_themes = theme_option(:icon_theme) || []
84   - for icon_theme in theme_icon_themes do
85   - theme_path = "designs/icons/#{icon_theme}/style.css"
86   - if File.exists?(Rails.root.join('public', theme_path))
87   - icon_themes << theme_path
88   - end
89   - end
90   - icon_themes
  81 + theme_icon_themes.map{ |it| "designs/icons/#{it}/style.css" }
91 82 end
92 83  
93 84 def jquery_ui_theme_stylesheet_path
... ...
app/helpers/manage_products_helper.rb
... ... @@ -75,9 +75,12 @@ module ManageProductsHelper
75 75 end
76 76  
77 77 def categories_container(categories_selection_html, hierarchy_html = '')
78   - hidden_field_tag('selected_category_id') +
79   - content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
80   - content_tag('div', categories_selection_html, :id => 'categories_container_wrapper')
  78 + content_tag 'div',
  79 + render('categories_autocomplete') +
  80 + hidden_field_tag('selected_category_id') +
  81 + content_tag('div', hierarchy_html, :id => 'hierarchy_navigation') +
  82 + content_tag('div', categories_selection_html, :id => 'categories_container_wrapper'),
  83 + :id => 'categories-container'
81 84 end
82 85  
83 86 def select_for_categories(categories, level = 0)
... ...
app/helpers/profile_editor_helper.rb
... ... @@ -141,8 +141,9 @@ module ProfileEditorHelper
141 141 )
142 142 end
143 143  
144   - def control_panel_button(title, icon, url)
145   - link_to title, url, :class => 'control-panel-%s' % icon
  144 + def control_panel_button(title, icon, url, html_options = {})
  145 + html_options ||= {}
  146 + link_to title, url, html_options.merge(:class => 'control-panel-%s' % icon)
146 147 end
147 148  
148 149 def unchangeable_privacy_field(profile)
... ...
app/helpers/profile_helper.rb
... ... @@ -190,4 +190,22 @@ module ProfileHelper
190 190 end
191 191 end
192 192  
  193 + def display_custom_field(title, profile, field, force = false)
  194 + unless force || profile.may_display_field_to?(field, user)
  195 + return
  196 + end
  197 + value = profile.custom_fields[field][:value]
  198 + !value.blank? ? content_tag('tr', content_tag('td', title) + content_tag('td', value)) : ''
  199 + end
  200 +
  201 + def display_custom_fields(profile)
  202 + fields = []
  203 + profile.custom_fields.each { |custom_field_key,custom_field_data|
  204 + if !profile.fields_privacy.blank? && profile.fields_privacy.include?(custom_field_key)
  205 + fields << display_custom_field(custom_field_data[:title], profile, custom_field_key) if profile.fields_privacy[custom_field_key] == 'public'
  206 + end
  207 + }
  208 + fields.size >= 1 ? content_tag('tr', content_tag('th', _('Custom Fields'), { :colspan => 2 })) + fields.join.html_safe : ''
  209 + end
  210 +
193 211 end
... ...
app/helpers/search_helper.rb
... ... @@ -106,6 +106,10 @@ module SearchHelper
106 106 end
107 107 end
108 108  
  109 + def city_with_state_for_profile(p)
  110 + city_with_state(p.region) || [p.city, p.state].compact.reject(&:blank?).join(', ')
  111 + end
  112 +
109 113 def display_selector(asset, display, float = 'right')
110 114 display = nil if display.blank?
111 115 display ||= asset_class(asset).default_search_display
... ...
app/helpers/task_helper.rb 0 → 100644
... ... @@ -0,0 +1,23 @@
  1 +module TaskHelper
  2 +
  3 + def task_email_template(description, email_templates, task, include_blank=true)
  4 + return '' unless email_templates.present?
  5 +
  6 + content_tag(
  7 + :div,
  8 + labelled_form_field(description, select_tag("tasks[#{task.id}][task][email_template_id]", options_from_collection_for_select(email_templates, :id, :name), :include_blank => include_blank, 'data-url' => url_for(:controller => 'profile_email_templates', :action => 'show_parsed', :profile => profile.identifier))),
  9 + :class => 'template-selection'
  10 + )
  11 + end
  12 +
  13 + def task_action action
  14 + base_url = { action: action }
  15 + url_for(base_url.merge(filter_params))
  16 + end
  17 +
  18 + def filter_params
  19 + filter_fields = ['filter_type', 'filter_text', 'filter_responsible', 'filter_tags']
  20 + params.select {|filter| filter if filter_fields.include? filter }
  21 + end
  22 +
  23 +end
... ...
app/helpers/tinymce_helper.rb
... ... @@ -17,9 +17,10 @@ module TinymceHelper
17 17 searchreplace wordcount visualblocks visualchars code fullscreen
18 18 insertdatetime media nonbreaking save table contextmenu directionality
19 19 emoticons template paste textcolor colorpicker textpattern],
  20 + :image_advtab => true,
20 21 :language => tinymce_language
21 22  
22   - options[:toolbar1] = "insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
  23 + options[:toolbar1] = "fullscreen | insertfile undo redo | copy paste | bold italic underline | styleselect fontsizeselect | forecolor backcolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image"
23 24 if options[:mode] == 'simple'
24 25 options[:menubar] = false
25 26 else
... ...
app/helpers/users_helper.rb
... ... @@ -14,7 +14,7 @@ module UsersHelper
14 14 select_field = select_tag(:filter, options, :onchange => onchange)
15 15 content_tag('div',
16 16 content_tag('strong', _('Filter')) + ': ' + select_field,
17   - :class => "environment-users-customize-search"
  17 + :class => "environment-profiles-customize-search"
18 18 )
19 19 end
20 20  
... ...
app/mailers/scrap_notifier.rb
1 1 class ScrapNotifier < ActionMailer::Base
2 2 def notification(scrap)
3 3 sender, receiver = scrap.sender, scrap.receiver
  4 + # for tests
  5 + return unless receiver.email
  6 +
4 7 @recipient = receiver.name
5 8 @sender = sender.name
6 9 @sender_link = sender.url
... ...
app/mailers/task_mailer.rb
1 1 class TaskMailer < ActionMailer::Base
2 2  
  3 + include EmailTemplateHelper
  4 +
3 5 def target_notification(task, message)
4 6 @message = extract_message(message)
5 7 @target = task.target.name
6 8 @environment = task.environment.name
7 9 @url = generate_environment_url(task, :controller => 'home')
8   - url_for_tasks_list = task.target.kind_of?(Environment) ? '' : url_for(task.target.tasks_url)
  10 + url_for_tasks_list = task.target.kind_of?(Environment) ? '' : url_for(task.target.tasks_url.merge(:script_name => Noosfero.root('/')))
9 11 @tasks_url = url_for_tasks_list
10 12  
11 13 mail(
... ... @@ -34,10 +36,12 @@ class TaskMailer &lt; ActionMailer::Base
34 36 @environment = task.requestor.environment.name
35 37 @url = url_for(:host => task.requestor.environment.default_hostname, :controller => 'home')
36 38  
37   - mail(
  39 + mail_with_template(
38 40 to: task.requestor.notification_emails,
39 41 from: self.class.generate_from(task),
40   - subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description]
  42 + subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description],
  43 + email_template: task.email_template,
  44 + template_params: {:environment => task.requestor.environment, :task => task, :message => @message, :url => @url, :requestor => task.requestor}
41 45 )
42 46 end
43 47  
... ... @@ -56,7 +60,7 @@ class TaskMailer &lt; ActionMailer::Base
56 60 end
57 61  
58 62 def generate_environment_url(task, url = {})
59   - url_for(Noosfero.url_options.merge(:host => task.environment.default_hostname).merge(url))
  63 + url_for(Noosfero.url_options.merge(:host => task.environment.default_hostname).merge(url).merge(:script_name => Noosfero.root('/')))
60 64 end
61 65  
62 66 end
... ...
app/mailers/user_mailer.rb
1 1 class UserMailer < ActionMailer::Base
  2 +
  3 + include EmailTemplateHelper
  4 +
2 5 def activation_email_notify(user)
3 6 user_email = "#{user.login}@#{user.email_domain}"
4 7 @name = user.name
... ... @@ -22,10 +25,12 @@ class UserMailer &lt; ActionMailer::Base
22 25 @redirection = (true if user.return_to)
23 26 @join = (user.community_to_join if user.community_to_join)
24 27  
25   - mail(
  28 + mail_with_template(
26 29 from: "#{user.environment.name} <#{user.environment.contact_email}>",
27 30 to: user.email,
28 31 subject: _("[%s] Activate your account") % [user.environment.name],
  32 + template_params: {:environment => user.environment, :activation_code => @activation_code, :redirection => @redirection, :join => @join},
  33 + email_template: user.environment.email_templates.find_by_template_type(:user_activation),
29 34 )
30 35 end
31 36  
... ...
app/models/abuse_complaint.rb
... ... @@ -40,10 +40,6 @@ class AbuseComplaint &lt; Task
40 40 true
41 41 end
42 42  
43   - def reject_details
44   - true
45   - end
46   -
47 43 def icon
48 44 {:type => :profile_image, :profile => reported, :url => reported.url}
49 45 end
... ...
app/models/add_friend.rb
... ... @@ -14,6 +14,9 @@ class AddFriend &lt; Task
14 14 alias :friend :target
15 15 alias :friend= :target=
16 16  
  17 + validates :requestor, :kind_of => { :kind => Person }
  18 + validates :target, :kind_of => { :kind => Person }
  19 +
17 20 after_create do |task|
18 21 TaskMailer.invitation_notification(task).deliver unless task.friend
19 22 remove_from_suggestion_list(task)
... ... @@ -54,7 +57,7 @@ class AddFriend &lt; Task
54 57 end
55 58  
56 59 def remove_from_suggestion_list(task)
57   - suggestion = task.requestor.profile_suggestions.find_by_suggestion_id task.target.id
  60 + suggestion = task.requestor.suggested_profiles.find_by_suggestion_id task.target.id
58 61 suggestion.disable if suggestion
59 62 end
60 63 end
... ...
app/models/add_member.rb
... ... @@ -2,6 +2,9 @@ class AddMember &lt; Task
2 2  
3 3 validates_presence_of :requestor_id, :target_id
4 4  
  5 + validates :requestor, kind_of: {kind: Person}
  6 + validates :target, kind_of: {kind: Organization}
  7 +
5 8 alias :person :requestor
6 9 alias :person= :requestor=
7 10  
... ... @@ -26,7 +29,8 @@ class AddMember &lt; Task
26 29 end
27 30  
28 31 def information
29   - {:message => _('%{requestor} wants to be a member of this community.')}
  32 + {:message => _("%{requestor} wants to be a member of '%{organization}'."),
  33 + variables: {requestor: requestor.name, organization: organization.name}}
30 34 end
31 35  
32 36 def accept_details
... ... @@ -42,7 +46,7 @@ class AddMember &lt; Task
42 46 end
43 47  
44 48 def target_notification_description
45   - _('%{requestor} wants to be a member of this community.') % {:requestor => requestor.name}
  49 + _("%{requestor} wants to be a member of '%{organization}'.") % {:requestor => requestor.name, :organization => organization.name}
46 50 end
47 51  
48 52 def target_notification_message
... ...
app/models/approve_article.rb
1 1 class ApproveArticle < Task
2 2 validates_presence_of :requestor_id, :target_id
3 3  
  4 + validates :requestor, kind_of: {kind: Person}
  5 + validate :allowed_requestor
  6 +
  7 + def allowed_requestor
  8 + if target
  9 + if target.person? && requestor != target
  10 + self.errors.add(:requestor, _('You can not post articles to other users.'))
  11 + end
  12 + if target.organization? && !target.members.include?(requestor) && target.environment.portal_community != target
  13 + self.errors.add(:requestor, _('Only members can post articles on communities.'))
  14 + end
  15 + end
  16 + end
  17 +
4 18 def article_title
5 19 article ? article.title : _('(The original text was removed)')
6 20 end
7   -
  21 +
8 22 def article
9 23 Article.find_by_id data[:article_id]
10 24 end
... ... @@ -82,10 +96,6 @@ class ApproveArticle &lt; Task
82 96 true
83 97 end
84 98  
85   - def reject_details
86   - true
87   - end
88   -
89 99 def default_decision
90 100 if article
91 101 'skip'
... ... @@ -128,4 +138,9 @@ class ApproveArticle &lt; Task
128 138 message
129 139 end
130 140  
  141 + def request_is_member_of_target
  142 + unless requestor.is_member_of?(target)
  143 + errors.add(:approve_article, N_('Requestor must be a member of target.'))
  144 + end
  145 + end
131 146 end
... ...
app/models/approve_comment.rb
... ... @@ -60,10 +60,6 @@ class ApproveComment &lt; Task
60 60 true
61 61 end
62 62  
63   - def reject_details
64   - true
65   - end
66   -
67 63 def default_decision
68 64 if article
69 65 'skip'
... ...
app/models/article.rb
1   -
2 1 class Article < ActiveRecord::Base
3 2  
4 3 attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent,
5 4 :allow_members_to_edit, :translation_of_id, :language,
6 5 :license_id, :parent_id, :display_posts_in_current_language,
7 6 :category_ids, :posts_per_page, :moderate_comments,
8   - :accept_comments, :feed, :published, :source,
  7 + :accept_comments, :feed, :published, :source, :source_name,
9 8 :highlighted, :notify_comments, :display_hits, :slug,
10 9 :external_feed_builder, :display_versions, :external_link,
11   - :image_builder, :show_to_followers
  10 + :author, :published_at, :person_followers, :show_to_followers, :image_builder
12 11  
13 12 acts_as_having_image
14 13  
... ... @@ -25,6 +24,16 @@ class Article &lt; ActiveRecord::Base
25 24 :display => %w[full]
26 25 }
27 26  
  27 + def initialize(*params)
  28 + super
  29 +
  30 + if !params.blank? && params.first.has_key?(:profile) && !params.first[:profile].blank?
  31 + profile = params.first[:profile]
  32 + self.published = false unless profile.public?
  33 + end
  34 +
  35 + end
  36 +
28 37 def self.default_search_display
29 38 'full'
30 39 end
... ... @@ -61,6 +70,10 @@ class Article &lt; ActiveRecord::Base
61 70 belongs_to :last_changed_by, :class_name => 'Person', :foreign_key => 'last_changed_by_id'
62 71 belongs_to :created_by, :class_name => 'Person', :foreign_key => 'created_by_id'
63 72  
  73 + #Article followers relation
  74 + has_many :article_followers, :dependent => :destroy
  75 + has_many :person_followers, :class_name => 'Person', :through => :article_followers, :source => :person
  76 +
64 77 has_many :comments, :class_name => 'Comment', :foreign_key => 'source_id', :dependent => :destroy, :order => 'created_at asc'
65 78  
66 79 has_many :article_categorizations, :conditions => [ 'articles_categories.virtual = ?', false ]
... ... @@ -86,6 +99,8 @@ class Article &lt; ActiveRecord::Base
86 99 belongs_to :translation_of, :class_name => 'Article', :foreign_key => :translation_of_id
87 100 before_destroy :rotate_translations
88 101  
  102 + acts_as_voteable
  103 +
89 104 before_create do |article|
90 105 article.published_at ||= Time.now
91 106 if article.reference_article && !article.parent
... ... @@ -117,9 +132,11 @@ class Article &lt; ActiveRecord::Base
117 132 {:include => 'categories_including_virtual', :conditions => { 'categories.id' => category.id }}
118 133 }
119 134  
  135 + include TimeScopes
  136 +
120 137 scope :by_range, lambda { |range| {
121 138 :conditions => [
122   - 'published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last }
  139 + 'articles.published_at BETWEEN :start_date AND :end_date', { :start_date => range.first, :end_date => range.last }
123 140 ]
124 141 }}
125 142  
... ... @@ -248,7 +265,7 @@ class Article &lt; ActiveRecord::Base
248 265 }
249 266  
250 267 scope :public,
251   - :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ], :joins => [:profile]
  268 + :conditions => [ "articles.advertise = ? AND articles.published = ? AND profiles.visible = ? AND profiles.public_profile = ?", true, true, true, true ], :joins => [:profile]
252 269  
253 270 scope :more_recent,
254 271 :conditions => [ "advertise = ? AND published = ? AND profiles.visible = ? AND profiles.public_profile = ? AND
... ... @@ -491,11 +508,11 @@ class Article &lt; ActiveRecord::Base
491 508 return [] if user.nil? || (profile && !profile.public? && !user.follows?(profile))
492 509 where(
493 510 [
494   - "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ?
495   - OR (show_to_followers = ? AND ?)", true, user.id, user.id,
  511 + "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ?
  512 + OR (show_to_followers = ? AND ? AND profile_id IN (?))", true, user.id, user.id,
496 513 profile.nil? ? false : user.has_permission?(:view_private_content, profile),
497   - true, user.follows?(profile)
498   - ]
  514 + true, (profile.nil? ? true : user.follows?(profile)), ( profile.nil? ? (user.friends.select('profiles.id')) : [profile.id])
  515 + ]
499 516 )
500 517 }
501 518  
... ... @@ -509,7 +526,7 @@ class Article &lt; ActiveRecord::Base
509 526  
510 527 def display_to?(user = nil)
511 528 if published?
512   - profile.display_info_to?(user)
  529 + (profile.secret? || !profile.visible?) ? profile.display_info_to?(user) : true
513 530 else
514 531 if !user
515 532 false
... ... @@ -567,25 +584,24 @@ class Article &lt; ActiveRecord::Base
567 584 profile.visible? && profile.public? && published?
568 585 end
569 586  
570   -
571   - def copy(options = {})
  587 + def copy_without_save(options = {})
572 588 attrs = attributes.reject! { |key, value| ATTRIBUTES_NOT_COPIED.include?(key.to_sym) }
573 589 attrs.merge!(options)
574 590 object = self.class.new
575 591 attrs.each do |key, value|
576 592 object.send(key.to_s+'=', value)
577 593 end
  594 + object
  595 + end
  596 +
  597 + def copy(options = {})
  598 + object = copy_without_save(options)
578 599 object.save
579 600 object
580 601 end
581 602  
582 603 def copy!(options = {})
583   - attrs = attributes.reject! { |key, value| ATTRIBUTES_NOT_COPIED.include?(key.to_sym) }
584   - attrs.merge!(options)
585   - object = self.class.new
586   - attrs.each do |key, value|
587   - object.send(key.to_s+'=', value)
588   - end
  604 + object = copy_without_save(options)
589 605 object.save!
590 606 object
591 607 end
... ... @@ -615,6 +631,11 @@ class Article &lt; ActiveRecord::Base
615 631 self.hits += 1
616 632 end
617 633  
  634 + def self.hit(articles)
  635 + Article.where(:id => articles.map(&:id)).update_all('hits = hits + 1')
  636 + articles.each { |a| a.hits += 1 }
  637 + end
  638 +
618 639 def can_display_hits?
619 640 true
620 641 end
... ... @@ -623,6 +644,14 @@ class Article &lt; ActiveRecord::Base
623 644 can_display_hits? && display_hits
624 645 end
625 646  
  647 + def display_media_panel?
  648 + can_display_media_panel? && environment.enabled?('media_panel')
  649 + end
  650 +
  651 + def can_display_media_panel?
  652 + false
  653 + end
  654 +
626 655 def image?
627 656 false
628 657 end
... ... @@ -692,6 +721,11 @@ class Article &lt; ActiveRecord::Base
692 721 person ? person.id : nil
693 722 end
694 723  
  724 + #FIXME make this test
  725 + def author_custom_image(size = :icon)
  726 + author ? author.profile_custom_image(size) : nil
  727 + end
  728 +
695 729 def version_license(version_number = nil)
696 730 return license if version_number.nil?
697 731 profile.environment.licenses.find_by_id(get_version(version_number).license_id)
... ... @@ -713,8 +747,9 @@ class Article &lt; ActiveRecord::Base
713 747 paragraphs.empty? ? '' : paragraphs.first.to_html
714 748 end
715 749  
716   - def lead
717   - abstract.blank? ? first_paragraph.html_safe : abstract.html_safe
  750 + def lead(length = nil)
  751 + content = abstract.blank? ? first_paragraph.html_safe : abstract.html_safe
  752 + length.present? ? content.truncate(length) : content
718 753 end
719 754  
720 755 def short_lead
... ... @@ -781,6 +816,14 @@ class Article &lt; ActiveRecord::Base
781 816 true
782 817 end
783 818  
  819 + def view_page
  820 + "content_viewer/view_page"
  821 + end
  822 +
  823 + def to_liquid
  824 + HashWithIndifferentAccess.new :name => name, :abstract => abstract, :body => body, :id => id, :parent_id => parent_id, :author => author
  825 + end
  826 +
784 827 private
785 828  
786 829 def sanitize_tag_list
... ...
app/models/article_block.rb
... ... @@ -3,7 +3,15 @@ class ArticleBlock &lt; Block
3 3 attr_accessible :article_id
4 4  
5 5 def self.description
6   - _('Display one of your contents')
  6 + _('Display one of your contents.')
  7 + end
  8 +
  9 + def self.short_description
  10 + _('Show one article')
  11 + end
  12 +
  13 + def self.pretty_name
  14 + _('Article')
7 15 end
8 16  
9 17 def help
... ...
app/models/article_follower.rb 0 → 100644
... ... @@ -0,0 +1,5 @@
  1 +class ArticleFollower < ActiveRecord::Base
  2 + attr_accessible :article_id, :person_id, :since
  3 + belongs_to :article
  4 + belongs_to :person
  5 +end
... ...
app/models/block.rb
1 1 class Block < ActiveRecord::Base
2 2  
3   - attr_accessible :title, :display, :limit, :box_id, :posts_per_page, :visualization_format, :language, :display_user, :box, :fixed
  3 + attr_accessible :title, :display, :limit, :box_id, :posts_per_page,
  4 + :visualization_format, :language, :display_user,
  5 + :box, :edit_modes, :move_modes, :mirror
4 6  
5 7 # to be able to generate HTML
6 8 include ActionView::Helpers::UrlHelper
... ... @@ -13,17 +15,29 @@ class Block &lt; ActiveRecord::Base
13 15  
14 16 acts_as_list :scope => :box
15 17 belongs_to :box
  18 + belongs_to :mirror_block, :class_name => "Block"
  19 + has_many :observers, :class_name => "Block", :foreign_key => "mirror_block_id"
16 20  
17 21 acts_as_having_settings
18 22  
19 23 scope :enabled, :conditions => { :enabled => true }
20 24  
  25 + after_save do |block|
  26 + if block.owner.kind_of?(Profile) && block.owner.is_template? && block.mirror?
  27 + block.observers.each do |observer|
  28 + observer.copy_from(block)
  29 + observer.title = block.title
  30 + observer.save
  31 + end
  32 + end
  33 + end
  34 +
21 35 def embedable?
22 36 false
23 37 end
24 38  
25 39 def get_limit
26   - [0,limit].max
  40 + [0,limit.to_i].max
27 41 end
28 42  
29 43 def embed_code
... ... @@ -110,8 +124,13 @@ class Block &lt; ActiveRecord::Base
110 124 # * <tt>'all'</tt>: the block is always displayed
111 125 settings_items :language, :type => :string, :default => 'all'
112 126  
113   - # The block can be configured to be fixed. Only can be edited by environment admins
114   - settings_items :fixed, :type => :boolean, :default => false
  127 + # The block can be configured to define the edition modes options. Only can be edited by environment admins
  128 + # It can assume the following values:
  129 + #
  130 + # * <tt>'all'</tt>: the block owner has all edit options for this block
  131 + # * <tt>'none'</tt>: the block owner can't do anything with the block
  132 + settings_items :edit_modes, :type => :string, :default => 'all'
  133 + settings_items :move_modes, :type => :string, :default => 'all'
115 134  
116 135 # returns the description of the block, used when the user sees a list of
117 136 # blocks to choose one to include in the design.
... ... @@ -122,6 +141,36 @@ class Block &lt; ActiveRecord::Base
122 141 '(dummy)'
123 142 end
124 143  
  144 + def self.short_description
  145 + self.pretty_name
  146 + end
  147 +
  148 + def self.icon
  149 + "/images/icon_block.png"
  150 + end
  151 +
  152 + def self.icon_path
  153 + basename = self.name.split('::').last.underscore
  154 + File.join('blocks', basename, 'icon.png')
  155 + end
  156 +
  157 + def self.pretty_name
  158 + self.name.split('::').last.gsub('Block','')
  159 + end
  160 +
  161 + def self.default_icon_path
  162 + 'icon_block.png'
  163 + end
  164 +
  165 + def self.preview_path
  166 + base_name = self.name.split('::').last.underscore
  167 + File.join('blocks', base_name,'previews')
  168 + end
  169 +
  170 + def self.default_preview_path
  171 + "block_preview.png"
  172 + end
  173 +
125 174 # Returns the content to be used for this block.
126 175 #
127 176 # This method can return several types of objects:
... ... @@ -148,7 +197,11 @@ class Block &lt; ActiveRecord::Base
148 197  
149 198 # Is this block editable? (Default to <tt>false</tt>)
150 199 def editable?
151   - true
  200 + self.edit_modes == "all"
  201 + end
  202 +
  203 + def movable?
  204 + self.move_modes == "all"
152 205 end
153 206  
154 207 # must always return false, except on MainBlock clas.
... ... @@ -228,6 +281,21 @@ class Block &lt; ActiveRecord::Base
228 281 }
229 282 end
230 283  
  284 + def edit_block_options
  285 + @edit_options ||= {
  286 + 'all' => _('Can be modified'),
  287 + 'none' => _('Cannot be modified')
  288 + }
  289 + end
  290 +
  291 + def move_block_options
  292 + @move_options ||= {
  293 + 'all' => _('Can be moved'),
  294 + 'none' => _('Cannot be moved')
  295 + }
  296 + end
  297 +
  298 +
231 299 def duplicate
232 300 duplicated_block = self.dup
233 301 duplicated_block.display = 'never'
... ... @@ -243,6 +311,10 @@ class Block &lt; ActiveRecord::Base
243 311 self.position = block.position
244 312 end
245 313  
  314 + def add_observer(block)
  315 + self.observers << block
  316 + end
  317 +
246 318 private
247 319  
248 320 def home_page_path
... ...
app/models/blog.rb
... ... @@ -76,9 +76,12 @@ class Blog &lt; Folder
76 76 end
77 77  
78 78 settings_items :visualization_format, :type => :string, :default => 'full'
79   - validates_inclusion_of :visualization_format, :in => [ 'full', 'short', 'short+pic' ], :if => :visualization_format
  79 + validates_inclusion_of :visualization_format,
  80 + :in => [ 'full', 'short', 'short+pic', 'compact'],
  81 + :if => :visualization_format
80 82  
81   - settings_items :display_posts_in_current_language, :type => :boolean, :default => false
  83 + settings_items :display_posts_in_current_language,
  84 + :type => :boolean, :default => false
82 85  
83 86 alias :display_posts_in_current_language? :display_posts_in_current_language
84 87  
... ...
app/models/change_password.rb
... ... @@ -18,6 +18,8 @@ class ChangePassword &lt; Task
18 18  
19 19 validates_presence_of :requestor
20 20  
  21 + validates :requestor, kind_of: {kind: Person}
  22 +
21 23 ###################################################
22 24 # validations for updating a ChangePassword task
23 25  
... ... @@ -26,6 +28,13 @@ class ChangePassword &lt; Task
26 28 validates_presence_of :password_confirmation, :on => :update, :if => lambda { |change| change.status != Task::Status::CANCELLED }
27 29 validates_confirmation_of :password, :if => lambda { |change| change.status != Task::Status::CANCELLED }
28 30  
  31 + before_save :set_email_template
  32 +
  33 + def set_email_template
  34 + template = environment.email_templates.find_by_template_type(:user_change_password)
  35 + data[:email_template_id] = template.id unless template.nil?
  36 + end
  37 +
29 38 def environment
30 39 requestor.environment unless requestor.nil?
31 40 end
... ...
app/models/chat_message.rb
... ... @@ -4,4 +4,5 @@ class ChatMessage &lt; ActiveRecord::Base
4 4 belongs_to :to, :class_name => 'Profile'
5 5 belongs_to :from, :class_name => 'Profile'
6 6  
  7 + validates_presence_of :from, :to
7 8 end
... ...
app/models/comment.rb
... ... @@ -20,6 +20,8 @@ class Comment &lt; ActiveRecord::Base
20 20  
21 21 scope :without_reply, :conditions => ['reply_of_id IS NULL']
22 22  
  23 + include TimeScopes
  24 +
23 25 # unauthenticated authors:
24 26 validates_presence_of :name, :if => (lambda { |record| !record.email.blank? })
25 27 validates_presence_of :email, :if => (lambda { |record| !record.name.blank? })
... ... @@ -32,11 +34,13 @@ class Comment &lt; ActiveRecord::Base
32 34 rec.errors.add(:name, _('{fn} can only be informed for unauthenticated authors').fix_i18n)
33 35 end
34 36 end
35   -
  37 +
36 38 acts_as_having_settings
37 39  
38 40 xss_terminate :only => [ :body, :title, :name ], :on => 'validation'
39 41  
  42 + acts_as_voteable
  43 +
40 44 def comment_root
41 45 (reply_of && reply_of.comment_root) || self
42 46 end
... ... @@ -65,6 +69,11 @@ class Comment &lt; ActiveRecord::Base
65 69 author ? author.url : nil
66 70 end
67 71  
  72 + #FIXME make this test
  73 + def author_custom_image(size = :icon)
  74 + author ? author.profile_custom_image(size) : nil
  75 + end
  76 +
68 77 def url
69 78 article.view_url.merge(:anchor => anchor)
70 79 end
... ...
app/models/communities_block.rb
... ... @@ -3,9 +3,17 @@ class CommunitiesBlock &lt; ProfileListBlock
3 3 attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type
4 4  
5 5 def self.description
  6 + _("<p>Display all of your communities.</p><p>You could choose the amount of communities will be displayed and you could priorize that profiles with images.</p> <p>The view all button is always present in the block.</p>")
  7 + end
  8 +
  9 + def self.short_description
6 10 _('Communities')
7 11 end
8 12  
  13 + def self.pretty_name
  14 + _('Communities Block')
  15 + end
  16 +
9 17 def default_title
10 18 n_('{#} community', '{#} communities', profile_count)
11 19 end
... ...
app/models/community.rb
... ... @@ -86,8 +86,8 @@ class Community &lt; Organization
86 86 {:title => _('Community Info and settings'), :icon => 'edit-profile-group'}
87 87 end
88 88  
89   - def activities
90   - 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.target_id = #{self.id} and action_tracker.verb != 'join_community' and action_tracker.verb != 'leave_scrap' UNION SELECT at.id, at.updated_at, '#{ActionTracker::Record.to_s}' AS klass FROM #{ActionTracker::Record.table_name} at INNER JOIN articles a ON at.target_id = a.id WHERE a.profile_id = #{self.id} AND at.target_type = 'Article' ORDER BY updated_at DESC")
  89 + def exclude_verbs_on_activities
  90 + %w[join_community leave_scrap]
91 91 end
92 92  
93 93 end
... ...
app/models/create_community.rb
... ... @@ -3,6 +3,9 @@ class CreateCommunity &lt; Task
3 3 validates_presence_of :requestor_id, :target_id
4 4 validates_presence_of :name
5 5  
  6 + validates :requestor, kind_of: {kind: Person}
  7 + validates :target, kind_of: {kind: Environment}
  8 +
6 9 alias :environment :target
7 10 alias :environment= :target=
8 11  
... ... @@ -56,10 +59,6 @@ class CreateCommunity &lt; Task
56 59 end
57 60 end
58 61  
59   - def reject_details
60   - true
61   - end
62   -
63 62 # tells if this request was rejected
64 63 def rejected?
65 64 self.status == Task::Status::CANCELLED
... ...
app/models/create_enterprise.rb
... ... @@ -27,6 +27,8 @@ class CreateEnterprise &lt; Task
27 27 # checks for actual attributes
28 28 validates_presence_of :requestor_id, :target_id
29 29  
  30 + validates :requestor, kind_of: {kind: Person}
  31 +
30 32 # checks for admins required attributes
31 33 DATA_FIELDS.each do |attribute|
32 34 validates_presence_of attribute, :if => lambda { |obj| obj.environment.required_enterprise_fields.include?(attribute) }
... ... @@ -164,10 +166,6 @@ class CreateEnterprise &lt; Task
164 166 {:message => _('%{requestor} wants to create enterprise %{subject}.')}
165 167 end
166 168  
167   - def reject_details
168   - true
169   - end
170   -
171 169 def task_created_message
172 170 _('Your request for registering enterprise "%{enterprise}" at %{environment} was just received. It will be reviewed by the validator organization of your choice, according to its methods and criteria.
173 171  
... ...
app/models/email_activation.rb
1 1 class EmailActivation < Task
2 2  
3 3 validates_presence_of :requestor_id, :target_id
  4 +
  5 + validates :requestor, kind_of: {kind: Person}
  6 + validates :target, kind_of: {kind: Environment}
  7 +
4 8 validate :already_requested, :on => :create
5 9  
6 10 alias :environment :target
7 11 alias :person :requestor
8 12  
9 13 def already_requested
10   - if !self.requestor.nil? && self.requestor.user.email_activation_pending?
  14 + if !self.requestor.nil? && self.requestor.person? && self.requestor.user.email_activation_pending?
11 15 self.errors.add(:base, _('You have already requested activation of your mailbox.'))
12 16 end
13 17 end
... ...
app/models/email_template.rb 0 → 100644
... ... @@ -0,0 +1,50 @@
  1 +class EmailTemplate < ActiveRecord::Base
  2 +
  3 + belongs_to :owner, :polymorphic => true
  4 +
  5 + attr_accessible :template_type, :subject, :body, :owner, :name
  6 +
  7 + validates_presence_of :name
  8 +
  9 + validates :name, uniqueness: { scope: [:owner_type, :owner_id] }
  10 +
  11 + validates :template_type, uniqueness: { scope: [:owner_type, :owner_id] }, if: :unique_by_type?
  12 +
  13 + def parsed_body(params)
  14 + @parsed_body ||= parse(body, params)
  15 + end
  16 +
  17 + def parsed_subject(params)
  18 + @parsed_subject ||= parse(subject, params)
  19 + end
  20 +
  21 + def self.available_types
  22 + {
  23 + :task_rejection => {:description => _('Task Rejection'), :owner_type => Profile},
  24 + :task_acceptance => {:description => _('Task Acceptance'), :owner_type => Profile},
  25 + :organization_members => {:description => _('Organization Members'), :owner_type => Profile},
  26 + :user_activation => {:description => _('User Activation'), :unique => true, :owner_type => Environment},
  27 + :user_change_password => {:description => _('Change User Password'), :unique => true, :owner_type => Environment}
  28 + }
  29 + end
  30 +
  31 + def available_types
  32 + HashWithIndifferentAccess.new EmailTemplate.available_types.select {|k, v| owner.kind_of?(v[:owner_type])}
  33 + end
  34 +
  35 + def type_description
  36 + available_types.fetch(template_type, {})[:description]
  37 + end
  38 +
  39 + def unique_by_type?
  40 + available_types.fetch(template_type, {})[:unique]
  41 + end
  42 +
  43 + protected
  44 +
  45 + def parse(source, params)
  46 + template = Liquid::Template.parse(source)
  47 + template.render(HashWithIndifferentAccess.new(params))
  48 + end
  49 +
  50 +end
... ...
app/models/enterprise.rb
... ... @@ -15,12 +15,15 @@ class Enterprise &lt; Organization
15 15  
16 16 N_('Enterprise')
17 17  
18   - has_many :products, :foreign_key => :profile_id, :dependent => :destroy, :order => 'name ASC'
  18 + acts_as_trackable after_add: proc{ |p, t| notify_activity t }
  19 +
  20 + has_many :products, :foreign_key => :profile_id, :dependent => :destroy
  21 + has_many :product_categories, :through => :products
19 22 has_many :inputs, :through => :products
20 23 has_many :production_costs, :as => :owner
21 24  
22 25 has_many :favorite_enterprise_people
23   - has_many :fans, through: :favorite_enterprise_people, source: :person
  26 + has_many :fans, source: :person, through: :favorite_enterprise_people
24 27  
25 28 def product_categories
26 29 ProductCategory.by_enterprise(self)
... ... @@ -194,10 +197,6 @@ class Enterprise &lt; Organization
194 197 true
195 198 end
196 199  
197   - def activities
198   - Scrap.find_by_sql("SELECT id, updated_at, 'Scrap' AS klass FROM scraps WHERE scraps.receiver_id = #{self.id} AND scraps.scrap_id IS NULL UNION SELECT id, updated_at, 'ActionTracker::Record' AS klass FROM action_tracker WHERE action_tracker.target_id = #{self.id} UNION SELECT action_tracker.id, action_tracker.updated_at, 'ActionTracker::Record' AS klass FROM action_tracker INNER JOIN articles ON action_tracker.target_id = articles.id WHERE articles.profile_id = #{self.id} AND action_tracker.target_type = 'Article' ORDER BY updated_at DESC")
199   - end
200   -
201 200 def catalog_url
202 201 { :profile => identifier, :controller => 'catalog'}
203 202 end
... ... @@ -206,4 +205,9 @@ class Enterprise &lt; Organization
206 205 ''
207 206 end
208 207  
  208 + def followed_by? person
  209 + super or self.fans.where(id: person.id).count > 0
  210 + end
  211 +
  212 +
209 213 end
... ...
app/models/enterprise_activation.rb
... ... @@ -8,6 +8,8 @@ class EnterpriseActivation &lt; Task
8 8  
9 9 validates_presence_of :enterprise
10 10  
  11 + validates :target, kind_of: {kind: Enterprise}
  12 +
11 13 def perform
12 14 self.enterprise.enable self.requestor
13 15 end
... ...
app/models/enterprise_homepage.rb
... ... @@ -35,4 +35,8 @@ class EnterpriseHomepage &lt; Article
35 35 false
36 36 end
37 37  
  38 + def can_display_media_panel?
  39 + true
  40 + end
  41 +
38 42 end
... ...
app/models/environment.rb
... ... @@ -3,7 +3,17 @@
3 3 # domains.
4 4 class Environment < ActiveRecord::Base
5 5  
6   - attr_accessible :name, :is_default, :signup_welcome_text_subject, :signup_welcome_text_body, :terms_of_use, :message_for_disabled_enterprise, :news_amount_by_folder, :default_language, :languages, :description, :organization_approval_method, :enabled_plugins, :enabled_features, :redirection_after_login, :redirection_after_signup, :contact_email, :theme, :reports_lower_bound, :noreply_email, :signup_welcome_screen_body, :members_whitelist_enabled, :members_whitelist, :highlighted_news_amount, :portal_news_amount
  6 + attr_accessible :name, :is_default, :signup_welcome_text_subject,
  7 + :signup_welcome_text_body, :terms_of_use,
  8 + :message_for_disabled_enterprise, :news_amount_by_folder,
  9 + :default_language, :languages, :description,
  10 + :organization_approval_method, :enabled_plugins,
  11 + :enabled_features, :redirection_after_login,
  12 + :redirection_after_signup, :contact_email, :theme,
  13 + :reports_lower_bound, :noreply_email,
  14 + :signup_welcome_screen_body, :members_whitelist_enabled,
  15 + :members_whitelist, :highlighted_news_amount,
  16 + :portal_news_amount, :date_format
7 17  
8 18 has_many :users
9 19  
... ... @@ -11,14 +21,23 @@ class Environment &lt; ActiveRecord::Base
11 21  
12 22 has_many :tasks, :dependent => :destroy, :as => 'target'
13 23 has_many :search_terms, :as => :context
  24 + has_many :email_templates, :foreign_key => :owner_id
14 25  
15 26 IDENTIFY_SCRIPTS = /(php[0-9s]?|[sp]htm[l]?|pl|py|cgi|rb)/
16 27  
  28 + validates_inclusion_of :date_format,
  29 + :in => [ 'numbers_with_year', 'numbers',
  30 + 'month_name_with_year', 'month_name',
  31 + 'past_time'],
  32 + :if => :date_format
  33 +
17 34 def self.verify_filename(filename)
18 35 filename += '.txt' if File.extname(filename) =~ IDENTIFY_SCRIPTS
19 36 filename
20 37 end
21 38  
  39 + NUMBER_OF_BOXES = 4
  40 +
22 41 PERMISSIONS['Environment'] = {
23 42 'view_environment_admin_panel' => N_('View environment admin panel'),
24 43 'edit_environment_features' => N_('Edit environment features'),
... ... @@ -27,10 +46,12 @@ class Environment &lt; ActiveRecord::Base
27 46 'manage_environment_roles' => N_('Manage environment roles'),
28 47 'manage_environment_validators' => N_('Manage environment validators'),
29 48 'manage_environment_users' => N_('Manage environment users'),
  49 + 'manage_environment_organizations' => N_('Manage environment organizations'),
30 50 'manage_environment_templates' => N_('Manage environment templates'),
31 51 'manage_environment_licenses' => N_('Manage environment licenses'),
32 52 'manage_environment_trusted_sites' => N_('Manage environment trusted sites'),
33 53 'edit_appearance' => N_('Edit appearance'),
  54 + 'manage_email_templates' => N_('Manage Email Templates'),
34 55 }
35 56  
36 57 module Roles
... ... @@ -72,7 +93,8 @@ class Environment &lt; ActiveRecord::Base
72 93 'edit_profile_design',
73 94 'manage_products',
74 95 'manage_friends',
75   - 'perform_task'
  96 + 'perform_task',
  97 + 'view_tasks'
76 98 ]
77 99 )
78 100 end
... ... @@ -108,6 +130,7 @@ class Environment &lt; ActiveRecord::Base
108 130 'disable_select_city_for_contact' => _('Disable state/city select for contact form'),
109 131 'disable_contact_person' => _('Disable contact for people'),
110 132 'disable_contact_community' => _('Disable contact for groups/communities'),
  133 + 'forbid_destroy_profile' => _('Forbid users of removing profiles'),
111 134  
112 135 'products_for_enterprises' => _('Enable products for enterprises'),
113 136 'enterprise_registration' => _('Enterprise registration'),
... ... @@ -147,7 +170,8 @@ class Environment &lt; ActiveRecord::Base
147 170 'site_homepage' => _('Redirects the user to the environment homepage.'),
148 171 'user_profile_page' => _('Redirects the user to his profile page.'),
149 172 'user_homepage' => _('Redirects the user to his homepage.'),
150   - 'user_control_panel' => _('Redirects the user to his control panel.')
  173 + 'user_control_panel' => _('Redirects the user to his control panel.'),
  174 + 'custom_url' => _('Specify the URL to redirect to:'),
151 175 }
152 176 end
153 177 validates_inclusion_of :redirection_after_login, :in => Environment.login_redirection_options.keys, :allow_nil => true
... ... @@ -172,7 +196,7 @@ class Environment &lt; ActiveRecord::Base
172 196 acts_as_having_boxes
173 197  
174 198 after_create do |env|
175   - 3.times do
  199 + NUMBER_OF_BOXES.times do
176 200 env.boxes << Box.new
177 201 end
178 202  
... ... @@ -228,6 +252,9 @@ class Environment &lt; ActiveRecord::Base
228 252 # store the Environment settings as YAML-serialized Hash.
229 253 acts_as_having_settings :field => :settings
230 254  
  255 + # introduce and explain to users something about the signup
  256 + settings_items :signup_intro, :type => String
  257 +
231 258 # the environment's terms of use: every user must accept them before registering.
232 259 settings_items :terms_of_use, :type => String
233 260  
... ... @@ -262,7 +289,20 @@ class Environment &lt; ActiveRecord::Base
262 289 settings_items :activation_blocked_text, :type => String
263 290 settings_items :message_for_disabled_enterprise, :type => String,
264 291 :default => _('This enterprise needs to be enabled.')
265   - settings_items :location, :type => String
  292 +
  293 + settings_items :contact_phone, type: String
  294 + settings_items :address, type: String
  295 + settings_items :city, type: String
  296 + settings_items :state, type: String
  297 + settings_items :country_name, type: String
  298 + settings_items :lat, type: Float
  299 + settings_items :lng, type: Float
  300 + settings_items :postal_code, type: String
  301 + settings_items :location, type: String
  302 +
  303 + alias_method :zip_code=, :postal_code
  304 + alias_method :zip_code, :postal_code
  305 +
266 306 settings_items :layout_template, :type => String, :default => 'default'
267 307 settings_items :homepage, :type => String
268 308 settings_items :description, :type => String, :default => '<div style="text-align: center"><a href="http://noosfero.org/"><img src="/images/noosfero-network.png" alt="Noosfero"/></a></div>'
... ... @@ -306,6 +346,9 @@ class Environment &lt; ActiveRecord::Base
306 346  
307 347 settings_items :signup_welcome_screen_body, :type => String
308 348  
  349 + #Captcha settings
  350 + settings_items :api_captcha_settings, :type => ActiveSupport::HashWithIndifferentAccess, :default => {}
  351 +
309 352 def has_custom_welcome_screen?
310 353 settings[:signup_welcome_screen_body].present?
311 354 end
... ... @@ -337,6 +380,16 @@ class Environment &lt; ActiveRecord::Base
337 380 self.save!
338 381 end
339 382  
  383 + def enable_all_plugins
  384 + Noosfero::Plugin.available_plugin_names.each do |plugin|
  385 + plugin_name = plugin.to_s + "Plugin"
  386 + unless self.enabled_plugins.include?(plugin_name)
  387 + self.enabled_plugins += [plugin_name]
  388 + end
  389 + end
  390 + self.save!
  391 + end
  392 +
340 393 # Disables a feature identified by its name
341 394 def disable(feature, must_save=true)
342 395 self.settings["#{feature}_enabled".to_sym] = false
... ... @@ -439,7 +492,8 @@ class Environment &lt; ActiveRecord::Base
439 492 end
440 493  
441 494 def custom_person_fields
442   - self.settings[:custom_person_fields].nil? ? {} : self.settings[:custom_person_fields]
  495 + self.settings[:custom_person_fields] = {} if self.settings[:custom_person_fields].nil?
  496 + self.settings[:custom_person_fields]
443 497 end
444 498  
445 499 def custom_person_fields=(values)
... ... @@ -737,8 +791,8 @@ class Environment &lt; ActiveRecord::Base
737 791 end
738 792  
739 793 def is_default_template?(template)
740   - is_default = template == community_default_template
741   - is_default = is_default || template == person_default_template
  794 + is_default = template == community_default_template
  795 + is_default = is_default || template == person_default_template
742 796 is_default = is_default || template == enterprise_default_template
743 797 is_default
744 798 end
... ... @@ -952,6 +1006,10 @@ class Environment &lt; ActiveRecord::Base
952 1006 self.licenses.any?
953 1007 end
954 1008  
  1009 + def to_liquid
  1010 + HashWithIndifferentAccess.new :name => name
  1011 + end
  1012 +
955 1013 private
956 1014  
957 1015 def default_language_available
... ...
app/models/event.rb
... ... @@ -3,13 +3,14 @@ require &#39;builder&#39;
3 3  
4 4 class Event < Article
5 5  
6   - attr_accessible :start_date, :end_date, :link, :address
  6 + attr_accessible :start_date, :end_date, :link, :address, :presenter
7 7  
8 8 def self.type_name
9 9 _('Event')
10 10 end
11 11  
12 12 settings_items :address, :type => :string
  13 + settings_items :presenter, :type => :string
13 14  
14 15 def link=(value)
15 16 self.setting[:link] = maybe_add_http(value)
... ... @@ -23,7 +24,7 @@ class Event &lt; Article
23 24  
24 25 def initialize(*args)
25 26 super(*args)
26   - self.start_date ||= Date.today
  27 + self.start_date ||= DateTime.now
27 28 end
28 29  
29 30 validates_presence_of :title, :start_date
... ... @@ -35,7 +36,7 @@ class Event &lt; Article
35 36 end
36 37  
37 38 scope :by_day, lambda { |date|
38   - { :conditions => ['start_date = :date AND end_date IS NULL OR (start_date <= :date AND end_date >= :date)', {:date => date}],
  39 + { :conditions => [' start_date >= :start_date AND start_date <= :end_date AND end_date IS NULL OR (start_date <= :end_date AND end_date >= :start_date)', {:start_date => date.beginning_of_day, :end_date => date.end_of_day}],
39 40 :order => 'start_date ASC'
40 41 }
41 42 }
... ... @@ -80,7 +81,7 @@ class Event &lt; Article
80 81  
81 82 def self.date_range(year, month)
82 83 if year.nil? || month.nil?
83   - today = Date.today
  84 + today = DateTime.now
84 85 year = today.year
85 86 month = today.month
86 87 else
... ... @@ -88,7 +89,7 @@ class Event &lt; Article
88 89 month = month.to_i
89 90 end
90 91  
91   - first_day = Date.new(year, month, 1)
  92 + first_day = DateTime.new(year, month, 1)
92 93 last_day = first_day + 1.month - 1.day
93 94  
94 95 first_day..last_day
... ... @@ -98,51 +99,23 @@ class Event &lt; Article
98 99 start_date..(end_date||start_date)
99 100 end
100 101  
101   - # FIXME this shouldn't be needed
102   - include ActionView::Helpers::TagHelper
103   - include ActionView::Helpers::UrlHelper
104   - include DatesHelper
  102 + def first_paragraph
  103 + paragraphs = Nokogiri::HTML.fragment(self.body).css('p')
  104 + paragraphs.empty? ? '' : paragraphs.first.to_html
  105 + end
105 106  
106 107 def to_html(options = {})
  108 + event = self
  109 + format = options[:format]
107 110  
108   - result = ''
109   - html = ::Builder::XmlMarkup.new(:target => result)
110   -
111   - html.div(:class => 'event-info' ) {
112   - html.ul(:class => 'event-data' ) {
113   - html.li(:class => 'event-dates' ) {
114   - html.span _('When:')
115   - html.text! show_period(start_date, end_date)
116   - } if start_date.present? || end_date.present?
117   - html.li {
118   - html.span _('URL:')
119   - html.a(self.link || "", 'href' => self.link || "")
120   - } if self.link.present?
121   - html.li {
122   - html.span _('Address:')
123   - html.text! self.address || ""
124   - } if self.address.present?
125   - }
126   -
127   - # TODO: some good soul, please clean this ugly hack:
128   - if self.body
129   - html.div('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', :class => 'event-description')
130   - end
131   - }
132   -
133   - if self.body
134   - if options[:format] == 'short'
135   - result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', display_short_format(self))
136   - else
137   - result.sub!('_____XXXX_DESCRIPTION_GOES_HERE_XXXX_____', self.body)
138   - end
  111 + proc do
  112 + render :file => 'content_viewer/event_page', :locals => { :event => event,
  113 + :format => format }
139 114 end
140   -
141   - result
142 115 end
143 116  
144 117 def duration
145   - ((self.end_date || self.start_date) - self.start_date).to_i
  118 + (((self.end_date || self.start_date) - self.start_date).to_i/60/60/24)
146 119 end
147 120  
148 121 alias_method :article_lead, :lead
... ... @@ -162,6 +135,10 @@ class Event &lt; Article
162 135 true
163 136 end
164 137  
  138 + def can_display_media_panel?
  139 + true
  140 + end
  141 +
165 142 include Noosfero::TranslatableContent
166 143 include MaybeAddHttp
167 144  
... ...
app/models/favorite_enterprise_person.rb
1 1 class FavoriteEnterprisePerson < ActiveRecord::Base
2 2  
3   - self.table_name = :favorite_enteprises_people
  3 + attr_accessible :person, :enterprise
  4 +
  5 + track_actions :favorite_enterprise, :after_create, keep_params: [:enterprise_name, :enterprise_url], if: proc{ |f| f.is_trackable? }
4 6  
5 7 belongs_to :enterprise
6 8 belongs_to :person
7 9  
  10 + protected
  11 +
  12 + def is_trackable?
  13 + self.enterprise.public?
  14 + end
  15 +
  16 + def enterprise_name
  17 + self.enterprise.short_name(nil)
  18 + end
  19 + def enterprise_url
  20 + self.enterprise.url
  21 + end
  22 +
8 23 end
... ...
app/models/featured_products_block.rb
... ... @@ -20,6 +20,10 @@ class FeaturedProductsBlock &lt; Block
20 20 _('Featured Products')
21 21 end
22 22  
  23 + def self.pretty_name
  24 + _('Featured Products')
  25 + end
  26 +
23 27 def products
24 28 Product.find(self.product_ids) || []
25 29 end
... ...
app/models/feed_reader_block.rb
... ... @@ -40,6 +40,10 @@ class FeedReaderBlock &lt; Block
40 40 _('Feed reader')
41 41 end
42 42  
  43 + def self.pretty_name
  44 + _('Feed Reader')
  45 + end
  46 +
43 47 def help
44 48 _('This block can be used to list the latest new from any site you want. You just need to inform the address of a RSS feed.')
45 49 end
... ...
app/models/forum.rb
... ... @@ -3,11 +3,11 @@ class Forum &lt; Folder
3 3 acts_as_having_posts :order => 'updated_at DESC'
4 4 include PostsLimit
5 5  
6   - attr_accessible :has_terms_of_use, :terms_of_use, :allows_members_to_create_topics
  6 + attr_accessible :has_terms_of_use, :terms_of_use, :topic_creation
7 7  
8 8 settings_items :terms_of_use, :type => :string, :default => ""
9 9 settings_items :has_terms_of_use, :type => :boolean, :default => false
10   - settings_items :allows_members_to_create_topics, :type => :boolean, :default => false
  10 + settings_items :topic_creation, :type => :string, :default => 'self'
11 11 has_and_belongs_to_many :users_with_agreement, :class_name => 'Person', :join_table => 'terms_forum_people'
12 12  
13 13 before_save do |forum|
... ... @@ -33,6 +33,23 @@ class Forum &lt; Folder
33 33 _('An internet forum, also called message board, where discussions can be held.')
34 34 end
35 35  
  36 + module TopicCreation
  37 + BASE = ActiveSupport::OrderedHash.new
  38 + BASE['users'] = _('Logged users')
  39 +
  40 + PERSON = ActiveSupport::OrderedHash.new
  41 + PERSON['self'] = _('Me')
  42 + PERSON['related'] = _('Friends')
  43 +
  44 + GROUP = ActiveSupport::OrderedHash.new
  45 + GROUP['self'] = _('Administrators')
  46 + GROUP['related'] = _('Members')
  47 +
  48 + def self.general_options(forum)
  49 + forum.profile.person? ? PERSON.merge(BASE) : GROUP.merge(BASE)
  50 + end
  51 + end
  52 +
36 53 include ActionView::Helpers::TagHelper
37 54 def to_html(options = {})
38 55 proc do
... ... @@ -69,11 +86,17 @@ class Forum &lt; Folder
69 86 self.users_with_agreement.exists? user
70 87 end
71 88  
72   - def can_create_topic?(user, profile)
73   - return profile.community? && profile.members.include?(user) && self.allows_members_to_create_topics
  89 + def can_create_topic?(user)
  90 + return true if user == profile || profile.admins.include?(user) || profile.environment.admins.include?(user)
  91 + case topic_creation
  92 + when 'related'
  93 + profile.person? ? profile.friends.include?(user) : profile.members.include?(user)
  94 + when 'users'
  95 + user.present?
  96 + end
74 97 end
75 98  
76 99 def allow_create?(user)
77   - super || can_create_topic?(user, profile)
  100 + super || can_create_topic?(user)
78 101 end
79 102 end
... ...
app/models/highlights_block.rb
... ... @@ -12,6 +12,7 @@ class HighlightsBlock &lt; Block
12 12 block.images.each do |i|
13 13 i[:image_id] = i[:image_id].to_i
14 14 i[:position] = i[:position].to_i
  15 + i[:address] = Noosfero.root + i[:address] unless Noosfero.root.nil?
15 16 begin
16 17 file = UploadedFile.find(i[:image_id])
17 18 i[:image_src] = file.public_filename
... ... @@ -22,12 +23,20 @@ class HighlightsBlock &lt; Block
22 23 end
23 24  
24 25 def self.description
25   - _('Highlights')
  26 + _('Creates image slideshow')
26 27 end
27 28  
28 29 def featured_images
29   - block_images = images.select{|i| !i[:image_src].nil? }.sort { |x, y| x[:position] <=> y[:position] }
30   - shuffle ? block_images.shuffle : block_images
  30 + images = get_images
  31 + shuffle ? images.shuffle : images
  32 + end
  33 +
  34 + def get_images
  35 + images.select do |i|
  36 + !i[:image_src].nil?
  37 + end.sort do |x, y|
  38 + x[:position] <=> y[:position]
  39 + end
31 40 end
32 41  
33 42 def content(args={})
... ...
app/models/image.rb
... ... @@ -23,7 +23,7 @@ class Image &lt; ActiveRecord::Base
23 23  
24 24 postgresql_attachment_fu
25 25  
26   - attr_accessible :uploaded_data
  26 + attr_accessible :uploaded_data, :label
27 27  
28 28 def current_data
29 29 File.file?(full_filename) ? File.read(full_filename) : nil
... ...
app/models/invitation.rb
... ... @@ -6,6 +6,8 @@ class Invitation &lt; Task
6 6  
7 7 validates_presence_of :target_id, :if => Proc.new{|invite| invite.friend_email.blank?}
8 8  
  9 + validates :requestor, kind_of: {kind: Person}
  10 +
9 11 validates_presence_of :friend_email, :if => Proc.new{|invite| invite.target_id.blank?}
10 12 validates_format_of :friend_email, :with => Noosfero::Constants::EMAIL_FORMAT, :if => Proc.new{|invite| invite.target_id.blank?}
11 13  
... ... @@ -34,7 +36,7 @@ class Invitation &lt; Task
34 36 end
35 37  
36 38 def not_invite_yourself
37   - email = friend ? friend.user.email : friend_email
  39 + email = friend && friend.person? ? friend.user.email : friend_email
38 40 if person && email && person.user.email == email
39 41 self.errors.add(:base, _("You can't invite youself"))
40 42 end
... ... @@ -136,7 +138,11 @@ class Invitation &lt; Task
136 138 end
137 139  
138 140 def environment
139   - self.requestor.environment
  141 + if self.requestor
  142 + self.requestor.environment
  143 + else
  144 + nil
  145 + end
140 146 end
141 147  
142 148 end
... ...
app/models/link_list_block.rb
... ... @@ -55,6 +55,10 @@ class LinkListBlock &lt; Block
55 55 _('This block can be used to create a menu of links. You can add, remove and update the links as you wish.')
56 56 end
57 57  
  58 + def self.pretty_name
  59 + _('Link list')
  60 + end
  61 +
58 62 def content(args={})
59 63 block_title(title) +
60 64 content_tag('ul',
... ...