Commit 87ccdfde777a2f6d1ef511c6a052ae68e298fee9
Exists in
staging
Merge branch 'master' into staging
Showing
2490 changed files
with
297841 additions
and
297897 deletions
Show diff stats
Too many changes.
To preserve performance only 100 of 2490 files displayed.
.gitlab-ci.yml
... | ... | @@ -59,18 +59,18 @@ selenium-6: |
59 | 59 | # NOOSFERO_BUNDLE_OPTS=install makes migrations fails |
60 | 60 | # probably because of rubygems-integration |
61 | 61 | plugins-1: |
62 | - script: SLICE=1/5 bundle exec rake test:noosfero_plugins | |
62 | + script: SLICE=1/5 bundle exec rake test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | |
63 | 63 | stage: all-tests |
64 | 64 | plugins-2: |
65 | - script: SLICE=2/5 bundle exec rake test:noosfero_plugins | |
65 | + script: SLICE=2/5 bundle exec rake test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | |
66 | 66 | stage: all-tests |
67 | 67 | plugins-3: |
68 | - script: SLICE=3/5 bundle exec rake test:noosfero_plugins | |
68 | + script: SLICE=3/5 bundle exec rake test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | |
69 | 69 | stage: all-tests |
70 | 70 | plugins-4: |
71 | - script: SLICE=4/5 bundle exec rake test:noosfero_plugins | |
71 | + script: SLICE=4/5 bundle exec rake test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | |
72 | 72 | stage: all-tests |
73 | 73 | plugins-5: |
74 | - script: SLICE=5/5 bundle exec rake test:noosfero_plugins | |
74 | + script: SLICE=5/5 bundle exec rake test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | |
75 | 75 | stage: all-tests |
76 | 76 | ... | ... |
.travis.yml
AUTHORS.md
... | ... | @@ -8,38 +8,42 @@ noosfero, that's not a problem). |
8 | 8 | Developers |
9 | 9 | ========== |
10 | 10 | |
11 | -Ábner Silva de Oliveira <abner.oliveira@serpro.gov.br> | |
12 | 11 | Alan Freihof Tygel <alantygel@gmail.com> |
12 | +Alessandro Caetano <alesasndro.caetanob@gmail.com> | |
13 | +Alessandro Caetano <alessandro.caetanob@gmail.com> | |
13 | 14 | Alessandro Palmeira <alessandro.palmeira@gmail.com> |
15 | +Alex Campelo <campelo.al1@gmail.com> | |
14 | 16 | Alexandre Barbosa <alexandreab@live.com> |
15 | 17 | Alexandre Torres <alexandrekry@gmail.com> |
16 | -Alex Campelo <campelo.al1@gmail.com> | |
17 | -Álvaro Fernando <alvarofernandoms@gmail.com> | |
18 | +Alipio muñiz <alipio@ecoalternative.net> | |
18 | 19 | Ana Losnak <analosnak@gmail.com> |
19 | 20 | Ana Paula Vargas <anapaulavnoronha@gmail.com> |
20 | 21 | Andre Bedran <bedran.fleck@gmail.com> |
21 | -André Guedes <andrebsguedes@gmail.com> | |
22 | 22 | Andrey Aleksanyants <aaleksanyants@yahoo.com> |
23 | +André Guedes <andrebsguedes@gmail.com> | |
23 | 24 | Antonio Terceiro <terceiro@colivre.coop.br> |
24 | 25 | Arthur Del Esposte <arthurmde@gmail.com> |
26 | +Arthur Jahn <stutrzbecher@gmail.com> | |
27 | +Artur Bersan de Faria <arturbersan@gmail.com> | |
25 | 28 | Athos Ribeiro <athoscribeiro@gmail.com> |
26 | -Aurelio A. Heckert <aurelio@colivre.coop.br> | |
29 | +Aurelio A. Heckert <aurium@colivre.coop.br> | |
30 | +Becca Cook <b.cook28@gmail.com> | |
27 | 31 | Braulio Bhavamitra <braulio@eita.org.br> |
28 | 32 | Brenddon Gontijo <brenddongontijo@msn.com> |
29 | 33 | Caio Formiga <caio.formiga@gmail.com> |
30 | -Caio Salgado <caio.csalgado@gmail.com> | |
31 | 34 | Caio SBA <caio@colivre.coop.br> |
35 | +Caio Salgado <caio.csalgado@gmail.com> | |
32 | 36 | Caio Tiago Oliveira <caiotiago@colivre.coop.br> |
33 | 37 | Carlos Andre de Souza <carlos.andre.souza@msn.com> |
34 | 38 | Carlos Morais <carlos88morais@gmail.com> |
35 | 39 | Carlos Purificacao <carloseugenio@gmail.com> |
36 | 40 | Christophe DANIEL <papaeng@gmail.com> |
37 | -Daniela Feitosa <alessandro.palmeira@gmail.com> | |
38 | 41 | Daniel Alves <danpaulalves@gmail.com> |
39 | -Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> | |
40 | 42 | Daniel Bucher <daniel.bucher88@gmail.com> |
41 | 43 | Daniel Cunha <daniel@colivre.coop.br> |
44 | +Daniel Henrique <danielhmarinho@gmail.com> | |
42 | 45 | Daniel Tygel <dtygel@eita.org.br> |
46 | +Daniela Soares Feitosa <danielafeitosa@colivre.coop.br> | |
43 | 47 | David Carlos <ddavidcarlos1392@gmail.com> |
44 | 48 | Diego Araujo <diegoamc90@gmail.com> |
45 | 49 | Dylan Guedes <djmgguedes@gmail.com> |
... | ... | @@ -48,76 +52,91 @@ Eduardo Passos <eduardosteps@gmail.com> |
48 | 52 | Eduardo Tourinho Edington <eduardo.edington@serpro.gov.br> |
49 | 53 | Eduardo Vital <vitaldu@gmail.com> |
50 | 54 | Evandro Magalhaes Leite Junior <evandro.leite@serpro.gov.br> |
51 | -Fabio Teixeira <fabio1079@gmail.com> | |
52 | 55 | FAMMA TV NOTICIAS MEDIOS DE CO <revistafammatvmusic.oficial@gmail.com> |
56 | +Fabio Teixeira <fabio1079@gmail.com> | |
57 | +Fagner Rodrigues <fagner128@gmail.com> | |
53 | 58 | Fernanda Lopes <nanda.listas+psl@gmail.com> |
54 | 59 | Filipe Ribeiro <firibeiro77@live.com> |
55 | 60 | Francisco Marcelo de Araújo Lima Júnior <francisco.lima-junior@serpro.gov.br> |
56 | -Gabriela Navarro <navarro1703@gmail.com> | |
57 | 61 | Gabriel Silva <gabriel93.silva@gmail.com> |
62 | +Gabriel Silva <grabriel93.silva@gmail.com> | |
63 | +Gabriela Navarro <navarro1703@gmail.com> | |
58 | 64 | Gonzalo Exequiel Pedone <hipersayan.x@gmail.com> |
59 | 65 | Grazieno Pellegrino <grazieno@gmail.com> |
60 | 66 | Guilherme C. Muniz <guilherme.cmuniz@gmail.com> |
61 | 67 | Guilherme Rojas <guilhermehrojas@gmail.com> |
68 | +Gustavo Cavalcante <gustavo.cavalcante.oliveira@live.com> | |
62 | 69 | Gustavo Coelho <gust.rod.coelho@gmail.com> |
70 | +Gustavo Jaruga <darkshades@gmail.com> | |
63 | 71 | Gustavo Jaruga <darksshades@gmail.com> |
64 | 72 | Hebert Douglas <hebertdougl@gmail.com> |
65 | 73 | Hugo Melo <hugo@riseup.net> |
74 | +Iago Rodrigues <iago006@hotmailcom> | |
66 | 75 | Iolane Andrade <andrade.icaa@gmail.com> |
76 | +Iryna Pruitt <jdpruitt2807@prodigy.net> | |
67 | 77 | Isaac Canan <isaac@intelletto.com.br> |
68 | 78 | Italo Valcy <italo@dcc.ufba.br> |
79 | +Izharul Haq <atoz.chevara.2013@gmail.com> | |
69 | 80 | Jefferson Fernandes <jeffs.fernandes@gmail.com> |
70 | -Jérôme Jutteau <j.jutteau@gmail.com> | |
71 | -Jéssica Cristina <jessica.cris1127@gmail.com> | |
72 | -João Machini | |
73 | -João M. M. da Silva <jaodsilv@linux.ime.usp.br> | |
74 | 81 | Joenio Costa <joenio@colivre.coop.br> |
75 | -Josef Spillner <josef.spillner@tu-dresden.de> | |
82 | +Joenio Costa <joenio@joenio.me> | |
76 | 83 | Jose Pedro <1jpsneto@gmail.com> |
84 | +Josef Spillner <josef.spillner@tu-dresden.de> | |
85 | +João M. M. da Silva <jaodsilv@linux.ime.usp.br> | |
86 | +João Machini | |
77 | 87 | Junior Silva <juniorsilva1001@gmail.com> |
88 | +Jérôme Jutteau <j.jutteau@gmail.com> | |
89 | +Jéssica Cristina <jessica.cris1127@gmail.com> | |
90 | +Karine Valença <valenca.karine@gmail.com> | |
78 | 91 | Keilla Menezes <keilla@colivre.coop.br> |
79 | 92 | Larissa Reis <larissa@colivre.coop.br> |
80 | 93 | Leandro Alves <leandrosustenido@gmail.com> |
81 | 94 | Leandro Nunes dos Santos <leandro.santos@serpro.gov.br> |
82 | 95 | Leandro Veloso <leandrovelosorodrigues@gmail.com> |
83 | 96 | LinguÁgil 2010 <linguagil.bahia@gmail.com> |
97 | +Luan Guimarães <guimaraesluan@me.com> | |
84 | 98 | Lucas Couto <loc.unb@gmail.com> |
85 | 99 | Lucas Kanashiro <kanashiro.duarte@gmail.com> |
86 | 100 | Lucas Melo <lucaspradomelo@gmail.com> |
101 | +Lucas Moura <lucas.moura128@gmail.com> | |
102 | +Lucas Severo <lucassalves65@gmail.com> | |
87 | 103 | Luciano Prestes Cavalcanti <lucianopcbr@gmail.com> |
88 | 104 | Luis David Aguilar Carlos <ludwig9003@gmail.com> |
89 | 105 | Luiz Fernando de Freitas Matos <luiz@luizff.matos@gmail.com> |
90 | 106 | Luiz Matos <luizff.matos@gmail.com> |
107 | +M for Momo <mo@rtnp.org> | |
91 | 108 | Macartur de Sousa <macartur.sc@gmail.com> |
92 | 109 | Marcelo Júnior <maljunior@gmail.com> |
93 | 110 | Marcos Ramos <ms.ramos@outlook.com> |
94 | 111 | Marcos Ronaldo <marcos.rpj2@gmail.com> |
95 | -María Vecino <mariavecino@ecoalternative.net> | |
96 | 112 | Mariel Zasso <noosfero-br@listas.softwarelivre.org> |
97 | 113 | Martín Olivera <molivera@solar.org.ar> |
114 | +María Vecino <mariavecino@ecoalternative.net> | |
98 | 115 | Matheus Faria <matheus.sousa.faria@gmail.com> |
116 | +Matheus Miranda <matheusmirandalacerda@gmail.com> | |
99 | 117 | Maurilio Atila <cabelotaina@gmail.com> |
100 | 118 | Melissa Wen <melissa.srw@gmail.com> |
101 | -M for Momo <mo@rtnp.org> | |
102 | 119 | Michal Čihař <michal@cihar.com> |
103 | 120 | Michel Felipe de Oliveira Ferreira <michel.ferreira@serpro.gov.br> |
104 | 121 | Moises Machado <moises@colivre.coop.br> |
105 | -Naíla Alves <naila@colivre.coop.br> | |
122 | +Murilo Duarte <muriloduartegoncalves@hotmail.com> | |
106 | 123 | Nanda Lopes <nanda.listas+psl@gmail.com> |
124 | +Naíla Alves <naila@colivre.coop.br> | |
107 | 125 | Niemand Jedermann <predatorix@web.de> |
108 | 126 | Omar Junior <omarroinuj@gmail.com> |
109 | 127 | Parley Martins <parleypachecomartins@gmail.com> |
110 | 128 | Paulo Meirelles <paulo@softwarelivre.org> |
111 | -Pedro de Lyra <pedrodelyra@gmail.com> | |
129 | +Paulo Tada <paulohtfs@gmail.com> | |
112 | 130 | Pedro Leal |
131 | +Pedro de Lyra <pedrodelyra@gmail.com> | |
113 | 132 | Phillip Rohmberger <rohmberger@hotmail.de> |
114 | -Rafael de Souza Queiroz <querafael@live.com> | |
115 | 133 | Rafael Gomes <rafaelgomes@techfree.com.br> |
116 | 134 | Rafael Martins <rmmartins@gmail.com> |
117 | 135 | Rafael Reggiani Manzo <rr.manzo@gmail.com> |
136 | +Rafael de Souza Queiroz <querafael@live.com> | |
118 | 137 | Raphaël Rousseau <raph@r4f.org> |
119 | -Raquel Lira <raquel.lira@gmail.com> | |
120 | 138 | Raquel <rcordioli@gmail.com> |
139 | +Raquel Lira <raquel.lira@gmail.com> | |
121 | 140 | Renan Costa <renan2727@hotmail.com> |
122 | 141 | Renan Teruo <renanteruoc@gmail.com> |
123 | 142 | Rodrigo Medeiros <rodrigo.mss01@gmail.com> |
... | ... | @@ -125,16 +144,18 @@ Rodrigo Siqueira <siqueira@kuniri.org> |
125 | 144 | Rodrigo Souto <rodrigo@colivre.coop.br> |
126 | 145 | Ronnie Simon <ronniesimonf@gmail.com> |
127 | 146 | Ronny Kursawe <kursawe.ronny@googlemail.com> |
147 | +Sabryna Sousa <sabryna.sousa1323@gmail.com> | |
128 | 148 | Samuel R. C. Vale <srcvale@holoscopio.com> |
129 | 149 | Simião Carvalho <simiaosimis@gmail.com> |
150 | +TWS <tablettws@gmail.com> | |
130 | 151 | Tallys Martins <tallysmartins@yahoo.com.br> |
131 | 152 | Thiago Casotti <thiago.casotti@uol.com.br> |
132 | 153 | Thiago Kairala <thiagor.kairala@gmail.com> |
133 | 154 | Thiago Ribeiro <thiagitosouza@hotmail.com> |
134 | 155 | Thiago Zoroastro <thiago.zoroastro@bol.com.br> |
135 | 156 | Tuux <tuxa@galaxie.eu.org> |
136 | -TWS <tablettws@gmail.com> | |
137 | 157 | Valessio Brito <contato@valessiobrito.com.br> |
158 | +Valet 322 <petymakar@gmail.com> | |
138 | 159 | Victor Costa <vfcosta@gmail.com> |
139 | 160 | Victor Hugo Alves de Carvalho <victorhugodf.ac@gmail.com> |
140 | 161 | Victor Navarro <victor.matias.navarro@gmail.com> |
... | ... | @@ -142,6 +163,9 @@ Vinicius Brand <viniciuscb@gmail.com> |
142 | 163 | Vitor Barbosa <vitornga15@gmail.com> |
143 | 164 | Wilton Rodrigues <braynwilton@gmail.com> |
144 | 165 | Yann Lugrin <yann.lugrin@liquid-concept.ch> |
166 | +Ábner Silva de Oliveira <abner.oliveira@serpro.gov.br> | |
167 | +Álvaro Fernando <alvarofernandoms@gmail.com> | |
168 | +Вадим Кардашьян <iosphone77@gmail.com> | |
145 | 169 | |
146 | 170 | Ideas, specifications and incentive |
147 | 171 | =================================== | ... | ... |
Gemfile
... | ... | @@ -27,7 +27,7 @@ gem 'rest-client', '~> 1.6' |
27 | 27 | gem 'exception_notification', '~> 4.0.1' |
28 | 28 | gem 'gettext', '~> 3.1', :require => false |
29 | 29 | gem 'locale', '~> 2.1' |
30 | -gem 'whenever', :require => false | |
30 | +gem 'whenever', '~> 0.9.4', :require => false | |
31 | 31 | gem 'eita-jrails', '~> 0.10.0', require: 'jrails' |
32 | 32 | gem 'diffy', '~> 3.0' |
33 | 33 | gem 'slim' |
... | ... | @@ -35,17 +35,16 @@ gem 'activerecord-session_store', ('1.0.0.pre' if RUBY_VERSION >= '2.3.0') |
35 | 35 | |
36 | 36 | # API dependencies |
37 | 37 | gem 'grape', '~> 0.12' |
38 | -gem 'grape-entity', '0.4.8' | |
38 | +gem 'grape-entity', '~>0.4.8' | |
39 | 39 | gem 'grape_logging' |
40 | 40 | gem 'grape-swagger' |
41 | 41 | gem 'swagger-ui_rails' |
42 | 42 | gem 'kramdown' |
43 | 43 | gem 'rack-cors' |
44 | 44 | gem 'rack-contrib' |
45 | -gem 'liquid', '~> 3.0.3' | |
46 | 45 | |
47 | 46 | gem 'api-pagination', '>= 4.1.1' |
48 | -gem 'liquid', '~> 3.0.3' | |
47 | +gem 'liquid', '>= 3.0.3' | |
49 | 48 | |
50 | 49 | # asset pipeline |
51 | 50 | gem 'uglifier', '>= 1.0.3' |
... | ... | @@ -81,10 +80,10 @@ end |
81 | 80 | group :cucumber do |
82 | 81 | gem 'capybara', '~> 2.2' |
83 | 82 | gem 'launchy' |
84 | - gem 'cucumber' | |
83 | + gem 'cucumber', '~> 1.3' | |
85 | 84 | gem 'cucumber-rails', '~> 1.4.2', :require => false |
86 | 85 | gem 'database_cleaner', '~> 1.3' |
87 | - gem 'selenium-webdriver', '>= 2.50' | |
86 | + gem 'selenium-webdriver', '>= 2.53' | |
88 | 87 | gem 'chromedriver-helper' if ENV['SELENIUM_DRIVER'] == 'chrome' |
89 | 88 | end |
90 | 89 | ... | ... |
HACKING.md
... | ... | @@ -31,7 +31,7 @@ If you want to use a different port than 3000, pass `-p <PORT>` to `./script/dev |
31 | 31 | Instructions for other systems |
32 | 32 | ------------------------------ |
33 | 33 | |
34 | -On other OS, you have 2 options: | |
34 | +On other OS, you have many options: | |
35 | 35 | |
36 | 36 | ### 1) using a chroot or a VM with Debian stable (easier) |
37 | 37 | |
... | ... | @@ -45,6 +45,14 @@ You can check `./script/install-dependencies/debian-squeeze.sh` to have an idea |
45 | 45 | |
46 | 46 | If you write such script for your own OS, *please* share it with us at the development mailing list so that we can include it in the official repository. This way other people using the same OS will have to put less effort to develop Noosfero. |
47 | 47 | |
48 | +### 3) Installing dependencies via Rubygems and RVM | |
49 | + | |
50 | +To setup the development environment through Rubygems you just need to install some basic deps and then install the gems defined on the Gemfile. Further instructions can be found on: http://noosfero.org/bin/view/Development/DepsWithRVMAndGems | |
51 | + | |
52 | +### 4) Using a docker image | |
53 | + | |
54 | +Use a docker image to run an out-of-the-box development environment. Further information can be found on: https://hub.docker.com/r/noosfero/dev-rails4/ | |
55 | + | |
48 | 56 | Submitting your changes back |
49 | 57 | ---------------------------- |
50 | 58 | ... | ... |
app/api/entities.rb
... | ... | @@ -38,9 +38,17 @@ module Api |
38 | 38 | PERMISSIONS[current_permission] <= PERMISSIONS[permission] |
39 | 39 | end |
40 | 40 | |
41 | + def self.expose_optional_field?(field, options = {}) | |
42 | + return false if options[:params].nil? | |
43 | + optional_fields = options[:params][:optional_fields] || [] | |
44 | + optional_fields.include?(field.to_s) | |
45 | + end | |
46 | + | |
47 | + | |
41 | 48 | class Image < Entity |
42 | 49 | root 'images', 'image' |
43 | 50 | |
51 | + expose :filename | |
44 | 52 | expose :url do |image, options| |
45 | 53 | image.public_filename |
46 | 54 | end |
... | ... | @@ -153,6 +161,9 @@ module Api |
153 | 161 | expose :articles_count do |person, options| |
154 | 162 | person.articles.count |
155 | 163 | end |
164 | + expose :friends_count do |person, options| | |
165 | + person.friends.size | |
166 | + end | |
156 | 167 | end |
157 | 168 | |
158 | 169 | class Enterprise < Profile |
... | ... | @@ -166,7 +177,8 @@ module Api |
166 | 177 | community.admins.map{|admin| {"name"=>admin.name, "id"=>admin.id, "username" => admin.identifier}} |
167 | 178 | end |
168 | 179 | expose :categories, :using => Category |
169 | - expose :members, :using => Person , :if => lambda{ |community, options| community.display_info_to? options[:current_person] } | |
180 | + expose :members_count | |
181 | + expose :members, :if => lambda {|community, options| Entities.expose_optional_field?(:members, options)} | |
170 | 182 | end |
171 | 183 | |
172 | 184 | class CommentBase < Entity |
... | ... | @@ -174,6 +186,10 @@ module Api |
174 | 186 | expose :created_at, :format_with => :timestamp |
175 | 187 | expose :author, :using => Profile |
176 | 188 | expose :reply_of, :using => CommentBase |
189 | + expose :permissions do |comment, options| | |
190 | + Entities.permissions_for_entity(comment, options[:current_person], | |
191 | + :allow_destroy?) | |
192 | + end | |
177 | 193 | end |
178 | 194 | |
179 | 195 | class Comment < CommentBase |
... | ... | @@ -209,7 +225,7 @@ module Api |
209 | 225 | expose :comments_count |
210 | 226 | expose :archived, :documentation => {:type => "Boolean", :desc => "Defines if a article is readonly"} |
211 | 227 | expose :type |
212 | - expose :comments, using: CommentBase, :if => lambda{|obj,opt| opt[:params] && ['1','true',true].include?(opt[:params][:show_comments])} | |
228 | + expose :comments, using: CommentBase, :if => lambda{|comment,options| Entities.expose_optional_field?(:comments, options)} | |
213 | 229 | expose :published |
214 | 230 | expose :accept_comments?, as: :accept_comments |
215 | 231 | end |
... | ... | @@ -304,7 +320,7 @@ module Api |
304 | 320 | end |
305 | 321 | expose :params, :if => lambda { |activity, options| activity.kind_of?(ActionTracker::Record)} |
306 | 322 | expose :content, :if => lambda { |activity, options| activity.kind_of?(Scrap)} |
307 | - expose :verb do |activity, options| | |
323 | + expose :verb do |activity, options| | |
308 | 324 | activity.kind_of?(Scrap) ? 'leave_scrap' : activity.verb |
309 | 325 | end |
310 | 326 | ... | ... |
app/api/helpers.rb
... | ... | @@ -57,9 +57,11 @@ module Api |
57 | 57 | def present_partial(model, options) |
58 | 58 | if(params[:fields].present?) |
59 | 59 | begin |
60 | - fields = JSON.parse(params[:fields]) | |
60 | + fields = JSON.parse((params.to_hash[:fields] || params.to_hash['fields']).to_json) | |
61 | 61 | if fields.present? |
62 | - options.merge!(fields.symbolize_keys.slice(:only, :except)) | |
62 | + fields = fields.symbolize_keys | |
63 | + options.merge!(:only => fields[:only]) if fields[:only].present? | |
64 | + options.merge!(:except => fields[:except]) if fields[:except].present? | |
63 | 65 | end |
64 | 66 | rescue |
65 | 67 | fields = params[:fields] |
... | ... | @@ -116,7 +118,7 @@ module Api |
116 | 118 | def post_article(asset, params) |
117 | 119 | return forbidden! unless current_person.can_post_content?(asset) |
118 | 120 | |
119 | - klass_type = params[:content_type] || params[:article].delete(:type) || TinyMceArticle.name | |
121 | + klass_type = params[:content_type] || params[:article].delete(:type) || TextArticle.name | |
120 | 122 | return forbidden! unless klass_type.constantize <= Article |
121 | 123 | |
122 | 124 | article = klass_type.constantize.new(params[:article]) |
... | ... | @@ -447,12 +449,12 @@ module Api |
447 | 449 | end |
448 | 450 | |
449 | 451 | def asset_with_image params |
450 | - if params.has_key? :image_builder | |
452 | + if !params.nil? && params.has_key?(:image_builder) | |
451 | 453 | asset_api_params = params |
452 | 454 | asset_api_params[:image_builder] = base64_to_uploadedfile(asset_api_params[:image_builder]) |
453 | 455 | return asset_api_params |
454 | 456 | end |
455 | - params | |
457 | + params | |
456 | 458 | end |
457 | 459 | |
458 | 460 | def base64_to_uploadedfile(base64_image) |
... | ... | @@ -503,11 +505,9 @@ module Api |
503 | 505 | |
504 | 506 | def parse_content_type(content_type) |
505 | 507 | return nil if content_type.blank? |
506 | - content_types = content_type.split(',').map do |content_type| | |
507 | - content_type = content_type.camelcase | |
508 | - content_type == 'TextArticle' ? Article.text_article_types : content_type | |
508 | + content_type.split(',').map do |content_type| | |
509 | + content_type.camelcase | |
509 | 510 | end |
510 | - content_types.flatten.uniq | |
511 | 511 | end |
512 | 512 | |
513 | 513 | def period(from_date, until_date) | ... | ... |
app/api/v1/articles.rb
... | ... | @@ -284,7 +284,7 @@ module Api |
284 | 284 | |
285 | 285 | if params[:path].present? |
286 | 286 | article = profile.articles.find_by path: params[:path] |
287 | - if !article || !article.display_to?(current_person) | |
287 | + if article && !article.display_to?(current_person) | |
288 | 288 | article = forbidden! |
289 | 289 | end |
290 | 290 | ... | ... |
app/api/v1/blocks.rb
... | ... | @@ -6,6 +6,7 @@ module Api |
6 | 6 | get ':id' do |
7 | 7 | block = Block.find(params["id"]) |
8 | 8 | return forbidden! unless block.visible_to_user?(current_person) || block.allow_edit?(current_person) |
9 | + block.api_content_params = params.except("id") | |
9 | 10 | present block, :with => Entities::Block, display_api_content: true, current_person: current_person |
10 | 11 | end |
11 | 12 | ... | ... |
app/api/v1/communities.rb
... | ... | @@ -18,7 +18,7 @@ module Api |
18 | 18 | communities = select_filtered_collection_of(environment, 'communities', params) |
19 | 19 | communities = profiles_for_person(communities, current_person) |
20 | 20 | communities = communities.by_location(params) # Must be the last. May return Exception obj |
21 | - present communities, :with => Entities::Community, :current_person => current_person | |
21 | + present communities, :with => Entities::Community, :current_person => current_person, :params => params | |
22 | 22 | end |
23 | 23 | |
24 | 24 | |
... | ... | @@ -49,7 +49,7 @@ module Api |
49 | 49 | |
50 | 50 | get ':id' do |
51 | 51 | community = profiles_for_person(environment.communities, current_person).find_by_id(params[:id]) |
52 | - present community, :with => Entities::Community, :current_person => current_person | |
52 | + present community, :with => Entities::Community, :current_person => current_person, :params => params | |
53 | 53 | end |
54 | 54 | |
55 | 55 | end | ... | ... |
app/api/v1/profiles.rb
... | ... | @@ -28,7 +28,7 @@ module Api |
28 | 28 | authenticate! |
29 | 29 | profile = environment.profiles.find_by(id: params[:id]) |
30 | 30 | return forbidden! unless profile.allow_edit?(current_person) |
31 | - profile.update_attributes!(params[:profile]) | |
31 | + profile.update_attributes!(asset_with_image(params[:profile])) | |
32 | 32 | present profile, :with => Entities::Profile, :current_person => current_person |
33 | 33 | end |
34 | 34 | ... | ... |
app/api/v1/session.rb
... | ... | @@ -174,14 +174,13 @@ module Api |
174 | 174 | # Example Request: |
175 | 175 | # PATCH /new_password?code=xxxx&password=secret&password_confirmation=secret |
176 | 176 | patch "/new_password" do |
177 | - change_password = ChangePassword.find_by code: params[:code] | |
178 | - not_found! if change_password.nil? | |
179 | - | |
180 | - if change_password.update_attributes(:password => params[:password], :password_confirmation => params[:password_confirmation]) | |
177 | + begin | |
178 | + change_password = ChangePassword.find_by! code: params[:code] | |
179 | + change_password.update_attributes!(:password => params[:password], :password_confirmation => params[:password_confirmation]) | |
181 | 180 | change_password.finish |
182 | 181 | present change_password.requestor.user, :with => Entities::UserLogin, :current_person => current_person |
183 | - else | |
184 | - something_wrong! | |
182 | + rescue Exception => ex | |
183 | + render_api_error!(ex.message, 400) | |
185 | 184 | end |
186 | 185 | end |
187 | 186 | ... | ... |
app/controllers/my_profile/cms_controller.rb
... | ... | @@ -146,11 +146,14 @@ class CmsController < MyProfileController |
146 | 146 | parent = check_parent(params[:parent_id]) |
147 | 147 | if parent |
148 | 148 | @article.parent = parent |
149 | + @article.published = parent.published | |
150 | + @article.show_to_followers = parent.show_to_followers | |
149 | 151 | @parent_id = parent.id |
150 | 152 | end |
151 | 153 | |
152 | 154 | @article.profile = profile |
153 | 155 | @article.author = user |
156 | + @article.editor = current_person.editor | |
154 | 157 | @article.last_changed_by = user |
155 | 158 | @article.created_by = user |
156 | 159 | |
... | ... | @@ -399,8 +402,7 @@ class CmsController < MyProfileController |
399 | 402 | |
400 | 403 | def available_article_types |
401 | 404 | articles = [ |
402 | - TinyMceArticle, | |
403 | - TextileArticle, | |
405 | + TextArticle, | |
404 | 406 | Event |
405 | 407 | ] |
406 | 408 | articles += special_article_types if params && params[:cms] |
... | ... | @@ -408,9 +410,6 @@ class CmsController < MyProfileController |
408 | 410 | if @parent && @parent.blog? |
409 | 411 | articles -= Article.folder_types.map(&:constantize) |
410 | 412 | end |
411 | - if user.is_admin?(profile.environment) | |
412 | - articles << RawHTMLArticle | |
413 | - end | |
414 | 413 | articles |
415 | 414 | end |
416 | 415 | ... | ... |
app/controllers/my_profile/profile_editor_controller.rb
... | ... | @@ -12,7 +12,7 @@ class ProfileEditorController < MyProfileController |
12 | 12 | include CategoriesHelper |
13 | 13 | |
14 | 14 | def index |
15 | - @pending_tasks = Task.to(profile).pending.without_spam.select{|i| user.has_permission?(i.permission, profile)} | |
15 | + @pending_tasks = Task.to(profile).pending.without_spam | |
16 | 16 | @show_appearance_option = user.is_admin?(environment) || environment.enabled?('enable_appearance') |
17 | 17 | @show_header_footer_option = user.is_admin?(environment) || (!profile.enterprise? && !environment.enabled?('disable_header_and_footer')) |
18 | 18 | end |
... | ... | @@ -95,7 +95,7 @@ class ProfileEditorController < MyProfileController |
95 | 95 | end |
96 | 96 | |
97 | 97 | def welcome_page |
98 | - @welcome_page = profile.welcome_page || TinyMceArticle.new(:name => 'Welcome Page', :profile => profile, :published => false) | |
98 | + @welcome_page = profile.welcome_page || TextArticle.new(:name => 'Welcome Page', :profile => profile, :published => false) | |
99 | 99 | if request.post? |
100 | 100 | begin |
101 | 101 | @welcome_page.update!(params[:welcome_page]) | ... | ... |
app/controllers/public/account_controller.rb
... | ... | @@ -164,6 +164,7 @@ class AccountController < ApplicationController |
164 | 164 | def logout |
165 | 165 | if logged_in? |
166 | 166 | self.current_user.forget_me |
167 | + current_user.update({:chat_status_at => DateTime.now}.merge({:last_chat_status => current_user.chat_status, :chat_status => 'offline'})) | |
167 | 168 | end |
168 | 169 | reset_session |
169 | 170 | session[:notice] = _("You have been logged out.") | ... | ... |
app/controllers/public/chat_controller.rb
... | ... | @@ -113,8 +113,20 @@ class ChatController < PublicController |
113 | 113 | end |
114 | 114 | |
115 | 115 | #TODO Ideally this is done through roster table on ejabberd. |
116 | - def roster_groups | |
117 | - render :text => user.memberships.map {|m| {:jid => m.jid, :name => m.name}}.to_json | |
116 | + def rosters | |
117 | + rooms = user.memberships.map {|m| {:jid => m.jid, :name => m.name}} | |
118 | + friends = user.friends.map {|f| {:jid => f.jid, :name => f.name}} | |
119 | + rosters = {:rooms => rooms, :friends => friends} | |
120 | + render :text => rosters.to_json | |
121 | + end | |
122 | + | |
123 | + def availabilities | |
124 | + availabilities = user.friends.map do |friend| | |
125 | + status = friend.user.chat_status | |
126 | + status = 'offline' if status.blank? | |
127 | + {:jid => friend.jid, :status => status} | |
128 | + end | |
129 | + render :text => availabilities.to_json | |
118 | 130 | end |
119 | 131 | |
120 | 132 | protected | ... | ... |
app/controllers/public/invite_controller.rb
... | ... | @@ -98,6 +98,8 @@ class InviteController < PublicController |
98 | 98 | scope = profile.invite_friends_only ? user.friends : environment.people |
99 | 99 | scope = scope.not_members_of(profile) if profile.organization? |
100 | 100 | scope = scope.not_friends_of(profile) if profile.person? |
101 | + scope = scope.distinct(false).group("profiles.id") | |
102 | + | |
101 | 103 | results = find_by_contents(:people, environment, scope, params['q'], {:page => 1}, {:joins => :user})[:results] |
102 | 104 | render :text => prepare_to_token_input(results).to_json |
103 | 105 | end | ... | ... |
app/controllers/public/profile_controller.rb
... | ... | @@ -13,12 +13,13 @@ class ProfileController < PublicController |
13 | 13 | |
14 | 14 | protect 'send_mail_to_members', :profile, :only => [:send_mail] |
15 | 15 | |
16 | + ACTIVITIES_PER_PAGE = 15 | |
17 | + | |
16 | 18 | def index |
17 | - @network_activities = !@profile.is_a?(Person) ? @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) : [] | |
18 | - if logged_in? && current_person.follows?(@profile) | |
19 | - @network_activities = @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) if @network_activities.empty? | |
20 | - @activities = @profile.activities.paginate(:per_page => 15, :page => params[:page]) | |
21 | - end | |
19 | + @offsets = {:wall => 0, :network => 0} | |
20 | + page = (params[:page] || 1).to_i | |
21 | + @network_activities = loop_fetch_activities(@profile.tracked_notifications, :network, page) if !@profile.is_a?(Person) || follow_profile? | |
22 | + @activities = loop_fetch_activities(@profile.activities, :wall, page) if follow_profile? | |
22 | 23 | @tags = profile.article_tags |
23 | 24 | allow_access_to_page |
24 | 25 | end |
... | ... | @@ -231,6 +232,7 @@ class ProfileController < PublicController |
231 | 232 | @scrap = Scrap.new(params[:scrap]) |
232 | 233 | @scrap.sender= sender |
233 | 234 | @scrap.receiver= receiver |
235 | + @scrap.marked_people = treat_followed_entries(params[:filter_followed]) | |
234 | 236 | @tab_action = params[:tab_action] |
235 | 237 | @message = @scrap.save ? _("Message successfully sent.") : _("You can't leave an empty message.") |
236 | 238 | activities = @profile.activities.paginate(:per_page => 15, :page => params[:page]) if params[:not_load_scraps].nil? |
... | ... | @@ -249,18 +251,44 @@ class ProfileController < PublicController |
249 | 251 | render :partial => 'profile_activities_list', :locals => {:activities => activities} |
250 | 252 | else |
251 | 253 | network_activities = @profile.tracked_notifications.visible.paginate(:per_page => 15, :page => params[:page]) |
252 | - render :partial => 'profile_network_activities', :locals => {:network_activities => network_activities} | |
254 | + render :partial => 'profile_network_activities', :locals => {:activities => network_activities} | |
253 | 255 | end |
254 | 256 | end |
255 | 257 | |
256 | - def view_more_activities | |
257 | - @activities = @profile.activities.paginate(:per_page => 10, :page => params[:page]) | |
258 | - render :partial => 'profile_activities_list', :locals => {:activities => @activities} | |
258 | + def search_followed | |
259 | + result = [] | |
260 | + circles = find_by_contents(:circles, user, user.circles.where(:profile_type => 'Person'), params[:q])[:results] | |
261 | + followed = find_by_contents(:followed, user, Profile.followed_by(user), params[:q])[:results] | |
262 | + result = circles + followed | |
263 | + render :text => prepare_to_token_input_by_class(result).to_json | |
259 | 264 | end |
260 | 265 | |
261 | - def view_more_network_activities | |
262 | - @activities = @profile.tracked_notifications.paginate(:per_page => 10, :page => params[:page]) | |
263 | - render :partial => 'profile_network_activities', :locals => {:network_activities => @activities} | |
266 | + def loop_fetch_activities(base_activities, kind, page) | |
267 | + activities = nil | |
268 | + while activities.nil? || (activities.empty? && page <= activities.total_pages) | |
269 | + activities = base_activities.offset(@offsets[kind.to_sym]).paginate(:per_page => ACTIVITIES_PER_PAGE, :page => page) | |
270 | + activities = filter_activities(activities, kind.to_sym) | |
271 | + page += 1 | |
272 | + end | |
273 | + activities | |
274 | + end | |
275 | + | |
276 | + def view_more_activities | |
277 | + @activities = nil | |
278 | + @offsets = params[:offsets] | |
279 | + page = (params[:page] || 1).to_i | |
280 | + kind = params[:kind] | |
281 | + | |
282 | + if kind == 'wall' | |
283 | + base_activities = @profile.activities | |
284 | + partial = 'profile_activities_list' | |
285 | + else | |
286 | + base_activities = @profile.tracked_notifications | |
287 | + partial = 'profile_network_activities' | |
288 | + end | |
289 | + | |
290 | + @activities = loop_fetch_activities(base_activities, kind, page) | |
291 | + render :partial => partial, :locals => {:activities => @activities} | |
264 | 292 | end |
265 | 293 | |
266 | 294 | def more_comments |
... | ... | @@ -434,7 +462,6 @@ class ProfileController < PublicController |
434 | 462 | end |
435 | 463 | end |
436 | 464 | |
437 | - | |
438 | 465 | protected |
439 | 466 | |
440 | 467 | def check_access_to_profile |
... | ... | @@ -480,4 +507,39 @@ class ProfileController < PublicController |
480 | 507 | render_not_found unless profile.allow_followers? |
481 | 508 | end |
482 | 509 | |
510 | + def treat_followed_entries(entries) | |
511 | + return [] if entries.blank? || profile != user | |
512 | + | |
513 | + followed = [] | |
514 | + entries.split(',').map do |entry| | |
515 | + klass, identifier = entry.split('_') | |
516 | + case klass | |
517 | + when 'Person' | |
518 | + followed << Person.find(identifier) | |
519 | + when 'Circle' | |
520 | + circle = Circle.find(identifier) | |
521 | + followed += Profile.in_circle(circle) | |
522 | + end | |
523 | + end | |
524 | + followed.uniq | |
525 | + end | |
526 | + | |
527 | + def filter_activities(activities, kind) | |
528 | + @offsets ||= {:wall => 0, :network => 0} | |
529 | + return activities if environment.admins.include?(user) | |
530 | + activities = Array(activities) | |
531 | + initial_count = activities.count | |
532 | + activities.delete_if do |activity| | |
533 | + activity = ActivityPresenter.for(activity) | |
534 | + next if activity.involved?(user) | |
535 | + activity.hidden_for?(user) | |
536 | + end | |
537 | + @offsets[kind] = @offsets[kind].to_i | |
538 | + @offsets[kind] += initial_count - activities.count | |
539 | + activities | |
540 | + end | |
541 | + | |
542 | + def follow_profile? | |
543 | + logged_in? && current_person.follows?(@profile) | |
544 | + end | |
483 | 545 | end | ... | ... |
app/helpers/application_helper.rb
... | ... | @@ -111,10 +111,6 @@ module ApplicationHelper |
111 | 111 | content = capture(&block) |
112 | 112 | end |
113 | 113 | |
114 | - if options[:type] == :textile | |
115 | - content = RedCloth.new(content).to_html | |
116 | - end | |
117 | - | |
118 | 114 | options[:class] = '' if ! options[:class] |
119 | 115 | options[:class] += ' button icon-help' # with-text |
120 | 116 | |
... | ... | @@ -132,13 +128,6 @@ module ApplicationHelper |
132 | 128 | text |
133 | 129 | end |
134 | 130 | |
135 | - # alias for <tt>help(content, :textile)</tt>. You can pass a block in the | |
136 | - # same way you would do if you called <tt>help</tt> directly. | |
137 | - def help_textile(content = nil, link_name = nil, options = {}, &block) | |
138 | - options[:type] = :textile | |
139 | - help(content, link_name, options, &block) | |
140 | - end | |
141 | - | |
142 | 131 | # TODO: do something more useful here |
143 | 132 | # TODO: test this helper |
144 | 133 | # TODO: add an icon? |
... | ... | @@ -531,8 +520,6 @@ module ApplicationHelper |
531 | 520 | html = "\n" |
532 | 521 | values.each { |val, h_val| |
533 | 522 | id = object_name.to_s() +'_'+ method.to_s() +'_'+ val.to_s() |
534 | - # Não está apresentando o sexo selecionado ao revisitar | |
535 | - # http://localhost:3000/myprofile/manuel/profile_editor/edit :-( | |
536 | 523 | html += self.class.content_tag( 'span', |
537 | 524 | @template.radio_button( object_name, method, val, |
538 | 525 | :id => id, :object => @object ) + |
... | ... | @@ -543,6 +530,7 @@ module ApplicationHelper |
543 | 530 | html += "<br />\n".html_safe |
544 | 531 | end |
545 | 532 | } |
533 | + html = html.html_safe | |
546 | 534 | html += "<br />\n".html_safe if line_size == 0 || ( values.size % line_size ) > 0 |
547 | 535 | column = object.class.columns_hash[method.to_s] if object |
548 | 536 | text = |
... | ... | @@ -552,7 +540,7 @@ module ApplicationHelper |
552 | 540 | ) |
553 | 541 | label_html = self.class.content_tag 'label', text, |
554 | 542 | :class => 'formlabel' |
555 | - control_html = self.class.content_tag 'div', html, | |
543 | + control_html = self.class.content_tag 'div', html.html_safe, | |
556 | 544 | :class => 'formfield type-radio '+ |
557 | 545 | 'fieldgroup linesize'+line_size.to_s() |
558 | 546 | |
... | ... | @@ -977,11 +965,16 @@ module ApplicationHelper |
977 | 965 | content_tag(:div, _('Source: %s') % source_url, :id => 'article-source') unless source_url.nil? |
978 | 966 | end |
979 | 967 | |
980 | - def task_information(task) | |
968 | + def task_information(task, params = {}) | |
981 | 969 | values = {} |
982 | 970 | values.merge!(task.information[:variables]) if task.information[:variables] |
983 | 971 | values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor |
984 | - values.merge!({:target => link_to(task.target.name, task.target.url)}) if (task.target && task.target.respond_to?(:url)) | |
972 | + if (task.target && task.target.respond_to?(:url)) | |
973 | + values.merge!({:target => link_to(task.target.name, task.target.url)}) | |
974 | + target_detail = _("in %s").html_safe % values[:target] | |
975 | + target_detail = '' if task.target.identifier == params[:profile] | |
976 | + values.merge!({:target_detail => target_detail}) | |
977 | + end | |
985 | 978 | values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject |
986 | 979 | values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject |
987 | 980 | (task.information[:message] % values).html_safe |
... | ... | @@ -992,8 +985,8 @@ module ApplicationHelper |
992 | 985 | end |
993 | 986 | |
994 | 987 | def add_zoom_to_images |
995 | - stylesheet_link_tag('jquery.fancybox') + | |
996 | - javascript_include_tag('jquery.fancybox.pack') + | |
988 | + stylesheet_link_tag('vendor/jquery.fancybox') + | |
989 | + javascript_include_tag('vendor/jquery.fancybox.pack') + | |
997 | 990 | javascript_tag("apply_zoom_to_images(#{_('Zoom in').to_json})") |
998 | 991 | end |
999 | 992 | |
... | ... | @@ -1185,10 +1178,10 @@ module ApplicationHelper |
1185 | 1178 | end |
1186 | 1179 | |
1187 | 1180 | controller_target = suggestion.suggestion_type == 'Person' ? :friends : :memberships |
1188 | - profiles << link_to("<big> +#{suggestion.profile_connections.count - 4}</big>", :controller => controller_target, :action => :connections, :id => suggestion.suggestion_id) if suggestion.profile_connections.count > 4 | |
1181 | + profiles << link_to("<big> +#{suggestion.profile_connections.count - 4}</big>".html_safe, :controller => controller_target, :action => :connections, :id => suggestion.suggestion_id) if suggestion.profile_connections.count > 4 | |
1189 | 1182 | |
1190 | 1183 | if profiles.present? |
1191 | - content_tag(:div, profiles.join , :class => 'profile-connections') | |
1184 | + content_tag(:div, profiles.safe_join , :class => 'profile-connections') | |
1192 | 1185 | else |
1193 | 1186 | '' |
1194 | 1187 | end |
... | ... | @@ -1245,4 +1238,15 @@ module ApplicationHelper |
1245 | 1238 | content.html_safe |
1246 | 1239 | end |
1247 | 1240 | |
1241 | + def current_editor_is?(editor) | |
1242 | + editor.blank? ? false : current_editor == editor | |
1243 | + end | |
1244 | + | |
1245 | + def current_editor(mode = '') | |
1246 | + editor = @article.editor || Article::Editor::TINY_MCE unless @article.nil? | |
1247 | + editor ||= (current_person.nil? || current_person.editor.nil?) ? Article::Editor::TINY_MCE : current_person.editor | |
1248 | + editor += '_' + mode unless mode.blank? | |
1249 | + editor | |
1250 | + end | |
1251 | + | |
1248 | 1252 | end | ... | ... |
app/helpers/article_helper.rb
... | ... | @@ -61,7 +61,9 @@ module ArticleHelper |
61 | 61 | 'div', |
62 | 62 | check_box(:article, :display_versions) + |
63 | 63 | content_tag('label', _('I want this article to display a link to older versions'), :for => 'article_display_versions') |
64 | - ) : '') | |
64 | + ) : '') + | |
65 | + | |
66 | + (self.respond_to?(:extra_options) ? self.extra_options : "") | |
65 | 67 | ) |
66 | 68 | end |
67 | 69 | |
... | ... | @@ -161,6 +163,10 @@ module ArticleHelper |
161 | 163 | array.map { |object| {:label => object.name, :value => object.name} } |
162 | 164 | end |
163 | 165 | |
166 | + def prepare_to_token_input_by_class(array) | |
167 | + array.map { |object| {:id => "#{object.class.name}_#{object.id || object.name}", :name => "#{object.name} (#{_(object.class.name)})", :class => object.class.name}} | |
168 | + end | |
169 | + | |
164 | 170 | def cms_label_for_new_children |
165 | 171 | _('New article') |
166 | 172 | end | ... | ... |
app/helpers/chat_helper.rb
... | ... | @@ -14,7 +14,7 @@ module ChatHelper |
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").html_safe, | |
18 | 18 | :style => 'display: none; z-index: 100', |
19 | 19 | :class => 'simplemenu-submenu' |
20 | 20 | ), | ... | ... |
app/helpers/email_template_helper.rb
... | ... | @@ -6,7 +6,7 @@ module EmailTemplateHelper |
6 | 6 | params[:subject] = params[:email_template].parsed_subject(params[:template_params]) |
7 | 7 | params[:content_type] = "text/html" |
8 | 8 | end |
9 | - mail(params.except(:email_template)) | |
9 | + mail(params.except(:email_template, :template_params)) | |
10 | 10 | end |
11 | 11 | |
12 | 12 | end | ... | ... |
... | ... | @@ -0,0 +1,13 @@ |
1 | +module GalleryHelper | |
2 | + | |
3 | + include ArticleHelper | |
4 | + | |
5 | + def extra_options | |
6 | + content_tag( | |
7 | + 'div', | |
8 | + check_box(:article, :allow_download) + | |
9 | + content_tag('label', _('Allow images from this gallery to be downloaded'), :for => 'article_allow_download') | |
10 | + ) | |
11 | + end | |
12 | + | |
13 | +end | ... | ... |
app/helpers/profile_editor_helper.rb
app/helpers/search_helper.rb
... | ... | @@ -45,7 +45,8 @@ module SearchHelper |
45 | 45 | def search_page_title(title, category = nil) |
46 | 46 | title = "<h1>" + title |
47 | 47 | title += ' - <small>' + category.name + '</small>' if category |
48 | - title + "</h1>" | |
48 | + title += "</h1>" | |
49 | + title.html_safe | |
49 | 50 | end |
50 | 51 | |
51 | 52 | def category_context(category, url) | ... | ... |
app/helpers/tags_helper.rb
... | ... | @@ -67,4 +67,17 @@ module TagsHelper |
67 | 67 | end.join("\n").html_safe |
68 | 68 | end |
69 | 69 | |
70 | + def linked_article_tags(article) | |
71 | + if @profile | |
72 | + # We are rendering a page inside a profile, so link to the profile tag search. | |
73 | + url = { :controller => 'profile', :profile => @profile.identifier, :action => 'tags' } | |
74 | + tagname_option = :id | |
75 | + else | |
76 | + # We are rendering a page outside a profile, so link to the global tag search. | |
77 | + url = { :action => 'tag' } | |
78 | + tagname_option = :tag | |
79 | + end | |
80 | + article.tags.map { |t| link_to(t, url.merge(tagname_option=>t.name) ) }.join("\n") | |
81 | + end | |
82 | + | |
70 | 83 | end | ... | ... |
app/helpers/tinymce_helper.rb
... | ... | @@ -18,7 +18,8 @@ module TinymceHelper |
18 | 18 | insertdatetime media nonbreaking save table contextmenu directionality |
19 | 19 | emoticons template paste textcolor colorpicker textpattern], |
20 | 20 | :image_advtab => true, |
21 | - :language => tinymce_language | |
21 | + :language => tinymce_language, | |
22 | + :selector => '.' + current_editor(options[:mode]) | |
22 | 23 | |
23 | 24 | options[:toolbar1] = toolbar1(options[:mode]) |
24 | 25 | options[:menubar] = menubar(options[:mode]) | ... | ... |
app/helpers/token_helper.rb
... | ... | @@ -5,10 +5,11 @@ module TokenHelper |
5 | 5 | end |
6 | 6 | |
7 | 7 | def token_input_field_tag(name, element_id, search_action, options = {}, text_field_options = {}, html_options = {}) |
8 | - options[:min_chars] ||= 3 | |
8 | + options[:min_chars] ||= 2 | |
9 | 9 | options[:hint_text] ||= _("Type in a search term") |
10 | 10 | options[:no_results_text] ||= _("No results") |
11 | 11 | options[:searching_text] ||= _("Searching...") |
12 | + options[:placeholder] ||= 'null' | |
12 | 13 | options[:search_delay] ||= 1000 |
13 | 14 | options[:prevent_duplicates] ||= true |
14 | 15 | options[:backspace_delete_item] ||= false |
... | ... | @@ -20,6 +21,9 @@ module TokenHelper |
20 | 21 | options[:on_delete] ||= 'null' |
21 | 22 | options[:on_ready] ||= 'null' |
22 | 23 | options[:query_param] ||= 'q' |
24 | + options[:theme] ||= 'null' | |
25 | + options[:results_formatter] ||= 'null' | |
26 | + options[:token_formatter] ||= 'null' | |
23 | 27 | |
24 | 28 | result = text_field_tag(name, nil, text_field_options.merge(html_options.merge({:id => element_id}))) |
25 | 29 | result += javascript_tag("jQuery('##{element_id}') |
... | ... | @@ -29,6 +33,7 @@ module TokenHelper |
29 | 33 | hintText: #{options[:hint_text].to_json}, |
30 | 34 | noResultsText: #{options[:no_results_text].to_json}, |
31 | 35 | searchingText: #{options[:searching_text].to_json}, |
36 | + placeholder: #{options[:placeholder].to_json}, | |
32 | 37 | searchDelay: #{options[:search_delay].to_json}, |
33 | 38 | preventDuplicates: #{options[:prevent_duplicates].to_json}, |
34 | 39 | backspaceDeleteItem: #{options[:backspace_delete_item].to_json}, |
... | ... | @@ -39,6 +44,9 @@ module TokenHelper |
39 | 44 | onAdd: #{options[:on_add]}, |
40 | 45 | onDelete: #{options[:on_delete]}, |
41 | 46 | onReady: #{options[:on_ready]}, |
47 | + theme: #{options[:theme] == 'null' ? options[:theme] : options[:theme].to_json}, | |
48 | + resultsFormater: #{options[:results_formatter]}, | |
49 | + tokenFormater: #{options[:token_formatter]}, | |
42 | 50 | }); |
43 | 51 | ") |
44 | 52 | result += javascript_tag("jQuery('##{element_id}').focus();") if options[:focus] | ... | ... |
app/jobs/notify_activity_to_profiles_job.rb
... | ... | @@ -11,7 +11,7 @@ class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id) |
11 | 11 | tracked_action = ActionTracker::Record.find(tracked_action_id) |
12 | 12 | return unless tracked_action.user.present? |
13 | 13 | target = tracked_action.target |
14 | - if target.is_a?(Community) && ( NOTIFY_ONLY_COMMUNITY.include?(tracked_action.verb) || ! target.public_profile ) | |
14 | + if target.is_a?(Community) && NOTIFY_ONLY_COMMUNITY.include?(tracked_action.verb) | |
15 | 15 | ActionTrackerNotification.create(:profile_id => target.id, :action_tracker_id => tracked_action.id) |
16 | 16 | return |
17 | 17 | end |
... | ... | @@ -19,8 +19,13 @@ class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id) |
19 | 19 | # Notify the user |
20 | 20 | ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id) |
21 | 21 | |
22 | - # Notify all followers | |
23 | - ActionTrackerNotification.connection.execute("INSERT INTO action_tracker_notifications(profile_id, action_tracker_id) SELECT DISTINCT c.person_id, #{tracked_action.id} FROM profiles_circles AS p JOIN circles as c ON c.id = p.circle_id WHERE p.profile_id = #{tracked_action.user.id} AND (c.person_id NOT IN (SELECT atn.profile_id FROM action_tracker_notifications AS atn WHERE atn.action_tracker_id = #{tracked_action.id}))") | |
22 | + if target.is_a?(Scrap) && target.marked_people.present? | |
23 | + # Notify only marked people | |
24 | + ActionTrackerNotification.connection.execute("INSERT INTO action_tracker_notifications(profile_id, action_tracker_id) SELECT DISTINCT profiles.id, #{tracked_action.id} FROM profiles WHERE profiles.id IN (#{target.marked_people.map(&:id).join(',')})") | |
25 | + else | |
26 | + # Notify all followers | |
27 | + ActionTrackerNotification.connection.execute("INSERT INTO action_tracker_notifications(profile_id, action_tracker_id) SELECT DISTINCT c.person_id, #{tracked_action.id} FROM profiles_circles AS p JOIN circles as c ON c.id = p.circle_id WHERE p.profile_id = #{tracked_action.user.id} AND (c.person_id NOT IN (SELECT atn.profile_id FROM action_tracker_notifications AS atn WHERE atn.action_tracker_id = #{tracked_action.id}))") | |
28 | + end | |
24 | 29 | |
25 | 30 | if tracked_action.user.is_a? Organization |
26 | 31 | ActionTrackerNotification.connection.execute "insert into action_tracker_notifications(profile_id, action_tracker_id) " + | ... | ... |
app/models/approve_article.rb
... | ... | @@ -9,9 +9,6 @@ class ApproveArticle < Task |
9 | 9 | if target.person? && requestor != target |
10 | 10 | self.errors.add(:requestor, _('You can not post articles to other users.')) |
11 | 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 | 12 | end |
16 | 13 | end |
17 | 14 | ... | ... |
app/models/article.rb
1 | 1 | |
2 | 2 | class Article < ApplicationRecord |
3 | 3 | |
4 | + module Editor | |
5 | + TEXTILE = 'textile' | |
6 | + TINY_MCE = 'tiny_mce' | |
7 | + RAW_HTML = 'raw_html' | |
8 | + end | |
9 | + | |
4 | 10 | include SanitizeHelper |
5 | 11 | |
6 | 12 | attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, |
... | ... | @@ -11,7 +17,7 @@ class Article < ApplicationRecord |
11 | 17 | :highlighted, :notify_comments, :display_hits, :slug, |
12 | 18 | :external_feed_builder, :display_versions, :external_link, |
13 | 19 | :image_builder, :show_to_followers, :archived, |
14 | - :author, :display_preview, :published_at, :person_followers | |
20 | + :author, :display_preview, :published_at, :person_followers, :editor | |
15 | 21 | |
16 | 22 | extend ActsAsHavingImage::ClassMethods |
17 | 23 | acts_as_having_image |
... | ... | @@ -57,7 +63,7 @@ class Article < ApplicationRecord |
57 | 63 | _('Content') |
58 | 64 | end |
59 | 65 | |
60 | - track_actions :create_article, :after_create, :keep_params => [:name, :url, :lead, :first_image], :if => Proc.new { |a| a.is_trackable? && !a.image? } | |
66 | + track_actions :create_article, :after_create, :keep_params => [:name, :url, :lead, :first_image], :if => Proc.new { |a| a.notifiable? } | |
61 | 67 | |
62 | 68 | # xss_terminate plugin can't sanitize array fields |
63 | 69 | # sanitize_tag_list is used with SanitizeHelper |
... | ... | @@ -177,10 +183,6 @@ class Article < ApplicationRecord |
177 | 183 | end |
178 | 184 | end |
179 | 185 | |
180 | - def is_trackable? | |
181 | - self.published? && self.notifiable? && self.advertise? && self.profile.public_profile | |
182 | - end | |
183 | - | |
184 | 186 | def external_link=(link) |
185 | 187 | if !link.blank? && link !~ /^[a-z]+:\/\//i |
186 | 188 | link = 'http://' + link |
... | ... | @@ -518,17 +520,12 @@ class Article < ApplicationRecord |
518 | 520 | ['Folder', 'Blog', 'Forum', 'Gallery'] |
519 | 521 | end |
520 | 522 | |
521 | - def self.text_article_types | |
522 | - ['TextArticle', 'TextileArticle', 'TinyMceArticle'] | |
523 | - end | |
524 | - | |
525 | 523 | scope :published, -> { where 'articles.published = ?', true } |
526 | 524 | scope :folders, -> profile { where 'articles.type IN (?)', profile.folder_types } |
527 | 525 | scope :no_folders, -> profile { where 'articles.type NOT IN (?)', profile.folder_types } |
528 | 526 | scope :galleries, -> { where "articles.type IN ('Gallery')" } |
529 | 527 | scope :images, -> { where :is_image => true } |
530 | 528 | scope :no_images, -> { where :is_image => false } |
531 | - scope :text_articles, -> { where 'articles.type IN (?)', text_article_types } | |
532 | 529 | scope :files, -> { where :type => 'UploadedFile' } |
533 | 530 | scope :with_types, -> types { where 'articles.type IN (?)', types } |
534 | 531 | |
... | ... | @@ -711,10 +708,6 @@ class Article < ApplicationRecord |
711 | 708 | false |
712 | 709 | end |
713 | 710 | |
714 | - def tiny_mce? | |
715 | - false | |
716 | - end | |
717 | - | |
718 | 711 | def folder? |
719 | 712 | false |
720 | 713 | end |
... | ... | @@ -848,7 +841,7 @@ class Article < ApplicationRecord |
848 | 841 | end |
849 | 842 | |
850 | 843 | def create_activity |
851 | - if is_trackable? && !image? | |
844 | + if notifiable? && !image? | |
852 | 845 | save_action_for_verb 'create_article', [:name, :url, :lead, :first_image], Proc.new{}, :author |
853 | 846 | end |
854 | 847 | end |
... | ... | @@ -879,6 +872,10 @@ class Article < ApplicationRecord |
879 | 872 | true |
880 | 873 | end |
881 | 874 | |
875 | + def editor?(editor) | |
876 | + self.editor == editor | |
877 | + end | |
878 | + | |
882 | 879 | private |
883 | 880 | |
884 | 881 | def sanitize_tag_list | ... | ... |
app/models/block.rb
app/models/circle.rb
app/models/comment.rb
... | ... | @@ -212,6 +212,9 @@ class Comment < ApplicationRecord |
212 | 212 | user == author || user == profile || user.has_permission?(:moderate_comments, profile) |
213 | 213 | end |
214 | 214 | |
215 | + # method used by the API | |
216 | + alias_method :allow_destroy?, :can_be_destroyed_by? | |
217 | + | |
215 | 218 | def can_be_marked_as_spam_by?(user) |
216 | 219 | return if user.nil? |
217 | 220 | user == profile || user.has_permission?(:moderate_comments, profile) | ... | ... |
app/models/event.rb
app/models/external_feed.rb
app/models/favorite_enterprise_person.rb
... | ... | @@ -2,7 +2,7 @@ class FavoriteEnterprisePerson < ApplicationRecord |
2 | 2 | |
3 | 3 | attr_accessible :person, :enterprise |
4 | 4 | |
5 | - track_actions :favorite_enterprise, :after_create, keep_params: [:enterprise_name, :enterprise_url], if: proc{ |f| f.is_trackable? } | |
5 | + track_actions :favorite_enterprise, :after_create, keep_params: [:enterprise_name, :enterprise_url], if: proc{ |f| f.notifiable? } | |
6 | 6 | |
7 | 7 | belongs_to :enterprise |
8 | 8 | belongs_to :person |
... | ... | @@ -13,7 +13,7 @@ class FavoriteEnterprisePerson < ApplicationRecord |
13 | 13 | |
14 | 14 | protected |
15 | 15 | |
16 | - def is_trackable? | |
16 | + def notifiable? | |
17 | 17 | self.enterprise.public? |
18 | 18 | end |
19 | 19 | ... | ... |
app/models/gallery.rb
app/models/organization.rb
... | ... | @@ -20,33 +20,28 @@ class Organization < Profile |
20 | 20 | # visible. |
21 | 21 | # 4) The user is not a member of the organization but the organization is |
22 | 22 | # visible, public and enabled. |
23 | - def self.listed_for_person(person) | |
23 | + scope :listed_for_person, lambda { |person| | |
24 | + | |
24 | 25 | joins('LEFT JOIN "role_assignments" ON ("role_assignments"."resource_id" = "profiles"."id" |
25 | 26 | AND "role_assignments"."resource_type" = \'Profile\') OR ( |
26 | 27 | "role_assignments"."resource_id" = "profiles"."environment_id" AND |
27 | 28 | "role_assignments"."resource_type" = \'Environment\' )') |
28 | 29 | .joins('LEFT JOIN "roles" ON "role_assignments"."role_id" = "roles"."id"') |
29 | 30 | .where( |
30 | - ['( (roles.key = ? OR roles.key = ?) AND role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) | |
31 | - OR | |
32 | - ( ( ( role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR | |
33 | - ( profiles.enabled = ? ) ) AND | |
34 | - ( profiles.visible = ? ) )', | |
35 | - 'profile_admin', 'environment_administrator', Profile.name, person.id, | |
36 | - Profile.name, person.id, true, true] | |
37 | - ).uniq | |
38 | - end | |
39 | - | |
40 | - def self.visible_for_person(person) | |
41 | - listed_for_person(person).where( | |
42 | - ['( (roles.key = ? OR roles.key = ?) AND role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) | |
43 | - OR | |
31 | + ['( (roles.key = ? OR roles.key = ?) AND role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR ( | |
32 | + ( ( role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR ( profiles.enabled = ?)) AND (profiles.visible = ?) )', | |
33 | + 'profile_admin', 'environment_administrator', Profile.name, person.id, Profile.name, person.id, true, true] | |
34 | + ).uniq | |
35 | + } | |
36 | + | |
37 | + scope :visible_for_person, lambda { |person| | |
38 | + listed_for_person(person).where( [' | |
44 | 39 | ( ( role_assignments.accessor_type = ? AND role_assignments.accessor_id = ? ) OR |
45 | - ( profiles.enabled = ? AND profiles.public_profile = ? ) )', | |
46 | - 'profile_admin', 'environment_administrator', Profile.name, person.id, | |
40 | + ( profiles.enabled = ? AND profiles.public_profile = ? ) )', | |
47 | 41 | Profile.name, person.id, true, true] |
48 | 42 | ) |
49 | - end | |
43 | + } | |
44 | + | |
50 | 45 | |
51 | 46 | settings_items :closed, :type => :boolean, :default => false |
52 | 47 | def closed? | ... | ... |
app/models/person.rb
1 | 1 | # A person is the profile of an user holding all relationships with the rest of the system |
2 | 2 | class Person < Profile |
3 | 3 | |
4 | - attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website, :following_articles | |
4 | + attr_accessible :organization, :contact_information, :sex, :birth_date, :cell_phone, :comercial_phone, :jabber_id, :personal_website, :nationality, :address_reference, :district, :schooling, :schooling_status, :formation, :custom_formation, :area_of_study, :custom_area_of_study, :professional_activity, :organization_website, :following_articles, :editor | |
5 | 5 | |
6 | 6 | SEARCH_FILTERS = { |
7 | 7 | :order => %w[more_recent more_popular more_active], |
... | ... | @@ -124,6 +124,8 @@ class Person < Profile |
124 | 124 | where 'profile_suggestions.suggestion_type = ? AND profile_suggestions.enabled = ?', 'Community', true |
125 | 125 | }, through: :suggested_profiles, source: :suggestion |
126 | 126 | |
127 | + has_and_belongs_to_many :marked_scraps, :join_table => :private_scraps, :class_name => 'Scrap' | |
128 | + | |
127 | 129 | scope :more_popular, -> { order 'friends_count DESC' } |
128 | 130 | |
129 | 131 | scope :abusers, -> { |
... | ... | @@ -344,6 +346,8 @@ class Person < Profile |
344 | 346 | |
345 | 347 | validates_associated :user |
346 | 348 | |
349 | + validates :editor, inclusion: { in: lambda { |p| p.available_editors } } | |
350 | + | |
347 | 351 | def email |
348 | 352 | self.user.nil? ? nil : self.user.email |
349 | 353 | end |
... | ... | @@ -616,8 +620,21 @@ class Person < Profile |
616 | 620 | Profile.followed_by self |
617 | 621 | end |
618 | 622 | |
623 | + def editor?(editor) | |
624 | + self.editor == editor | |
625 | + end | |
626 | + | |
619 | 627 | def in_social_circle?(person) |
620 | 628 | self.is_a_friend?(person) || super |
621 | 629 | end |
622 | 630 | |
631 | + def available_editors | |
632 | + available_editors = { | |
633 | + Article::Editor::TINY_MCE => _('TinyMCE'), | |
634 | + Article::Editor::TEXTILE => _('Textile') | |
635 | + } | |
636 | + available_editors.merge!({Article::Editor::RAW_HTML => _('Raw HTML')}) if self.is_admin? | |
637 | + available_editors | |
638 | + end | |
639 | + | |
623 | 640 | end | ... | ... |
app/models/profile.rb
... | ... | @@ -885,13 +885,14 @@ private :generate_url, :url_options |
885 | 885 | |
886 | 886 | # returns +true+ if the given +user+ can see profile information about this |
887 | 887 | # +profile+, and +false+ otherwise. |
888 | - def display_info_to?(user) | |
888 | + def display_info_to?(user = nil) | |
889 | 889 | if self.public? |
890 | 890 | true |
891 | 891 | else |
892 | 892 | display_private_info_to?(user) |
893 | 893 | end |
894 | 894 | end |
895 | + alias_method :display_to?, :display_info_to? | |
895 | 896 | |
896 | 897 | after_save :update_category_from_region |
897 | 898 | def update_category_from_region | ... | ... |
app/models/raw_html_article.rb
... | ... | @@ -1,17 +0,0 @@ |
1 | -class RawHTMLArticle < TextArticle | |
2 | - | |
3 | - def self.type_name | |
4 | - _('HTML') | |
5 | - end | |
6 | - | |
7 | - def self.short_description | |
8 | - _('Raw HTML text article') | |
9 | - end | |
10 | - | |
11 | - def self.description | |
12 | - _('Allows HTML without filter (only for admins).') | |
13 | - end | |
14 | - | |
15 | - xss_terminate :only => [ ] | |
16 | - | |
17 | -end |
app/models/scrap.rb
... | ... | @@ -2,7 +2,7 @@ class Scrap < ApplicationRecord |
2 | 2 | |
3 | 3 | include SanitizeHelper |
4 | 4 | |
5 | - attr_accessible :content, :sender_id, :receiver_id, :scrap_id | |
5 | + attr_accessible :content, :sender_id, :receiver_id, :scrap_id, :marked_people | |
6 | 6 | |
7 | 7 | SEARCHABLE_FIELDS = { |
8 | 8 | :content => {:label => _('Content'), :weight => 1}, |
... | ... | @@ -19,6 +19,8 @@ class Scrap < ApplicationRecord |
19 | 19 | where profile_activities: {activity_type: 'Scrap'} |
20 | 20 | }, foreign_key: :activity_id, dependent: :destroy |
21 | 21 | |
22 | + has_and_belongs_to_many :marked_people, :join_table => :private_scraps, :class_name => 'Person' | |
23 | + | |
22 | 24 | after_create :create_activity |
23 | 25 | after_update :update_activity |
24 | 26 | |
... | ... | @@ -65,6 +67,10 @@ class Scrap < ApplicationRecord |
65 | 67 | sender != receiver && (is_root? ? root.receiver.receives_scrap_notification? : receiver.receives_scrap_notification?) |
66 | 68 | end |
67 | 69 | |
70 | + def display_to?(user = nil) | |
71 | + marked_people.blank? || marked_people.include?(user) | |
72 | + end | |
73 | + | |
68 | 74 | protected |
69 | 75 | |
70 | 76 | def create_activity | ... | ... |
app/models/suggest_article.rb
... | ... | @@ -44,7 +44,7 @@ class SuggestArticle < Task |
44 | 44 | type = article[:type].constantize |
45 | 45 | return type if type < Article |
46 | 46 | end |
47 | - TinyMceArticle | |
47 | + TextArticle | |
48 | 48 | end |
49 | 49 | |
50 | 50 | def perform |
... | ... | @@ -65,7 +65,7 @@ class SuggestArticle < Task |
65 | 65 | |
66 | 66 | def information |
67 | 67 | variables = requestor.blank? ? {:requestor => sender} : {} |
68 | - { :message => _('%{requestor} suggested the publication of the article: %{subject}.').html_safe, | |
68 | + { :message => _('%{requestor} suggested the publication %{target_detail} of the article: %{subject}.').html_safe, | |
69 | 69 | :variables => variables } |
70 | 70 | end |
71 | 71 | ... | ... |
app/models/text_article.rb
1 | 1 | # a base class for all text article types. |
2 | 2 | class TextArticle < Article |
3 | 3 | |
4 | - xss_terminate :only => [ :name ], :on => 'validation' | |
4 | + def self.short_description | |
5 | + _('Text article') | |
6 | + end | |
7 | + | |
8 | + def self.description | |
9 | + _('Text article to create user content.') | |
10 | + end | |
11 | + | |
12 | + xss_terminate :only => [ :name, :body, :abstract ], :with => 'white_list', :on => 'validation', :if => lambda { |a| !a.editor?(Article::Editor::TEXTILE) && !a.editor?(Article::Editor::RAW_HTML) } | |
13 | + | |
14 | + include WhiteListFilter | |
15 | + filter_iframes :abstract, :body | |
16 | + def iframe_whitelist | |
17 | + profile && profile.environment && profile.environment.trusted_sites_for_iframe | |
18 | + end | |
5 | 19 | |
6 | 20 | def self.type_name |
7 | 21 | _('Article') |
... | ... | @@ -21,6 +35,18 @@ class TextArticle < Article |
21 | 35 | true |
22 | 36 | end |
23 | 37 | |
38 | + def can_display_media_panel? | |
39 | + true | |
40 | + end | |
41 | + | |
42 | + def self.can_display_blocks? | |
43 | + false | |
44 | + end | |
45 | + | |
46 | + def notifiable? | |
47 | + true | |
48 | + end | |
49 | + | |
24 | 50 | before_save :set_relative_path |
25 | 51 | |
26 | 52 | def set_relative_path |
... | ... | @@ -43,4 +69,24 @@ class TextArticle < Article |
43 | 69 | parent && parent.kind_of?(Blog) && parent.display_preview |
44 | 70 | end |
45 | 71 | |
72 | + def to_html(options ={}) | |
73 | + content = super(options) | |
74 | + content = convert_textile_to_html(content) if self.editor?(Article::Editor::TEXTILE) | |
75 | + content | |
76 | + end | |
77 | + | |
78 | + def lead(length = nil) | |
79 | + content = super(length) | |
80 | + content = convert_textile_to_html(content) if self.editor?(Article::Editor::TEXTILE) | |
81 | + content | |
82 | + end | |
83 | + | |
84 | + protected | |
85 | + | |
86 | + def convert_textile_to_html(textile) | |
87 | + converter = RedCloth.new(textile|| '') | |
88 | + converter.hard_breaks = false | |
89 | + sanitize_html(converter.to_html, :white_list) | |
90 | + end | |
91 | + | |
46 | 92 | end | ... | ... |
app/models/textile_article.rb
... | ... | @@ -1,44 +0,0 @@ |
1 | -class TextileArticle < TextArticle | |
2 | - include SanitizeHelper | |
3 | - | |
4 | - def self.short_description | |
5 | - _('Text article with Textile markup language') | |
6 | - end | |
7 | - | |
8 | - def self.description | |
9 | - _('Accessible alternative for visually impaired users.') | |
10 | - end | |
11 | - | |
12 | - def to_html(options ={}) | |
13 | - convert_to_html(body) | |
14 | - end | |
15 | - | |
16 | - def lead(length = nil) | |
17 | - if abstract.blank? | |
18 | - super | |
19 | - else | |
20 | - convert_to_html(abstract) | |
21 | - end | |
22 | - end | |
23 | - | |
24 | - def notifiable? | |
25 | - true | |
26 | - end | |
27 | - | |
28 | - def can_display_media_panel? | |
29 | - true | |
30 | - end | |
31 | - | |
32 | - def self.can_display_blocks? | |
33 | - false | |
34 | - end | |
35 | - | |
36 | - protected | |
37 | - | |
38 | - def convert_to_html(textile) | |
39 | - converter = RedCloth.new(textile|| '') | |
40 | - converter.hard_breaks = false | |
41 | - sanitize_html(converter.to_html, :white_list) | |
42 | - end | |
43 | - | |
44 | -end |
app/models/tiny_mce_article.rb
... | ... | @@ -1,37 +0,0 @@ |
1 | -class TinyMceArticle < TextArticle | |
2 | - | |
3 | - def self.short_description | |
4 | - _('Text article with visual editor') | |
5 | - end | |
6 | - | |
7 | - def self.description | |
8 | - _('Not accessible for visually impaired users.') | |
9 | - end | |
10 | - | |
11 | - xss_terminate :only => [ ] | |
12 | - | |
13 | - xss_terminate :only => [ :name, :abstract, :body ], :with => 'white_list', :on => 'validation' | |
14 | - | |
15 | - include WhiteListFilter | |
16 | - filter_iframes :abstract, :body | |
17 | - def iframe_whitelist | |
18 | - profile && profile.environment && profile.environment.trusted_sites_for_iframe | |
19 | - end | |
20 | - | |
21 | - def notifiable? | |
22 | - true | |
23 | - end | |
24 | - | |
25 | - def tiny_mce? | |
26 | - true | |
27 | - end | |
28 | - | |
29 | - def can_display_media_panel? | |
30 | - true | |
31 | - end | |
32 | - | |
33 | - def self.can_display_blocks? | |
34 | - false | |
35 | - end | |
36 | - | |
37 | -end |
app/models/uploaded_file.rb
... | ... | @@ -9,6 +9,12 @@ class UploadedFile < Article |
9 | 9 | |
10 | 10 | attr_accessible :uploaded_data, :title |
11 | 11 | |
12 | + include Noosfero::Plugin::HotSpot | |
13 | + | |
14 | + def environment | |
15 | + profile.environment | |
16 | + end | |
17 | + | |
12 | 18 | def self.type_name |
13 | 19 | _('File') |
14 | 20 | end |
... | ... | @@ -184,8 +190,12 @@ class UploadedFile < Article |
184 | 190 | true |
185 | 191 | end |
186 | 192 | |
193 | + def image? | |
194 | + mime_type =~ /^image\// | |
195 | + end | |
196 | + | |
187 | 197 | def notifiable? |
188 | - true | |
198 | + !image? | |
189 | 199 | end |
190 | 200 | |
191 | 201 | end | ... | ... |
... | ... | @@ -0,0 +1,44 @@ |
1 | +class ActivityPresenter < Presenter | |
2 | + def self.base_class | |
3 | + ActionTracker::Record | |
4 | + end | |
5 | + | |
6 | + def self.available?(instance) | |
7 | + instance.kind_of?(ActionTracker::Record) || instance.kind_of?(ProfileActivity) | |
8 | + end | |
9 | + | |
10 | + def self.target(instance) | |
11 | + if instance.kind_of?(ProfileActivity) | |
12 | + target(instance.activity) | |
13 | + elsif instance.kind_of?(ActionTracker::Record) | |
14 | + instance.target | |
15 | + else | |
16 | + instance | |
17 | + end | |
18 | + end | |
19 | + | |
20 | + def self.owner(instance) | |
21 | + instance.kind_of?(ProfileActivity) ? instance.profile : instance.user | |
22 | + end | |
23 | + | |
24 | + def target | |
25 | + self.class.target(encapsulated_instance) | |
26 | + end | |
27 | + | |
28 | + def owner | |
29 | + self.class.owner(encapsulated_instance) | |
30 | + end | |
31 | + | |
32 | + def hidden_for?(user) | |
33 | + target.respond_to?(:display_to?) && !target.display_to?(user) | |
34 | + end | |
35 | + | |
36 | + def involved?(user) | |
37 | + owner == user || target == user | |
38 | + end | |
39 | +end | |
40 | + | |
41 | +# Preload ActivityPresenter subclasses to allow `Presenter.for()` to work | |
42 | +Dir.glob(File.join('app', 'presenters', 'activity', '*.rb')) do |file| | |
43 | + load file | |
44 | +end | ... | ... |
... | ... | @@ -0,0 +1,23 @@ |
1 | +class FilePresenter::Image < FilePresenter | |
2 | + def self.accepts?(f) | |
3 | + return nil unless f.respond_to? :image? | |
4 | + f.image? ? 10 : nil | |
5 | + end | |
6 | + | |
7 | + def sized_icon(size) | |
8 | + public_filename size | |
9 | + end | |
10 | + | |
11 | + def icon_name | |
12 | + public_filename :icon | |
13 | + end | |
14 | + | |
15 | + def short_description | |
16 | + _('Image (%s)') % content_type.split('/')[1].upcase | |
17 | + end | |
18 | + | |
19 | + #Overwriting method from FilePresenter to allow download of images | |
20 | + def download?(view = nil) | |
21 | + view.blank? || view == 'false' | |
22 | + end | |
23 | +end | ... | ... |
... | ... | @@ -0,0 +1,80 @@ |
1 | +class FilePresenter < Presenter | |
2 | + def self.base_class | |
3 | + Article | |
4 | + end | |
5 | + | |
6 | + def self.available?(instance) | |
7 | + instance.kind_of?(UploadedFile) && !instance.kind_of?(Image) | |
8 | + end | |
9 | + | |
10 | + def download? view = nil | |
11 | + view.blank? | |
12 | + end | |
13 | + | |
14 | + def short_description | |
15 | + file_type = if content_type.present? | |
16 | + content_type.sub(/^application\//, '').sub(/^x-/, '').sub(/^image\//, '') | |
17 | + else | |
18 | + _('Unknown') | |
19 | + end | |
20 | + _("File (%s)") % file_type | |
21 | + end | |
22 | + | |
23 | + # Define the css classes to style the page fragment with the file related | |
24 | + # content. If you want other classes to identify this area to your | |
25 | + # customized presenter, so do this: | |
26 | + # def css_class_list | |
27 | + # [super, 'myclass'].flatten | |
28 | + # end | |
29 | + def css_class_list | |
30 | + [ encapsulated_instance.css_class_list, | |
31 | + 'file-' + self.class.to_s.split(/:+/).map(&:underscore)[1..-1].join('-'), | |
32 | + 'content-type_' + self.content_type.split('/')[0], | |
33 | + 'content-type_' + self.content_type.gsub(/[^a-z0-9]/i,'-') | |
34 | + ].flatten | |
35 | + end | |
36 | + | |
37 | + # Enable file presenter to customize the css classes on view_page.rhtml | |
38 | + # You may not overwrite this method on your customized presenter. | |
39 | + def css_class_name | |
40 | + [css_class_list].flatten.compact.join(' ') | |
41 | + end | |
42 | + | |
43 | + # The generic icon class-name or the specific file path. | |
44 | + # You may replace this method on your custom FilePresenter. | |
45 | + # See the current used icons class-names in public/designs/icons/tango/style.css | |
46 | + def icon_name | |
47 | + if mime_type | |
48 | + [ mime_type.split('/')[0], mime_type.gsub(/[^a-z0-9]/i, '-') ] | |
49 | + else | |
50 | + 'upload-file' | |
51 | + end | |
52 | + end | |
53 | + | |
54 | + # Automatic render `file_presenter/<custom>.html.erb` to display your | |
55 | + # custom presenter html content. | |
56 | + # You may not overwrite this method on your customized presenter. | |
57 | + # A variable with the same presenter name will be created to refer | |
58 | + # to the file object. | |
59 | + # Example: | |
60 | + # The `FilePresenter::Image` render `file_presenter/image.html.erb` | |
61 | + # inside the `file_presenter/image.html.erb` you can access the | |
62 | + # required `FilePresenter::Image` instance in the `image` variable. | |
63 | + def to_html(options = {}) | |
64 | + file = self | |
65 | + proc do | |
66 | + render :partial => file.class.to_s.underscore, | |
67 | + :locals => { :options => options }, | |
68 | + :object => file | |
69 | + end | |
70 | + end | |
71 | +end | |
72 | + | |
73 | +Dir.glob(File.join('app', 'presenters', 'file', '*.rb')) do |file| | |
74 | + load file | |
75 | +end | |
76 | + | |
77 | +# Preload FilePresenters from plugins to allow `FilePresenter.for()` to work | |
78 | +Dir.glob(File.join('plugins', '*', 'lib', 'presenters', '*.rb')) do |file| | |
79 | + load file | |
80 | +end | ... | ... |
app/presenters/generic.rb
app/presenters/image.rb
... | ... | @@ -1,23 +0,0 @@ |
1 | -class FilePresenter::Image < FilePresenter | |
2 | - def self.accepts?(f) | |
3 | - return nil unless f.respond_to? :image? | |
4 | - f.image? ? 10 : nil | |
5 | - end | |
6 | - | |
7 | - def sized_icon(size) | |
8 | - public_filename size | |
9 | - end | |
10 | - | |
11 | - def icon_name | |
12 | - public_filename :icon | |
13 | - end | |
14 | - | |
15 | - def short_description | |
16 | - _('Image (%s)') % content_type.split('/')[1].upcase | |
17 | - end | |
18 | - | |
19 | - #Overwriting method from FilePresenter to allow download of images | |
20 | - def download?(view = nil) | |
21 | - view.blank? || view == 'false' | |
22 | - end | |
23 | -end |
app/views/account/_signup_form.html.erb
... | ... | @@ -111,7 +111,7 @@ |
111 | 111 | |
112 | 112 | <% unless @terms_of_use.blank? %> |
113 | 113 | <div id='terms-of-use-box' class='formfieldline'> |
114 | - <%= labelled_check_box(_('I accept the %s') % link_to(_('terms of use'), {:controller => 'home', :action => 'terms'}, :target => '_blank'), 'user[terms_accepted]') %> | |
114 | + <%= labelled_check_box(_('I accept the %s').html_safe % link_to(_('terms of use'), {:controller => 'home', :action => 'terms'}, :target => '_blank'), 'user[terms_accepted]') %> | |
115 | 115 | </div> |
116 | 116 | <% end %> |
117 | 117 | ... | ... |
app/views/admin_panel/_signup_intro.html.erb
... | ... | @@ -2,4 +2,4 @@ |
2 | 2 | <%= _('This text will be shown to the user on the top of the sign up form.') %> |
3 | 3 | </div> |
4 | 4 | |
5 | -<%= labelled_form_field(_('Body'), text_area(:environment, :signup_intro, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %> | |
5 | +<%= labelled_form_field(_('Body'), text_area(:environment, :signup_intro, :cols => 40, :style => 'width: 100%', :class => current_editor)) %> | ... | ... |
app/views/admin_panel/_signup_welcome_screen.html.erb
1 | 1 | <div class='description'> |
2 | 2 | <%= _('If you enable this feature on the "Features" section of the Administration Panel, this text will be shown as a welcome message to users after signup.') %> |
3 | 3 | </div> |
4 | -<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_screen_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %> | |
4 | +<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_screen_body, :cols => 40, :style => 'width: 100%', :class => current_editor)) %> | |
5 | 5 | |
6 | 6 | <div class='description'> |
7 | 7 | <%= _('If this content is left blank, the following page will be displayed to the user:') %> | ... | ... |
app/views/admin_panel/_signup_welcome_text.html.erb
... | ... | @@ -4,4 +4,4 @@ |
4 | 4 | </div> |
5 | 5 | |
6 | 6 | <%= labelled_form_field(_('Subject'), text_field(:environment, :signup_welcome_text_subject, :style => 'width:100%')) %> |
7 | -<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_text_body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor')) %> | |
7 | +<%= labelled_form_field(_('Body'), text_area(:environment, :signup_welcome_text_body, :cols => 40, :style => 'width: 100%', :class => current_editor)) %> | ... | ... |
app/views/admin_panel/_site_info.html.erb
... | ... | @@ -31,4 +31,4 @@ |
31 | 31 | <%= balanced_table(fields)%> |
32 | 32 | |
33 | 33 | <br /> |
34 | -<%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => 'mceEditor') %> | |
34 | +<%= labelled_form_field _('Homepage content'), text_area(:environment, :description, :cols => 40, :style => 'width: 90%', :class => current_editor) %> | ... | ... |
app/views/admin_panel/_terms_of_use.html.erb
app/views/admin_panel/message_for_disabled_enterprise.html.erb
1 | 1 | <h2><%= _('Site info') %></h2> |
2 | 2 | |
3 | -<%= render :file => 'shared/tiny_mce' %> | |
4 | - | |
5 | 3 | <%= labelled_form_for :environment, :url => {:action => 'site_info'} do |f| %> |
6 | 4 | |
7 | - <%= f.text_area :message_for_disabled_enterprise, :cols => 40, :style => 'width: 90%' %> | |
5 | + <%= f.text_area :message_for_disabled_enterprise, :cols => 40, :style => 'width: 90%', :class => current_editor %> | |
8 | 6 | |
9 | 7 | <%= button_bar do %> |
10 | 8 | <%= submit_button(:save, _('Save')) %> | ... | ... |
app/views/admin_panel/site_info.html.erb
app/views/api/index.html.erb
1 | 1 | <h1>EndPoints</h1> |
2 | 2 | |
3 | 3 | <div style="float: right"> |
4 | - <%= s_('api-playground|Try the %s') % link_to('API Playground', {:controller => 'api', :action => 'playground'}) %> | |
4 | + <%= s_('api-playground|Try the %s').html_safe % link_to('API Playground', {:controller => 'api', :action => 'playground'}) %> | |
5 | 5 | </div> |
6 | 6 | |
7 | 7 | <%= endpoints.map do |endpoint| |
8 | 8 | app = endpoint.options[:app].to_s |
9 | 9 | unless app.blank? |
10 | - content_tag(:h2, app.split('::').last.to_s, title: app) + | |
10 | + content_tag(:h2, app.split('::').last.to_s, title: app).html_safe + | |
11 | 11 | (content_tag :ul do |
12 | 12 | endpoint.routes.map do |route| |
13 | 13 | content_tag :li do |
14 | 14 | content_tag(:strong, route.route_method) + ' ' + |
15 | - route.route_path.gsub(':version', content_tag(:b, route.route_version)) | |
15 | + route.route_path.gsub(':version', content_tag(:b, route.route_version)).html_safe | |
16 | 16 | end |
17 | - end.join "\n" | |
17 | + end.safe_join "\n" | |
18 | 18 | end) |
19 | 19 | end |
20 | -end.join "\n" %> | |
20 | +end.safe_join "\n" %> | ... | ... |
app/views/categories/_form.html.erb
1 | -<%= stylesheet_link_tag 'spectrum.css' %> | |
2 | -<%= javascript_include_tag "spectrum.js" %> | |
1 | +<%= stylesheet_link_tag 'vendor/spectrum.css' %> | |
2 | +<%= javascript_include_tag "vendor/spectrum.js" %> | |
3 | 3 | <%= javascript_include_tag "colorpicker-noosfero.js" %> |
4 | 4 | |
5 | 5 | <%= error_messages_for 'category' %> | ... | ... |
app/views/cms/_article.html.erb
app/views/cms/_blog.html.erb
... | ... | @@ -2,8 +2,6 @@ |
2 | 2 | |
3 | 3 | <h1><%= _('My Blog') %></h1> |
4 | 4 | |
5 | -<%= render :file => 'shared/tiny_mce' %> | |
6 | - | |
7 | 5 | <%= required f.text_field(:name, :size => '64', :maxlength => 150, :onchange => "updateUrlField(this, 'article_slug')") %> |
8 | 6 | |
9 | 7 | <%= render :partial => 'general_fields' %> |
... | ... | @@ -53,7 +51,7 @@ |
53 | 51 | %> |
54 | 52 | </div> |
55 | 53 | |
56 | -<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 10, :class => 'mceEditor')) %> | |
54 | +<%= labelled_form_field(_('Description:'), text_area(:article, :body, :rows => 10, :class => current_editor)) %> | |
57 | 55 | |
58 | 56 | <div id="blog-image-builder"> |
59 | 57 | <%= f.fields_for :image_builder, @article.image do |i| %> | ... | ... |
app/views/cms/_enterprise_homepage.html.erb
1 | -<%= render :file => 'shared/tiny_mce' %> | |
2 | - | |
3 | -<%= labelled_form_field(_('Text'), text_area(:article, 'body', :cols => 40, :style => 'width:99%', :class => 'mceEditor')) %> | |
1 | +<%= labelled_form_field(_('Text'), text_area(:article, 'body', :cols => 40, :style => 'width:99%', :class => current_editor)) %> | |
4 | 2 | ... | ... |
app/views/cms/_event.html.erb
1 | 1 | <%= required_fields_message %> |
2 | 2 | |
3 | -<%# TODO add Textile help here %> | |
4 | -<%= render :file => 'shared/tiny_mce' %> | |
5 | - | |
6 | 3 | <%= required f.text_field('name', :size => '64', :maxlength => 150) %> |
7 | 4 | |
8 | 5 | <%= render :partial => 'general_fields' %> |
... | ... | @@ -16,4 +13,4 @@ |
16 | 13 | |
17 | 14 | <%= labelled_form_field(_('Address:'), text_field(:article, :address)) %> |
18 | 15 | |
19 | -<%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :body_label => 'Information about the event:'} %> | |
16 | +<%= render :partial => 'shared/lead_and_body', :locals => {:body_label => 'Information about the event:'} %> | ... | ... |
app/views/cms/_forum.html.erb
... | ... | @@ -4,18 +4,16 @@ |
4 | 4 | |
5 | 5 | <%= required_fields_message %> |
6 | 6 | |
7 | -<%= render :file => 'shared/tiny_mce' %> | |
8 | - | |
9 | 7 | <%= required f.text_field(:name, :size => '64', :maxlength => 150, :onchange => "updateUrlField(this, 'article_slug')") %> |
10 | 8 | |
11 | 9 | <%= render :partial => 'general_fields' %> |
12 | 10 | |
13 | -<%= labelled_form_field(_('Description:'), text_area(:article, :body, :class => 'mceEditor', :cols => 64, :rows => 10)) %> | |
11 | +<%= labelled_form_field(_('Description:'), text_area(:article, :body, :class => current_editor, :cols => 64, :rows => 10)) %> | |
14 | 12 | |
15 | 13 | <%= labelled_form_field(_('Posts per page:'), f.select(:posts_per_page, Forum.posts_per_page_options)) %> |
16 | 14 | |
17 | 15 | <%= labelled_form_field(_('Has terms of use:'), check_box(:article, :has_terms_of_use))%> |
18 | 16 | |
19 | 17 | <div id="text_area_terms_of_use"> |
20 | - <%= labelled_form_field(_('Terms of use:'), text_area(:article, :terms_of_use, :class => 'mceEditor',:cols => 64, :rows => 10)) %> | |
18 | + <%= labelled_form_field(_('Terms of use:'), text_area(:article, :terms_of_use, :class => current_editor,:cols => 64, :rows => 10)) %> | |
21 | 19 | </div> | ... | ... |
app/views/cms/_raw_html_article.html.erb
... | ... | @@ -1,8 +0,0 @@ |
1 | -<%= required_fields_message %> | |
2 | - | |
3 | -<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64', :maxlength => 150)) %> | |
4 | - | |
5 | -<%= render :partial => 'text_fields' %> | |
6 | -<%= render :partial => 'general_fields' %> | |
7 | -<%= render :partial => 'translatable' %> | |
8 | -<%= render :partial => 'shared/lead_and_body' %> |
... | ... | @@ -0,0 +1,10 @@ |
1 | +<%= required_fields_message %> | |
2 | + | |
3 | +<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '72', :maxlength => 150)) %> | |
4 | + | |
5 | +<%= render :partial => 'text_fields' %> | |
6 | +<%= render :partial => 'general_fields' %> | |
7 | +<%= render :partial => 'translatable' %> | |
8 | + | |
9 | +<%= render :partial => 'shared/lead_and_body' %> | |
10 | + | ... | ... |
app/views/cms/_text_editor_sidebar.html.erb
... | ... | @@ -7,7 +7,7 @@ |
7 | 7 | |
8 | 8 | <div class='header'><strong><%= _('Insert media') %></strong><%= button('vertical-toggle', _('Show/Hide'), '#') %></div> |
9 | 9 | |
10 | - <%= render(:partial => 'textile_quick_reference') if @article.is_a?(TextileArticle) %> | |
10 | + <%= render(:partial => 'textile_quick_reference') if @article.editor?(Article::Editor::TEXTILE) %> | |
11 | 11 | <div class='text-editor-sidebar-box' id='media-upload-box'> |
12 | 12 | <div id='media-upload-form'> |
13 | 13 | <%= form_tag({ :action => 'media_upload' }, :multipart => true) do %> |
... | ... | @@ -48,4 +48,4 @@ |
48 | 48 | </script> |
49 | 49 | |
50 | 50 | <%= render :partial => 'media_new_folder', :locals => {:default_folder => default_folder} %> |
51 | -<%= javascript_include_tag 'jquery.fileupload.js', 'tmpl.js', 'media-panel.js' %> | |
51 | +<%= javascript_include_tag 'vendor/jquery.fileupload.js', 'vendor/tmpl.js', 'media-panel.js' %> | ... | ... |
app/views/cms/_textile_article.html.erb
... | ... | @@ -1,10 +0,0 @@ |
1 | -<%= required_fields_message %> | |
2 | - | |
3 | -<%# TODO add Textile help here %> | |
4 | - | |
5 | -<%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '72', :maxlength => 150)) %> | |
6 | - | |
7 | -<%= render :partial => 'text_fields' %> | |
8 | -<%= render :partial => 'general_fields' %> | |
9 | -<%= render :partial => 'translatable' %> | |
10 | -<%= render :partial => 'shared/lead_and_body' %> |
app/views/cms/_tiny_mce_article.html.erb
... | ... | @@ -1,12 +0,0 @@ |
1 | -<%= required_fields_message %> | |
2 | - | |
3 | -<%= render :file => 'shared/tiny_mce' %> | |
4 | - | |
5 | -<div> | |
6 | - <%= required labelled_form_field(_('Title'), text_field(:article, 'name', :size => '64', :maxlength => 150)) %> | |
7 | - | |
8 | - <%= render :partial => 'text_fields' %> | |
9 | - <%= render :partial => 'general_fields' %> | |
10 | - <%= render :partial => 'translatable' %> | |
11 | - <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true} %> | |
12 | -</div> |
app/views/cms/edit.html.erb
app/views/cms/suggest_an_article.html.erb
... | ... | @@ -2,8 +2,6 @@ |
2 | 2 | |
3 | 3 | <%= required_fields_message %> |
4 | 4 | |
5 | -<%= render :file => 'shared/tiny_mce' %> | |
6 | - | |
7 | 5 | <%= labelled_form_for 'task' do |f| %> |
8 | 6 | |
9 | 7 | <%= required labelled_form_field(_('Title'), text_field('task[article]', 'name', :size => 50)) %> |
... | ... | @@ -17,7 +15,7 @@ |
17 | 15 | <%= required labelled_form_field(_('Email'), text_field(:task, 'email')) %> |
18 | 16 | <% end %> |
19 | 17 | |
20 | - <%= render :partial => 'shared/lead_and_body', :locals => {:tiny_mce => true, :object => 'task[article]'} %> | |
18 | + <%= render :partial => 'shared/lead_and_body', :locals => {:object => 'task[article]'} %> | |
21 | 19 | |
22 | 20 | <%= hidden_field_tag('back_to', @back_to) %> |
23 | 21 | ... | ... |
app/views/contact/new.html.erb
... | ... | @@ -25,8 +25,7 @@ |
25 | 25 | |
26 | 26 | <%= required f.text_field(:subject) %> |
27 | 27 | |
28 | - <%= render :file => 'shared/tiny_mce' %> | |
29 | - <%= required f.text_area(:message, :class => 'mceEditor') %> | |
28 | + <%= required f.text_area(:message, :class => current_editor) %> | |
30 | 29 | |
31 | 30 | <%= labelled_form_field check_box(:contact, :receive_a_copy) + _('I want to receive a copy of the message in my e-mail.'), '' %> |
32 | 31 | ... | ... |
app/views/email_templates/_form.html.erb
... | ... | @@ -19,8 +19,7 @@ |
19 | 19 | <%= @template_params_allowed %> |
20 | 20 | </div> |
21 | 21 | </div> |
22 | - <%= render :file => 'shared/tiny_mce' %> | |
23 | - <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %> | |
22 | + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => current_editor)) %> | |
24 | 23 | </div> |
25 | 24 | |
26 | 25 | <div class="actions"> | ... | ... |
app/views/file_presenter/_image.html.erb
1 | 1 | <% if image.gallery? && options[:gallery_view] %> |
2 | 2 | <% |
3 | 3 | images = image.parent.images |
4 | - current_index = images.index(image.encapsulated_file) | |
4 | + current_index = images.index(image.encapsulated_instance) | |
5 | 5 | total_of_images = images.count |
6 | 6 | link_to_previous = if current_index >= 1 |
7 | 7 | link_to(_('« Previous').html_safe, images[current_index - 1].view_url, :class => 'previous') |
... | ... | @@ -30,7 +30,10 @@ |
30 | 30 | |
31 | 31 | <img src="<%= [Noosfero.root, image.public_filename(:display)].join %>" class="<%=image.css_class_name%>"> |
32 | 32 | |
33 | +<% if image.parent.is_a?(Gallery) && image.parent.allow_download %> | |
34 | + <%= link_to _('Download image'), [Noosfero.root, image.public_filename(:display)].join, download: image.filename, id: 'download-image-id', class: "button with-text icon-save" %> | |
35 | +<% end %> | |
36 | + | |
33 | 37 | <div class="uploaded-file-description <%= 'empty' if image.abstract.blank? %>"> |
34 | 38 | <%= image.abstract %> |
35 | 39 | </div> |
36 | - | ... | ... |
app/views/home/terms.html.erb
app/views/layouts/application-ng.html.erb
... | ... | @@ -35,6 +35,9 @@ |
35 | 35 | noosfero.profile = <%= (@profile.identifier if @profile).to_json.html_safe %> |
36 | 36 | </script> |
37 | 37 | |
38 | + <% if current_editor_is?(Article::Editor::TINY_MCE) %> | |
39 | + <%= render :file => 'shared/tiny_mce' %> | |
40 | + <% end %> | |
38 | 41 | </head> |
39 | 42 | <body class="<%= h body_classes %>"> |
40 | 43 | <a href="#content" id="link-go-content"><span><%= _("Go to the content") %></span></a> |
... | ... | @@ -72,7 +75,7 @@ |
72 | 75 | </div><!-- end id="content" --> |
73 | 76 | </div><!-- end id="wrap-2" --> |
74 | 77 | </div><!-- end id="wrap-1" --> |
75 | - <%= render_environment_features(:logged_in) if logged_in? %> | |
78 | + <%= render_environment_features(:logged_in).html_safe if logged_in? %> | |
76 | 79 | <div id="footer"> |
77 | 80 | <div id="theme-footer"> |
78 | 81 | <%= theme_footer %> |
... | ... | @@ -86,9 +89,9 @@ |
86 | 89 | <%= |
87 | 90 | str = (@plugins.dispatch(:body_ending).map do |content| |
88 | 91 | if content.respond_to?(:call) then |
89 | - instance_exec(&content) | |
92 | + instance_exec(&content).html_safe | |
90 | 93 | else |
91 | - content | |
94 | + content.html_safe | |
92 | 95 | end |
93 | 96 | end) |
94 | 97 | safe_join(str, "\n") | ... | ... |
app/views/layouts/slideshow.html.erb
... | ... | @@ -11,7 +11,7 @@ |
11 | 11 | %></title> |
12 | 12 | |
13 | 13 | <%= stylesheet_import "slideshow" %> |
14 | - <%= javascript_include_tag 'jquery-2.1.1.min', 'sliderjs', 'pikachoose' %> | |
14 | + <%= javascript_include_tag 'jquery-2.1.1.min', 'vendor/sliderjs', 'vendor/pikachoose' %> | |
15 | 15 | <script type="text/javascript"> |
16 | 16 | $(document).ready(function (){ |
17 | 17 | $("#slideshow").PikaChoose({ | ... | ... |
app/views/profile/_default_activity.html.erb
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | <%= link_to(profile_image(activity.user, :minor), activity.user.url) %> |
3 | 3 | </div> |
4 | 4 | <div class='profile-activity-description'> |
5 | - <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p> | |
5 | + <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe(activity).html_safe %></p> | |
6 | 6 | <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p> |
7 | 7 | <div class='profile-wall-actions'> |
8 | 8 | <%= link_to s_('profile|Comment'), '#', { :class => 'focus-on-comment'} %> | ... | ... |
app/views/profile/_favorite_enterprise.html.erb
... | ... | @@ -3,7 +3,7 @@ |
3 | 3 | </div> |
4 | 4 | <div class='profile-activity-description'> |
5 | 5 | <p class='profile-activity-text'> |
6 | - <%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe activity %> | |
6 | + <%= link_to activity.user.short_name(nil), activity.user.url %> <%= describe(activity).html_safe %> | |
7 | 7 | </p> |
8 | 8 | <p class='profile-activity-time'><%= time_ago_in_words activity.created_at %></p> |
9 | 9 | ... | ... |
app/views/profile/_leave_scrap.html.erb
... | ... | @@ -2,7 +2,7 @@ |
2 | 2 | <%= link_to(profile_image(activity.user, :minor), activity.user.url) %> |
3 | 3 | </div> |
4 | 4 | <div class='profile-activity-description'> |
5 | - <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe activity %></p> | |
5 | + <p class='profile-activity-text'><%= link_to activity.user.name, activity.user.url %> <%= describe(activity).html_safe %></p> | |
6 | 6 | <p class='profile-activity-time'><%= time_ago_in_words(activity.created_at) %></p> |
7 | 7 | <div class='profile-wall-actions'> |
8 | 8 | <%= link_to_function(_('Remove'), 'remove_item_wall(this, \'%s\', \'%s\', \'%s\'); return false ;' % [".profile-activity-item", url_for(:profile => params[:profile], :action => :remove_activity, :activity_id => activity.id, :view => params[:view]), _('Are you sure you want to remove this activity and all its replies?')]) if logged_in? && current_person == @profile %> | ... | ... |
app/views/profile/_profile_activities_list.html.erb
... | ... | @@ -12,6 +12,6 @@ |
12 | 12 | |
13 | 13 | <% if activities.current_page < activities.total_pages %> |
14 | 14 | <div id='profile_activities_page_<%= activities.current_page %>'> |
15 | - <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_activities', :page => (activities.current_page + 1)}, :update => "profile_activities_page_#{activities.current_page}" %> | |
15 | + <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_activities', :page => (activities.current_page + 1), :offsets => @offsets, :kind => 'wall'}, :update => "profile_activities_page_#{activities.current_page}" %> | |
16 | 16 | </div> |
17 | 17 | <% end %> | ... | ... |
app/views/profile/_profile_network.html.erb
1 | 1 | <h3><%= _("%s's network activity") % @profile.name %></h3> |
2 | 2 | <ul id='network-activities' class='profile-activities'> |
3 | - <%= render :partial => 'profile_network_activities', :locals => {:network_activities => @network_activities} %> | |
3 | + <%= render :partial => 'profile_network_activities', :locals => {:activities => @network_activities} %> | |
4 | 4 | </ul> | ... | ... |
app/views/profile/_profile_network_activities.html.erb
1 | -<% network_activities.each do |activity| %> | |
1 | +<% activities.each do |activity| %> | |
2 | 2 | <%= render :partial => 'profile_activity', :locals => { :activity => activity, :tab_action => 'network' } if activity.visible? %> |
3 | 3 | <% end %> |
4 | -<% if network_activities.current_page < network_activities.total_pages %> | |
5 | - <div id='profile_network_activities_page_<%= network_activities.current_page %>'> | |
6 | - <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_network_activities', :page => (network_activities.current_page + 1)}, :update => "profile_network_activities_page_#{network_activities.current_page}" %> | |
4 | +<% if activities.current_page < activities.total_pages %> | |
5 | + <div id='profile_network_activities_page_<%= activities.current_page %>'> | |
6 | + <%= button_to_remote :add, _('View more'), :url => {:action => 'view_more_activities', :page => (activities.current_page + 1), :offsets => @offsets, :kind => 'network'}, :update => "profile_network_activities_page_#{activities.current_page}" %> | |
7 | 7 | </div> |
8 | 8 | <% end %> | ... | ... |
app/views/profile/_profile_wall.html.erb
1 | 1 | <h3><%= _("%s's wall") % @profile.name %></h3> |
2 | 2 | <div id='leave_scrap'> |
3 | 3 | <%= flash[:error] %> |
4 | - <%= form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "jQuery('#leave_scrap_content').val('')", :complete => "jQuery('#leave_scrap_form').removeClass('loading').find('*').attr('disabled', false)", :loading => "jQuery('#leave_scrap_form').addClass('loading').find('*').attr('disabled', true)", :html => {:id => 'leave_scrap_form' } do %> | |
5 | - <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :cols => 50, :rows => 2, :class => 'autogrow' %> | |
4 | + <%= form_remote_tag :url => {:controller => 'profile', :action => 'leave_scrap', :tab_action => 'wall' }, :update => 'profile_activities', :success => "jQuery('#leave_scrap_content').val(''); jQuery('#filter-followed').tokenInput('clear')", :complete => "jQuery('#leave_scrap_form').removeClass('loading').find('*').attr('disabled', false)", :loading => "jQuery('#leave_scrap_form').addClass('loading').find('*').attr('disabled', true)", :html => {:id => 'leave_scrap_form' } do %> | |
5 | + <%= limited_text_area :scrap, :content, 420, 'leave_scrap_content', :rows => 2, :class => 'autogrow' %> | |
6 | + <% if profile == user %> | |
7 | + <%= token_input_field_tag(:filter_followed, 'filter-followed', {:action => 'search_followed'}, {:theme => 'facebook', :placeholder => _('Filter followed, friends or group of friends to send them a private scrap...')}) %> | |
8 | + <% end %> | |
6 | 9 | <%= submit_button :new, _('Share') %> |
7 | 10 | <% end %> |
8 | 11 | </div> | ... | ... |
app/views/profile/send_mail.html.erb
... | ... | @@ -22,8 +22,7 @@ |
22 | 22 | |
23 | 23 | <%= labelled_form_field(_('Subject:'), f.text_field(:subject)) %> |
24 | 24 | |
25 | - <%= render :file => 'shared/tiny_mce' %> | |
26 | - <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'mceEditor')) %> | |
25 | + <%= labelled_form_field(_('Body:'), f.text_area(:body, :class => 'body ' + current_editor)) %> | |
27 | 26 | |
28 | 27 | <%= submit_button(:send, _('Send')) %> |
29 | 28 | <%= button :cancel, _('Cancel e-mail'), :back %> | ... | ... |
app/views/profile_editor/_pending_tasks.html.erb
... | ... | @@ -2,9 +2,9 @@ |
2 | 2 | |
3 | 3 | <% unless @pending_tasks.empty? %> |
4 | 4 | <div class='pending-tasks'> |
5 | - <h2><%= _('You have pending requests') %></h2> | |
5 | + <h2><%= _('You have %s pending requests' % @pending_tasks.count) %></h2> | |
6 | 6 | <ul> |
7 | - <%= safe_join(@pending_tasks.map {|task| content_tag('li', task_information(task).html_safe)}) %> | |
7 | + <%= safe_join(@pending_tasks.limit(5).map {|task| content_tag('li', task_information(task, params).html_safe)}) %> | |
8 | 8 | </ul> |
9 | 9 | <%= button(:todo, _('Process requests'), :controller => 'tasks', :action => 'index') %> |
10 | 10 | </div> | ... | ... |
app/views/profile_editor/_person.html.erb
... | ... | @@ -16,6 +16,8 @@ |
16 | 16 | </div> |
17 | 17 | </div> |
18 | 18 | |
19 | + <%= select_editor(_('Editor'), 'profile_data', 'editor', {}) %> | |
20 | + | |
19 | 21 | <%= safe_join(@plugins.dispatch(:profile_info_extra_contents).collect { |content| instance_exec(&content) }, "") %> |
20 | 22 | |
21 | 23 | <div class="formfieldline"> | ... | ... |
app/views/profile_editor/header_footer.html.erb
1 | -<%= render :file => 'shared/tiny_mce' %> | |
2 | - | |
3 | 1 | <h1><%= _('Editing header and footer') %></h1> |
4 | 2 | |
5 | 3 | <%= form_tag do %> |
... | ... | @@ -21,9 +19,9 @@ |
21 | 19 | </div> |
22 | 20 | <% end %> |
23 | 21 | <h2><%= _('Content for header ') %></h2> |
24 | - <%= text_area_tag(:custom_header, @header, :style => 'width: 100%; height: 150px;', :class => 'mceEditor') %> | |
22 | + <%= text_area_tag(:custom_header, @header, :style => 'width: 100%; height: 150px;', :class => current_editor) %> | |
25 | 23 | <h2><%= _('Content for footer') %></h2> |
26 | - <%= text_area_tag(:custom_footer, @footer, :style => 'width: 100%; height: 150px;', :class => 'mceEditor') %> | |
24 | + <%= text_area_tag(:custom_footer, @footer, :style => 'width: 100%; height: 150px;', :class => current_editor) %> | |
27 | 25 | <%= button_bar do %> |
28 | 26 | <%= submit_button(:save, _('Save')) %> |
29 | 27 | <%= button(:cancel, _('Cancel'), :action => 'index') %> | ... | ... |
app/views/profile_editor/welcome_page.html.erb
... | ... | @@ -8,7 +8,7 @@ |
8 | 8 | <%= _('Your welcome page will only be displayed if this options is selected.') %> |
9 | 9 | </div> |
10 | 10 | |
11 | - <%= f.text_area(:body, :cols => 40, :style => 'width: 100%', :class => 'mceEditor') %> | |
11 | + <%= f.text_area(:body, :cols => 40, :style => 'width: 100%', :class => current_editor) %> | |
12 | 12 | <div class='explanation'> |
13 | 13 | <%= _('This page will be displayed to the user after his signup with this template.') %> |
14 | 14 | </div> |
... | ... | @@ -17,5 +17,3 @@ |
17 | 17 | <%= submit_button('save', _('Save'), :cancel => @back_to) %> |
18 | 18 | <% end %> |
19 | 19 | <% end %> |
20 | - | |
21 | -<%= render :file => 'shared/tiny_mce' %> | ... | ... |
app/views/shared/_lead_and_body.html.erb
app/views/shared/_profile_connections.html.erb
... | ... | @@ -4,7 +4,7 @@ |
4 | 4 | <ul class="profile-list"> |
5 | 5 | <% profiles.each do |profile| %> |
6 | 6 | <li> |
7 | - <%= link_to_profile profile_image(profile) + '<br/>' + profile.short_name, | |
7 | + <%= link_to_profile profile_image(profile) + '<br/>'.html_safe + profile.short_name, | |
8 | 8 | profile.identifier, :class => 'profile-link' %> |
9 | 9 | </li> |
10 | 10 | <% end %> | ... | ... |
app/views/shared/logged_in/xmpp_chat.html.erb
1 | - <%= javascript_include_tag 'strophejs-1.1.3/strophe.min', 'jquery.emoticon', 'designs/icons/pidgin/emoticons.js', 'ba-linkify', 'jquery.ba-hashchange', 'jquery.sound', 'chat', 'vendor/perfect-scrollbar.min.js', 'vendor/perfect-scrollbar.with-mousewheel.min.js', 'jquery.timeago.js' %> | |
1 | + <%= javascript_include_tag 'vendor/strophejs-1.1.3/strophe.min', 'vendor/jquery.emoticon', 'designs/icons/pidgin/emoticons.js', 'vendor/ba-linkify', 'vendor/jquery.ba-hashchange', 'vendor/jquery.sound', 'chat', 'vendor/perfect-scrollbar.min.js', 'vendor/perfect-scrollbar.with-mousewheel.min.js', 'vendor/jquery.timeago.js' %> | |
2 | 2 | <%= stylesheet_link_tag 'vendor/perfect-scrollbar.min.css' %> |
3 | 3 | |
4 | 4 | <% extend ChatHelper %> | ... | ... |
app/views/shared/not_found.html.erb
1 | 1 | <div id='not-found'> |
2 | - <h1><%= _('There is no such page: %s') % (content_tag('tt', @path)) %></h1> | |
2 | + <h1><%= _('There is no such page: %s').html_safe % (content_tag('tt', @path)) %></h1> | |
3 | 3 | <p> |
4 | 4 | <%= _('.You may have clicked an expired link or mistyped the address.') %> |
5 | 5 | <%= _('.This page does not exist. Would you like to: Create a new content or locate existing content.') %> | ... | ... |
app/views/shared/tiny_mce.html.erb
... | ... | @@ -47,7 +47,9 @@ function tinymce_macros_setup(editor) { |
47 | 47 | tinymce.PluginManager.add('macrosPlugin', tinymce.plugins.MacrosPlugin); |
48 | 48 | |
49 | 49 | jQuery(document).ready(function () { |
50 | - <%= tinymce_init_js :mode => mode %> | |
50 | + <%= tinymce_init_js %> | |
51 | + <%= tinymce_init_js :mode => 'simple' %> | |
52 | + <%= tinymce_init_js :mode => 'restricted' %> | |
51 | 53 | }); |
52 | 54 | </script> |
53 | 55 | ... | ... |