Compare View
Commits (128)
-
should task endpoints be accessed only by logged users See merge request !980
-
Signed-off-by: Alessandro Caetano <alessandro.caetanob@gmail.com> Signed-off-by: Artur Bersan de Faria <arturbersan@gmail.com> Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> Signed-off-by: Matheus Miranda <matheusmirandalacerda@gmail.com> Signed-off-by: Sabryna Sousa <sabryna.sousa1323@gmail.com> Signed-off-by: Victor Matias Navarro <victor.matias.navarro@gmail.com> Signed-off-by: Vitor Barbosa <vitormga15@gmail.com>
-
Concern needs to be included before first use of setting items
-
Lists and edits followers and circles in control panel of profile that is being viewed instead of logged in person. Also unfollow person in control panel based on current viewed profile instead of current logged in user. This is necessary because sometimes an environment admin is editing someone else's profile and those actions should be performed on that profile instead of admin's profile.
-
Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com>
-
Profile followers feature Signed-off-by: Alessandro Caetano <alessandro.caetanob@gmail.com> Signed-off-by: Artur Bersan de Faria <arturbersan@gmail.com> Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> Signed-off-by: Matheus Miranda <matheusmirandalacerda@gmail.com> Signed-off-by: Sabryna Sousa <sabryna.sousa1323@gmail.com> Signed-off-by: Victor Matias Navarro <victor.matias.navarro@gmail.com> Signed-off-by: Vitor Barbosa <vitormga15@gmail.com> See merge request !976
-
We now remove profile_follewers if its circle is deleted
-
comment_paragraph: change filename of exported comments See merge request !966
-
Signed-off-by: Paulo Tada <paulohtfs@gmail.com> Signed-off-by: Tallys Martins <tallysmartins@gmail.com>
-
Adds public fields to Profile API Signed-off-by: Paulo Tada <paulohtfs@gmail.com> Signed-off-by: Tallys Martins <tallysmartins@gmail.com> See merge request !981
-
- Environments and profiles now return the layout template used. Signed-off-by: Tallys Martins <tallysmartins@gmail.com>
-
Display layout_template on api - Environments and profiles now return the layout template used. @marcosronaldo can you take a look at this? We'll use it on angular theme. See merge request !968
-
Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com>
-
Organization_ratings: Show rejected message to admins Show rejected message to admins on organization_ratings plugin. Only environment admins can see the rejected message. Signed-off-by: Gabriel Silva <gabriel93.silva@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> See merge request !969
-
… recent activities of the profile who owns it
-
Recent activities Adding a plugin "recent_activities" which adds a block that list the recent activities of the profile who owns it: ![76](/uploads/000199ff2aaf4dd40f8f905ce11d884d/76.png) See merge request !972
-
The profile activities returns action trackers and scraps, but the scraps should not be displayed on recent activities block. Only the action tracker records Related to merge request !972
-
spaminator: update mailer to rails4 new scheme See merge request !971
-
api: add and remove members from profile See merge request !977
-
API - Environment entity new fields Added the fields `:signup_intro`, `:terms_of_use` and `:top_url` (exposed using `:host` alias) to `Environment` entity: See merge request !982
-
Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> Signed-off-by: Victor Navarro <victor.matias.navarro@gmail.com> Signed-off-by: Vitor Barbosa <vitornga15@gmail.com>
-
Add endpoint to close task with status Signed-off-by: Victor Navarro <victor.matias.navarro@gmail.com> Signed-off-by: Vitor Barbosa <vitornga15@gmail.com> See merge request !939
-
api: list all pending tasks for the current person See merge request !979
-
api: return organization roles See merge request !983
-
api: accept parameters to update a task when accept/reject See merge request !984
-
Create elasticsearch structure Index models for elasticsearch Adding category search filter Make query generic Add README.md for elasticsearch plugin Start tests with rspec for elasticsearch Applyng filtering by type on articles Adding visible filter Signed-off-by: Lucas Moura <lucas.moura128@gmail.com> Signed-off-by: Luciano Prestes Cavalcanti <lucianopcbr@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com> Signed-off-by: Daniel Henrique <danielhmarinho@gmail.com>
-
Rakefile to download and install elasticsearch Adding rubygems.org as source for Gemfile Removing trailing whitespace Updating install instructions Elasticsearch depends on openjdk-7-jdk
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
redirect index -> search action removing models extensions that are removed from core renaming elasticsearch helper to a better name (now, working as well) model extensions working with the new helper name check :weight exists refactoring models extensions
-
Adding community.rb and fixing searchable_fields Adding regex filter Add person & gallery to allow search on those models Show all results when query is empty Signed-off-by: Daniel Henrique <danielhmarinho@gmail.com> Signed-off-by: David Carlos <ddavidcarlos1392@gmail.com>
-
Signed-off-by: Daniel Henrique <danielhmarinho@gmail.com> Signed-off-by: David Carlos <ddavidcarlos1392@gmail.com>
-
* Person * Community * TextArticle * Event * UploadedFile
-
Create initial style of elasticsearch, and refectored html Changes style of elasticsearch plugin, add variable to store search types. Adds style for communities partial. Adds person partial style Adding event to models and adding styles Refactored search controller and view - Changed search-form to use get instead of post - Uses search method directly in models - Refactored process results - Adding pagination Removed hardcode name from community view Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Arthur Jahn <stutrzbecher@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Arthur Jahn <stutrzbecher@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Arthur Jahn <stutrzbecher@gmail.com> Signed-off-by: DylanGuedes <djmgguedes@gmail.com>
-
Signed-off-by: Dylan Guedes <djmgguedes@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Dylan Guedes <djmgguedes@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Adding tests to elasticsearch controller Adding ElasticsearchTestHelper Fixed model tests Adding tests and refactored control_fields indexed Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Fixes minor bugs in style, adds link-to to search results, and translations
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Adding Elasticsearch_helper Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Adding views to uploaded_files and text_articles Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Sort documents by name Adds lexical sort for searchs without expression Sort by name.raw instead of name Indexes models by raw nested in name, remove suggests Fixes tests and alphabetical ordering Adds created at as a type of sort Fixing search using sort by Fixed Sort by to receive filter param Fixed noosfero to be support noosfero links Fixed text_articles and upload_files extensions Fixed api tests Refactored elasticsearch_plugin and elasticsearch_api Fixed to use partial query Fixed sort and query_string Signed-off-by: Arthur Jahn <stutrzbecher@gmail.com> Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur Sousa <macartur.sc@gmail.com> Signed-off-by: David Carlos <ddavidcarlos1392@gmail.com>
-
related to #362 - fixes for search view makes css rules more specific Signed-off-by: Arthur Jahn <stutrzbecher@gmail.com> Signed-off-by: Daniel Henrique <danielhmarinho@gmail.com>
-
* Filter by environment * Filter by visible community Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Adding nested query: * NestedEnvironment * NestedProfile Adding bool query: * should * must * must_not Moved elasticsearch_indexed_model to helpers folder Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
* Adding more_popular and more_active to Community and Person * Fixed Api to support dynamic filter Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
* Changed name from helpers to display sort_types * Adding dynamic sort to text_article * indexed category_ids to be used after Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com> Signed-off-by: Arthur Jahn <stutrzbecher@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur de Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur de Sousa <macartur.sc@gmail.com> Signed-off-by: DylanGuedes <djmgguedes@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur de Sousa <macartur.sc@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur de Sousa <macartur.sc@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur de Sousa <macartur.sc@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com>
-
Signed-off-by: DylanGuedes <djmgguedes@gmail.com> Signed-off-by: Macartur de Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
-
Signed-off-by: Macartur Sousa <macartur.sc@gmail.com>
Showing
341 changed files
Show diff stats
Too many changes.
To preserve performance only 100 of 341 files displayed.
app/api/app.rb
@@ -54,6 +54,7 @@ module Api | @@ -54,6 +54,7 @@ module Api | ||
54 | mount V1::Blocks | 54 | mount V1::Blocks |
55 | mount V1::Profiles | 55 | mount V1::Profiles |
56 | mount V1::Activities | 56 | mount V1::Activities |
57 | + mount V1::Roles | ||
57 | 58 | ||
58 | # hook point which allow plugins to add Grape::API extensions to Api::App | 59 | # hook point which allow plugins to add Grape::API extensions to Api::App |
59 | #finds for plugins which has api mount points classes defined (the class should extends Grape::API) | 60 | #finds for plugins which has api mount points classes defined (the class should extends Grape::API) |
app/api/entities.rb
@@ -111,6 +111,10 @@ module Api | @@ -111,6 +111,10 @@ module Api | ||
111 | hash[value.custom_field.name]=value.value | 111 | hash[value.custom_field.name]=value.value |
112 | end | 112 | end |
113 | 113 | ||
114 | + profile.public_fields.each do |field| | ||
115 | + hash[field] = profile.send(field.to_sym) | ||
116 | + end | ||
117 | + | ||
114 | private_values = profile.custom_field_values - profile.public_values | 118 | private_values = profile.custom_field_values - profile.public_values |
115 | private_values.each do |value| | 119 | private_values.each do |value| |
116 | if Entities.can_display_profile_field?(profile,options) | 120 | if Entities.can_display_profile_field?(profile,options) |
@@ -124,6 +128,7 @@ module Api | @@ -124,6 +128,7 @@ module Api | ||
124 | expose :type | 128 | expose :type |
125 | expose :custom_header | 129 | expose :custom_header |
126 | expose :custom_footer | 130 | expose :custom_footer |
131 | + expose :layout_template | ||
127 | expose :permissions do |profile, options| | 132 | expose :permissions do |profile, options| |
128 | Entities.permissions_for_entity(profile, options[:current_person], | 133 | Entities.permissions_for_entity(profile, options[:current_person], |
129 | :allow_post_content?, :allow_edit?, :allow_destroy?) | 134 | :allow_post_content?, :allow_edit?, :allow_destroy?) |
@@ -258,12 +263,28 @@ module Api | @@ -258,12 +263,28 @@ module Api | ||
258 | root 'tasks', 'task' | 263 | root 'tasks', 'task' |
259 | expose :id | 264 | expose :id |
260 | expose :type | 265 | expose :type |
266 | + expose :requestor, using: Profile | ||
267 | + expose :status | ||
268 | + expose :created_at | ||
269 | + expose :data | ||
270 | + expose :accept_details | ||
271 | + expose :reject_details | ||
272 | + expose :accept_disabled?, as: :accept_disabled | ||
273 | + expose :reject_disabled?, as: :reject_disabled | ||
274 | + expose :target do |task, options| | ||
275 | + type_map = {Profile => ::Profile, Environment => ::Environment}.find {|h| task.target.kind_of?(h.last)} | ||
276 | + type_map.first.represent(task.target) unless type_map.nil? | ||
277 | + end | ||
261 | end | 278 | end |
262 | 279 | ||
263 | class Environment < Entity | 280 | class Environment < Entity |
264 | expose :name | 281 | expose :name |
265 | expose :id | 282 | expose :id |
266 | expose :description | 283 | expose :description |
284 | + expose :layout_template | ||
285 | + expose :signup_intro | ||
286 | + expose :terms_of_use | ||
287 | + expose :top_url, as: :host | ||
267 | expose :settings, if: lambda { |instance, options| options[:is_admin] } | 288 | expose :settings, if: lambda { |instance, options| options[:is_admin] } |
268 | end | 289 | end |
269 | 290 | ||
@@ -281,5 +302,12 @@ module Api | @@ -281,5 +302,12 @@ module Api | ||
281 | type_map.first.represent(activity.target) unless type_map.nil? | 302 | type_map.first.represent(activity.target) unless type_map.nil? |
282 | end | 303 | end |
283 | end | 304 | end |
305 | + | ||
306 | + class Role < Entity | ||
307 | + root 'roles', 'role' | ||
308 | + expose :id | ||
309 | + expose :name | ||
310 | + expose :key | ||
311 | + end | ||
284 | end | 312 | end |
285 | end | 313 | end |
app/api/helpers.rb
@@ -4,7 +4,7 @@ require 'tempfile' | @@ -4,7 +4,7 @@ require 'tempfile' | ||
4 | module Api | 4 | module Api |
5 | module Helpers | 5 | module Helpers |
6 | PRIVATE_TOKEN_PARAM = :private_token | 6 | PRIVATE_TOKEN_PARAM = :private_token |
7 | - DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived] | 7 | + ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived, :status] |
8 | 8 | ||
9 | include SanitizeParams | 9 | include SanitizeParams |
10 | include Noosfero::Plugin::HotSpot | 10 | include Noosfero::Plugin::HotSpot |
@@ -124,8 +124,8 @@ module Api | @@ -124,8 +124,8 @@ module Api | ||
124 | present_partial article, with: Entities::Article, params: params, current_person: current_person | 124 | present_partial article, with: Entities::Article, params: params, current_person: current_person |
125 | end | 125 | end |
126 | 126 | ||
127 | - def present_articles_for_asset(asset, method = 'articles') | ||
128 | - articles = find_articles(asset, method) | 127 | + def present_articles_for_asset(asset, method_or_relation = 'articles') |
128 | + articles = find_articles(asset, method_or_relation) | ||
129 | present_articles(articles) | 129 | present_articles(articles) |
130 | end | 130 | end |
131 | 131 | ||
@@ -133,8 +133,8 @@ module Api | @@ -133,8 +133,8 @@ module Api | ||
133 | present_partial paginate(articles), :with => Entities::Article, :params => params, current_person: current_person | 133 | present_partial paginate(articles), :with => Entities::Article, :params => params, current_person: current_person |
134 | end | 134 | end |
135 | 135 | ||
136 | - def find_articles(asset, method = 'articles') | ||
137 | - articles = select_filtered_collection_of(asset, method, params) | 136 | + def find_articles(asset, method_or_relation = 'articles') |
137 | + articles = select_filtered_collection_of(asset, method_or_relation, params) | ||
138 | if current_person.present? | 138 | if current_person.present? |
139 | articles = articles.display_filter(current_person, nil) | 139 | articles = articles.display_filter(current_person, nil) |
140 | else | 140 | else |
@@ -143,14 +143,17 @@ module Api | @@ -143,14 +143,17 @@ module Api | ||
143 | articles | 143 | articles |
144 | end | 144 | end |
145 | 145 | ||
146 | - def find_task(asset, id) | ||
147 | - task = asset.tasks.find(id) | 146 | + def find_task(asset, method_or_relation, id) |
147 | + task = is_a_relation?(method_or_relation) ? method_or_relation : asset.send(method_or_relation) | ||
148 | + task = task.find_by_id(id) | ||
149 | + not_found! if task.blank? | ||
148 | current_person.has_permission?(task.permission, asset) ? task : forbidden! | 150 | current_person.has_permission?(task.permission, asset) ? task : forbidden! |
149 | end | 151 | end |
150 | 152 | ||
151 | def post_task(asset, params) | 153 | def post_task(asset, params) |
152 | klass_type= params[:content_type].nil? ? 'Task' : params[:content_type] | 154 | klass_type= params[:content_type].nil? ? 'Task' : params[:content_type] |
153 | return forbidden! unless klass_type.constantize <= Task | 155 | return forbidden! unless klass_type.constantize <= Task |
156 | + return forbidden! if !current_person.has_permission?(:perform_task, asset) | ||
154 | 157 | ||
155 | task = klass_type.constantize.new(params[:task]) | 158 | task = klass_type.constantize.new(params[:task]) |
156 | task.requestor_id = current_person.id | 159 | task.requestor_id = current_person.id |
@@ -163,15 +166,24 @@ module Api | @@ -163,15 +166,24 @@ module Api | ||
163 | present_partial task, :with => Entities::Task | 166 | present_partial task, :with => Entities::Task |
164 | end | 167 | end |
165 | 168 | ||
166 | - def present_task(asset) | ||
167 | - task = find_task(asset, params[:id]) | 169 | + def find_tasks(asset, method_or_relation = 'tasks') |
170 | + return forbidden! if !current_person.has_permission?(:perform_task, asset) | ||
171 | + tasks = select_filtered_collection_of(asset, method_or_relation, params) | ||
172 | + tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)} | ||
173 | + tasks | ||
174 | + end | ||
175 | + | ||
176 | + def present_task(asset, method_or_relation = 'tasks') | ||
177 | + task = find_task(asset, method_or_relation, params[:id]) | ||
168 | present_partial task, :with => Entities::Task | 178 | present_partial task, :with => Entities::Task |
169 | end | 179 | end |
170 | 180 | ||
171 | - def present_tasks(asset) | ||
172 | - tasks = select_filtered_collection_of(asset, 'tasks', params) | ||
173 | - tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)} | ||
174 | - return forbidden! if tasks.empty? && !current_person.has_permission?(:perform_task, asset) | 181 | + def present_tasks_for_asset(asset, method_or_relation = 'tasks') |
182 | + tasks = find_tasks(asset, method_or_relation) | ||
183 | + present_tasks(tasks) | ||
184 | + end | ||
185 | + | ||
186 | + def present_tasks(tasks) | ||
175 | present_partial tasks, :with => Entities::Task | 187 | present_partial tasks, :with => Entities::Task |
176 | end | 188 | end |
177 | 189 | ||
@@ -180,7 +192,6 @@ module Api | @@ -180,7 +192,6 @@ module Api | ||
180 | conditions = {} | 192 | conditions = {} |
181 | from_date = DateTime.parse(parsed_params.delete(:from)) if parsed_params[:from] | 193 | from_date = DateTime.parse(parsed_params.delete(:from)) if parsed_params[:from] |
182 | until_date = DateTime.parse(parsed_params.delete(:until)) if parsed_params[:until] | 194 | until_date = DateTime.parse(parsed_params.delete(:until)) if parsed_params[:until] |
183 | - | ||
184 | conditions[:type] = parse_content_type(parsed_params.delete(:content_type)) unless parsed_params[:content_type].nil? | 195 | conditions[:type] = parse_content_type(parsed_params.delete(:content_type)) unless parsed_params[:content_type].nil? |
185 | 196 | ||
186 | conditions[:created_at] = period(from_date, until_date) if from_date || until_date | 197 | conditions[:created_at] = period(from_date, until_date) if from_date || until_date |
@@ -190,7 +201,7 @@ module Api | @@ -190,7 +201,7 @@ module Api | ||
190 | end | 201 | end |
191 | 202 | ||
192 | # changing make_order_with_parameters to avoid sql injection | 203 | # changing make_order_with_parameters to avoid sql injection |
193 | - def make_order_with_parameters(object, method, params) | 204 | + def make_order_with_parameters(object, method_or_relation, params) |
194 | order = "created_at DESC" | 205 | order = "created_at DESC" |
195 | unless params[:order].blank? | 206 | unless params[:order].blank? |
196 | if params[:order].include? '\'' or params[:order].include? '"' | 207 | if params[:order].include? '\'' or params[:order].include? '"' |
@@ -199,9 +210,9 @@ module Api | @@ -199,9 +210,9 @@ module Api | ||
199 | order = 'RANDOM()' | 210 | order = 'RANDOM()' |
200 | else | 211 | else |
201 | field_name, direction = params[:order].split(' ') | 212 | field_name, direction = params[:order].split(' ') |
202 | - assoc = object.class.reflect_on_association(method.to_sym) | ||
203 | - if !field_name.blank? and assoc | ||
204 | - if assoc.klass.attribute_names.include? field_name | 213 | + assoc_class = extract_associated_classname(method_or_relation) |
214 | + if !field_name.blank? and assoc_class | ||
215 | + if assoc_class.attribute_names.include? field_name | ||
205 | if direction.present? and ['ASC','DESC'].include? direction.upcase | 216 | if direction.present? and ['ASC','DESC'].include? direction.upcase |
206 | order = "#{field_name} #{direction.upcase}" | 217 | order = "#{field_name} #{direction.upcase}" |
207 | end | 218 | end |
@@ -212,12 +223,14 @@ module Api | @@ -212,12 +223,14 @@ module Api | ||
212 | return order | 223 | return order |
213 | end | 224 | end |
214 | 225 | ||
215 | - def make_timestamp_with_parameters_and_method(params, method) | 226 | + def make_timestamp_with_parameters_and_method(params, method_or_relation) |
216 | timestamp = nil | 227 | timestamp = nil |
217 | if params[:timestamp] | 228 | if params[:timestamp] |
218 | datetime = DateTime.parse(params[:timestamp]) | 229 | datetime = DateTime.parse(params[:timestamp]) |
219 | - table_name = method.to_s.singularize.camelize.constantize.table_name | ||
220 | - timestamp = "#{table_name}.updated_at >= '#{datetime}'" | 230 | + table_name = extract_associated_tablename(method_or_relation) |
231 | + assoc_class = extract_associated_classname(method_or_relation) | ||
232 | + date_atrr = assoc_class.attribute_names.include?('updated_at') ? 'updated_at' : 'created_at' | ||
233 | + timestamp = "#{table_name}.#{date_atrr} >= '#{datetime}'" | ||
221 | end | 234 | end |
222 | 235 | ||
223 | timestamp | 236 | timestamp |
@@ -242,12 +255,12 @@ module Api | @@ -242,12 +255,12 @@ module Api | ||
242 | end | 255 | end |
243 | end | 256 | end |
244 | 257 | ||
245 | - def select_filtered_collection_of(object, method, params) | 258 | + def select_filtered_collection_of(object, method_or_relation, params) |
246 | conditions = make_conditions_with_parameter(params) | 259 | conditions = make_conditions_with_parameter(params) |
247 | - order = make_order_with_parameters(object,method,params) | ||
248 | - timestamp = make_timestamp_with_parameters_and_method(params, method) | 260 | + order = make_order_with_parameters(object,method_or_relation,params) |
261 | + timestamp = make_timestamp_with_parameters_and_method(params, method_or_relation) | ||
249 | 262 | ||
250 | - objects = object.send(method) | 263 | + objects = is_a_relation?(method_or_relation) ? method_or_relation : object.send(method_or_relation) |
251 | objects = by_reference(objects, params) | 264 | objects = by_reference(objects, params) |
252 | objects = by_categories(objects, params) | 265 | objects = by_categories(objects, params) |
253 | 266 | ||
@@ -302,12 +315,12 @@ module Api | @@ -302,12 +315,12 @@ module Api | ||
302 | end | 315 | end |
303 | 316 | ||
304 | def cant_be_saved_request!(attribute) | 317 | def cant_be_saved_request!(attribute) |
305 | - message = _("(Invalid request) %s can't be saved") % attribute | 318 | + message = _("(Invalid request) %s can't be saved").html_safe % attribute |
306 | render_api_error!(message, 400) | 319 | render_api_error!(message, 400) |
307 | end | 320 | end |
308 | 321 | ||
309 | def bad_request!(attribute) | 322 | def bad_request!(attribute) |
310 | - message = _("(Invalid request) %s not given") % attribute | 323 | + message = _("(Invalid request) %s not given").html_safe % attribute |
311 | render_api_error!(message, 400) | 324 | render_api_error!(message, 400) |
312 | end | 325 | end |
313 | 326 | ||
@@ -393,10 +406,27 @@ module Api | @@ -393,10 +406,27 @@ module Api | ||
393 | end | 406 | end |
394 | private | 407 | private |
395 | 408 | ||
409 | + def extract_associated_tablename(method_or_relation) | ||
410 | + extract_associated_classname(method_or_relation).table_name | ||
411 | + end | ||
412 | + | ||
413 | + def extract_associated_classname(method_or_relation) | ||
414 | + if is_a_relation?(method_or_relation) | ||
415 | + method_or_relation.blank? ? '' : method_or_relation.first.class | ||
416 | + else | ||
417 | + method_or_relation.to_s.singularize.camelize.constantize | ||
418 | + end | ||
419 | + end | ||
420 | + | ||
421 | + def is_a_relation?(method_or_relation) | ||
422 | + method_or_relation.kind_of?(ActiveRecord::Relation) | ||
423 | + end | ||
424 | + | ||
425 | + | ||
396 | def parser_params(params) | 426 | def parser_params(params) |
397 | parsed_params = {} | 427 | parsed_params = {} |
398 | params.map do |k,v| | 428 | params.map do |k,v| |
399 | - parsed_params[k.to_sym] = v if DEFAULT_ALLOWED_PARAMETERS.include?(k.to_sym) | 429 | + parsed_params[k.to_sym] = v if ALLOWED_PARAMETERS.include?(k.to_sym) |
400 | end | 430 | end |
401 | parsed_params | 431 | parsed_params |
402 | end | 432 | end |
app/api/v1/people.rb
@@ -119,6 +119,20 @@ module Api | @@ -119,6 +119,20 @@ module Api | ||
119 | members = select_filtered_collection_of(profile, 'members', params) | 119 | members = select_filtered_collection_of(profile, 'members', params) |
120 | present members, :with => Entities::Person, :current_person => current_person | 120 | present members, :with => Entities::Person, :current_person => current_person |
121 | end | 121 | end |
122 | + | ||
123 | + post do | ||
124 | + authenticate! | ||
125 | + profile = environment.profiles.find_by id: params[:profile_id] | ||
126 | + profile.add_member(current_person) rescue forbidden! | ||
127 | + {pending: !current_person.is_member_of?(profile)} | ||
128 | + end | ||
129 | + | ||
130 | + delete do | ||
131 | + authenticate! | ||
132 | + profile = environment.profiles.find_by id: params[:profile_id] | ||
133 | + profile.remove_member(current_person) | ||
134 | + present current_person, :with => Entities::Person, :current_person => current_person | ||
135 | + end | ||
122 | end | 136 | end |
123 | end | 137 | end |
124 | end | 138 | end |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Roles < Grape::API | ||
4 | + before { authenticate! } | ||
5 | + | ||
6 | + MAX_PER_PAGE = 50 | ||
7 | + | ||
8 | + resource :profiles do | ||
9 | + segment "/:profile_id" do | ||
10 | + resource :roles do | ||
11 | + | ||
12 | + paginate max_per_page: MAX_PER_PAGE | ||
13 | + get do | ||
14 | + profile = environment.profiles.find(params[:profile_id]) | ||
15 | + return forbidden! unless profile.kind_of?(Organization) | ||
16 | + roles = Profile::Roles.organization_roles(profile.environment.id, profile.id) | ||
17 | + present_partial paginate(roles), with: Entities::Role | ||
18 | + end | ||
19 | + | ||
20 | + end | ||
21 | + end | ||
22 | + end | ||
23 | + end | ||
24 | + end | ||
25 | +end |
app/api/v1/tasks.rb
1 | module Api | 1 | module Api |
2 | module V1 | 2 | module V1 |
3 | class Tasks < Grape::API | 3 | class Tasks < Grape::API |
4 | -# before { authenticate! } | 4 | + before { authenticate! } |
5 | 5 | ||
6 | -# ARTICLE_TYPES = Article.descendants.map{|a| a.to_s} | 6 | + MAX_PER_PAGE = 50 |
7 | 7 | ||
8 | resource :tasks do | 8 | resource :tasks do |
9 | 9 | ||
10 | - # Collect tasks | 10 | + paginate max_per_page: MAX_PER_PAGE |
11 | + # Collect all tasks that current person has permission | ||
11 | # | 12 | # |
12 | # Parameters: | 13 | # Parameters: |
13 | # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created | 14 | # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created |
@@ -17,15 +18,27 @@ module Api | @@ -17,15 +18,27 @@ module Api | ||
17 | # Example Request: | 18 | # Example Request: |
18 | # GET host/api/v1/tasks?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317 | 19 | # GET host/api/v1/tasks?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317 |
19 | get do | 20 | get do |
20 | - tasks = select_filtered_collection_of(environment, 'tasks', params) | ||
21 | - tasks = tasks.select {|t| current_person.has_permission?(t.permission, environment)} | ||
22 | - present_partial tasks, :with => Entities::Task | 21 | + tasks = Task.to(current_person) |
22 | + present_tasks_for_asset(current_person, tasks) | ||
23 | end | 23 | end |
24 | 24 | ||
25 | desc "Return the task id" | 25 | desc "Return the task id" |
26 | get ':id' do | 26 | get ':id' do |
27 | - task = find_task(environment, params[:id]) | ||
28 | - present_partial task, :with => Entities::Task | 27 | + present_task(current_person, Task.to(current_person)) |
28 | + end | ||
29 | + | ||
30 | + %w[finish cancel].each do |action| | ||
31 | + desc "#{action.capitalize} a task" | ||
32 | + put ":id/#{action}" do | ||
33 | + task = find_task(current_person, Task.to(current_person), params[:id]) | ||
34 | + begin | ||
35 | + task.update(params[:task]) | ||
36 | + task.send(action, current_person) if (task.status == Task::Status::ACTIVE) | ||
37 | + present_partial task, :with => Entities::Task | ||
38 | + rescue Exception => ex | ||
39 | + render_api_error!(ex.message, 500) | ||
40 | + end | ||
41 | + end | ||
29 | end | 42 | end |
30 | end | 43 | end |
31 | 44 | ||
@@ -36,7 +49,8 @@ module Api | @@ -36,7 +49,8 @@ module Api | ||
36 | resource :tasks do | 49 | resource :tasks do |
37 | get do | 50 | get do |
38 | profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | 51 | profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) |
39 | - present_tasks(profile) | 52 | + tasks = Task.to(profile) |
53 | + present_tasks_for_asset(profile, tasks) | ||
40 | end | 54 | end |
41 | 55 | ||
42 | get ':id' do | 56 | get ':id' do |
app/controllers/admin/categories_controller.rb
@@ -44,7 +44,7 @@ class CategoriesController < AdminController | @@ -44,7 +44,7 @@ class CategoriesController < AdminController | ||
44 | if request.post? | 44 | if request.post? |
45 | @category.update!(params[:category]) | 45 | @category.update!(params[:category]) |
46 | @saved = true | 46 | @saved = true |
47 | - session[:notice] = _("Category %s saved." % @category.name) | 47 | + session[:notice] = _("Category %s saved." % @category.name).html_safe |
48 | redirect_to :action => 'index' | 48 | redirect_to :action => 'index' |
49 | end | 49 | end |
50 | rescue Exception => e | 50 | rescue Exception => e |
app/controllers/application_controller.rb
@@ -14,6 +14,20 @@ class ApplicationController < ActionController::Base | @@ -14,6 +14,20 @@ class ApplicationController < ActionController::Base | ||
14 | before_filter :redirect_to_current_user | 14 | before_filter :redirect_to_current_user |
15 | 15 | ||
16 | before_filter :set_session_theme | 16 | before_filter :set_session_theme |
17 | + | ||
18 | + # FIXME: only include necessary methods | ||
19 | + include ApplicationHelper | ||
20 | + | ||
21 | + # concerns | ||
22 | + include PermissionCheck | ||
23 | + include CustomDesign | ||
24 | + include NeedsProfile | ||
25 | + | ||
26 | + # implementations | ||
27 | + include FindByContents | ||
28 | + include Noosfero::Plugin::HotSpot | ||
29 | + include SearchTermHelper | ||
30 | + | ||
17 | def set_session_theme | 31 | def set_session_theme |
18 | if params[:theme] | 32 | if params[:theme] |
19 | session[:theme] = environment.theme_ids.include?(params[:theme]) ? params[:theme] : nil | 33 | session[:theme] = environment.theme_ids.include?(params[:theme]) ? params[:theme] : nil |
@@ -48,7 +62,6 @@ class ApplicationController < ActionController::Base | @@ -48,7 +62,6 @@ class ApplicationController < ActionController::Base | ||
48 | end | 62 | end |
49 | end | 63 | end |
50 | 64 | ||
51 | - include ApplicationHelper | ||
52 | layout :get_layout | 65 | layout :get_layout |
53 | def get_layout | 66 | def get_layout |
54 | return false if request.format == :js or request.xhr? | 67 | return false if request.format == :js or request.xhr? |
@@ -74,9 +87,6 @@ class ApplicationController < ActionController::Base | @@ -74,9 +87,6 @@ class ApplicationController < ActionController::Base | ||
74 | helper :document | 87 | helper :document |
75 | helper :language | 88 | helper :language |
76 | 89 | ||
77 | - include DesignHelper | ||
78 | - include PermissionCheck | ||
79 | - | ||
80 | before_filter :set_locale | 90 | before_filter :set_locale |
81 | def set_locale | 91 | def set_locale |
82 | FastGettext.available_locales = environment.available_locales | 92 | FastGettext.available_locales = environment.available_locales |
@@ -89,8 +99,6 @@ class ApplicationController < ActionController::Base | @@ -89,8 +99,6 @@ class ApplicationController < ActionController::Base | ||
89 | end | 99 | end |
90 | end | 100 | end |
91 | 101 | ||
92 | - include NeedsProfile | ||
93 | - | ||
94 | attr_reader :environment | 102 | attr_reader :environment |
95 | 103 | ||
96 | # declares that the given <tt>actions</tt> cannot be accessed by other HTTP | 104 | # declares that the given <tt>actions</tt> cannot be accessed by other HTTP |
@@ -107,6 +115,10 @@ class ApplicationController < ActionController::Base | @@ -107,6 +115,10 @@ class ApplicationController < ActionController::Base | ||
107 | 115 | ||
108 | protected | 116 | protected |
109 | 117 | ||
118 | + def accept_only_post | ||
119 | + return render_not_found if !request.post? | ||
120 | + end | ||
121 | + | ||
110 | def verified_request? | 122 | def verified_request? |
111 | super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] | 123 | super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] |
112 | end | 124 | end |
@@ -151,8 +163,6 @@ class ApplicationController < ActionController::Base | @@ -151,8 +163,6 @@ class ApplicationController < ActionController::Base | ||
151 | end | 163 | end |
152 | end | 164 | end |
153 | 165 | ||
154 | - include Noosfero::Plugin::HotSpot | ||
155 | - | ||
156 | # FIXME this filter just loads @plugins to children controllers and helpers | 166 | # FIXME this filter just loads @plugins to children controllers and helpers |
157 | def init_noosfero_plugins | 167 | def init_noosfero_plugins |
158 | plugins | 168 | plugins |
@@ -184,9 +194,6 @@ class ApplicationController < ActionController::Base | @@ -184,9 +194,6 @@ class ApplicationController < ActionController::Base | ||
184 | end | 194 | end |
185 | end | 195 | end |
186 | 196 | ||
187 | - include SearchTermHelper | ||
188 | - include FindByContents | ||
189 | - | ||
190 | def find_suggestions(query, context, asset, options={}) | 197 | def find_suggestions(query, context, asset, options={}) |
191 | plugins.dispatch_first(:find_suggestions, query, context, asset, options) | 198 | plugins.dispatch_first(:find_suggestions, query, context, asset, options) |
192 | end | 199 | end |
app/controllers/box_organizer_controller.rb
@@ -109,7 +109,7 @@ class BoxOrganizerController < ApplicationController | @@ -109,7 +109,7 @@ class BoxOrganizerController < ApplicationController | ||
109 | def show_block_type_info | 109 | def show_block_type_info |
110 | type = params[:type] | 110 | type = params[:type] |
111 | if type.blank? || !available_blocks.map(&:name).include?(type) | 111 | if type.blank? || !available_blocks.map(&:name).include?(type) |
112 | - raise ArgumentError.new("Type %s is not allowed. Go away." % type) | 112 | + raise ArgumentError.new("Type %s is not allowed. Go away.".html_safe % type) |
113 | end | 113 | end |
114 | @block = type.constantize.new | 114 | @block = type.constantize.new |
115 | @block.box = Box.new(:owner => boxes_holder) | 115 | @block.box = Box.new(:owner => boxes_holder) |
@@ -122,7 +122,7 @@ class BoxOrganizerController < ApplicationController | @@ -122,7 +122,7 @@ class BoxOrganizerController < ApplicationController | ||
122 | 122 | ||
123 | def new_block(type, box) | 123 | def new_block(type, box) |
124 | if !available_blocks.map(&:name).include?(type) | 124 | if !available_blocks.map(&:name).include?(type) |
125 | - raise ArgumentError.new("Type %s is not allowed. Go away." % type) | 125 | + raise ArgumentError.new("Type %s is not allowed. Go away.".html_safe % type) |
126 | end | 126 | end |
127 | block = type.constantize.new | 127 | block = type.constantize.new |
128 | box.blocks << block | 128 | box.blocks << block |
@@ -0,0 +1,169 @@ | @@ -0,0 +1,169 @@ | ||
1 | +module AuthenticatedSystem | ||
2 | + | ||
3 | + protected | ||
4 | + | ||
5 | + extend ActiveSupport::Concern | ||
6 | + | ||
7 | + included do | ||
8 | + if self < ActionController::Base | ||
9 | + around_filter :user_set_current | ||
10 | + before_filter :override_user | ||
11 | + before_filter :login_from_cookie | ||
12 | + end | ||
13 | + | ||
14 | + # Inclusion hook to make #current_user and #logged_in? | ||
15 | + # available as ActionView helper methods. | ||
16 | + helper_method :current_user, :logged_in? | ||
17 | + end | ||
18 | + | ||
19 | + # Returns true or false if the user is logged in. | ||
20 | + # Preloads @current_user with the user model if they're logged in. | ||
21 | + def logged_in? | ||
22 | + current_user != nil | ||
23 | + end | ||
24 | + | ||
25 | + # Accesses the current user from the session. | ||
26 | + def current_user user_id = session[:user] | ||
27 | + @current_user ||= begin | ||
28 | + user = User.find_by id: user_id if user_id | ||
29 | + user.session = session if user | ||
30 | + User.current = user | ||
31 | + user | ||
32 | + end | ||
33 | + end | ||
34 | + | ||
35 | + # Store the given user in the session. | ||
36 | + def current_user=(new_user) | ||
37 | + if new_user.nil? | ||
38 | + session.delete(:user) | ||
39 | + else | ||
40 | + session[:user] = new_user.id | ||
41 | + new_user.session = session | ||
42 | + new_user.register_login | ||
43 | + end | ||
44 | + @current_user = User.current = new_user | ||
45 | + end | ||
46 | + | ||
47 | + # See impl. from http://stackoverflow.com/a/2513456/670229 | ||
48 | + def user_set_current | ||
49 | + User.current = current_user | ||
50 | + yield | ||
51 | + ensure | ||
52 | + # to address the thread variable leak issues in Puma/Thin webserver | ||
53 | + User.current = nil | ||
54 | + end | ||
55 | + | ||
56 | + # Check if the user is authorized. | ||
57 | + # | ||
58 | + # Override this method in your controllers if you want to restrict access | ||
59 | + # to only a few actions or if you want to check if the user | ||
60 | + # has the correct rights. | ||
61 | + # | ||
62 | + # Example: | ||
63 | + # | ||
64 | + # # only allow nonbobs | ||
65 | + # def authorize? | ||
66 | + # current_user.login != "bob" | ||
67 | + # end | ||
68 | + def authorized? | ||
69 | + true | ||
70 | + end | ||
71 | + | ||
72 | + # Filter method to enforce a login requirement. | ||
73 | + # | ||
74 | + # To require logins for all actions, use this in your controllers: | ||
75 | + # | ||
76 | + # before_filter :login_required | ||
77 | + # | ||
78 | + # To require logins for specific actions, use this in your controllers: | ||
79 | + # | ||
80 | + # before_filter :login_required, :only => [ :edit, :update ] | ||
81 | + # | ||
82 | + # To skip this in a subclassed controller: | ||
83 | + # | ||
84 | + # skip_before_filter :login_required | ||
85 | + # | ||
86 | + def login_required | ||
87 | + username, passwd = get_auth_data | ||
88 | + if username && passwd | ||
89 | + self.current_user ||= User.authenticate(username, passwd) || nil | ||
90 | + end | ||
91 | + if logged_in? && authorized? | ||
92 | + true | ||
93 | + else | ||
94 | + if params[:require_login_popup] | ||
95 | + render :json => { :require_login_popup => true } | ||
96 | + else | ||
97 | + access_denied | ||
98 | + end | ||
99 | + end | ||
100 | + end | ||
101 | + | ||
102 | + # Redirect as appropriate when an access request fails. | ||
103 | + # | ||
104 | + # The default action is to redirect to the login screen. | ||
105 | + # | ||
106 | + # Override this method in your controllers if you want to have special | ||
107 | + # behavior in case the user is not authorized | ||
108 | + # to access the requested action. For example, a popup window might | ||
109 | + # simply close itself. | ||
110 | + def access_denied | ||
111 | + respond_to do |accepts| | ||
112 | + accepts.html do | ||
113 | + if request.xhr? | ||
114 | + render :text => _('Access denied'), :status => 401 | ||
115 | + else | ||
116 | + store_location | ||
117 | + redirect_to :controller => '/account', :action => 'login' | ||
118 | + end | ||
119 | + end | ||
120 | + accepts.xml do | ||
121 | + headers["Status"] = "Unauthorized" | ||
122 | + headers["WWW-Authenticate"] = %(Basic realm="Web Password") | ||
123 | + render :text => "Could't authenticate you", :status => '401 Unauthorized' | ||
124 | + end | ||
125 | + end | ||
126 | + false | ||
127 | + end | ||
128 | + | ||
129 | + # Store the URI of the current request in the session. | ||
130 | + # | ||
131 | + # We can return to this location by calling #redirect_back_or_default. | ||
132 | + def store_location(location = request.url) | ||
133 | + session[:return_to] = location | ||
134 | + end | ||
135 | + | ||
136 | + # Redirect to the URI stored by the most recent store_location call or | ||
137 | + # to the passed default. | ||
138 | + def redirect_back_or_default(default) | ||
139 | + if session[:return_to] | ||
140 | + redirect_to(session.delete(:return_to)) | ||
141 | + else | ||
142 | + redirect_to(default) | ||
143 | + end | ||
144 | + end | ||
145 | + | ||
146 | + def override_user | ||
147 | + return if params[:override_user].blank? | ||
148 | + return unless logged_in? and user.is_admin? environment | ||
149 | + @current_user = nil | ||
150 | + current_user params[:override_user] | ||
151 | + end | ||
152 | + | ||
153 | + # When called with before_filter :login_from_cookie will check for an :auth_token | ||
154 | + # cookie and log the user back in if apropriate | ||
155 | + def login_from_cookie | ||
156 | + return if cookies[:auth_token].blank? or logged_in? | ||
157 | + user = User.where(remember_token: cookies[:auth_token]).first | ||
158 | + self.current_user = user if user and user.remember_token? | ||
159 | + end | ||
160 | + | ||
161 | + private | ||
162 | + @@http_auth_headers = %w(X-HTTP_AUTHORIZATION HTTP_AUTHORIZATION Authorization) | ||
163 | + # gets BASIC auth info | ||
164 | + def get_auth_data | ||
165 | + auth_key = @@http_auth_headers.detect { |h| request.env.has_key?(h) } | ||
166 | + auth_data = request.env[auth_key].to_s.split unless auth_key.blank? | ||
167 | + return auth_data && auth_data[0] == 'Basic' ? Base64.decode64(auth_data[1]).split(':')[0..1] : [nil, nil] | ||
168 | + end | ||
169 | +end |
@@ -0,0 +1,50 @@ | @@ -0,0 +1,50 @@ | ||
1 | +module CustomDesign | ||
2 | + | ||
3 | + extend ActiveSupport::Concern | ||
4 | + | ||
5 | + included do | ||
6 | + extend ClassMethods | ||
7 | + include InstanceMethods | ||
8 | + before_filter :load_custom_design if self.respond_to? :before_filter | ||
9 | + end | ||
10 | + | ||
11 | + module ClassMethods | ||
12 | + | ||
13 | + def no_design_blocks | ||
14 | + @no_design_blocks = true | ||
15 | + end | ||
16 | + | ||
17 | + def use_custom_design options = {} | ||
18 | + @custom_design = options | ||
19 | + end | ||
20 | + | ||
21 | + def custom_design | ||
22 | + @custom_design ||= {} | ||
23 | + end | ||
24 | + | ||
25 | + def uses_design_blocks? | ||
26 | + !@no_design_blocks | ||
27 | + end | ||
28 | + | ||
29 | + end | ||
30 | + | ||
31 | + module InstanceMethods | ||
32 | + | ||
33 | + protected | ||
34 | + | ||
35 | + def uses_design_blocks? | ||
36 | + !@no_design_blocks && self.class.uses_design_blocks? | ||
37 | + end | ||
38 | + | ||
39 | + def load_custom_design | ||
40 | + # see also: LayoutHelper#body_classes | ||
41 | + @layout_template = self.class.custom_design[:layout_template] | ||
42 | + end | ||
43 | + | ||
44 | + def custom_design | ||
45 | + @custom_design || self.class.custom_design | ||
46 | + end | ||
47 | + | ||
48 | + end | ||
49 | + | ||
50 | +end |
@@ -0,0 +1,40 @@ | @@ -0,0 +1,40 @@ | ||
1 | +module NeedsProfile | ||
2 | + | ||
3 | + module ClassMethods | ||
4 | + def needs_profile | ||
5 | + before_filter :load_profile | ||
6 | + end | ||
7 | + end | ||
8 | + | ||
9 | + def self.included(including) | ||
10 | + including.send(:extend, NeedsProfile::ClassMethods) | ||
11 | + end | ||
12 | + | ||
13 | + def boxes_holder | ||
14 | + profile || environment # prefers profile, but defaults to environment | ||
15 | + end | ||
16 | + | ||
17 | + def profile | ||
18 | + @profile | ||
19 | + end | ||
20 | + | ||
21 | + protected | ||
22 | + | ||
23 | + def load_profile | ||
24 | + if params[:profile] | ||
25 | + params[:profile].downcase! | ||
26 | + @profile ||= environment.profiles.where(identifier: params[:profile]).first | ||
27 | + end | ||
28 | + | ||
29 | + if @profile | ||
30 | + profile_hostname = @profile.hostname | ||
31 | + if profile_hostname && profile_hostname != request.host | ||
32 | + params.delete(:profile) | ||
33 | + redirect_to(Noosfero.url_options.merge(params).merge(:host => profile_hostname)) | ||
34 | + end | ||
35 | + else | ||
36 | + render_not_found | ||
37 | + end | ||
38 | + end | ||
39 | + | ||
40 | +end |
@@ -0,0 +1,58 @@ | @@ -0,0 +1,58 @@ | ||
1 | +class CirclesController < MyProfileController | ||
2 | + | ||
3 | + before_action :accept_only_post, :only => [:create, :update, :destroy] | ||
4 | + | ||
5 | + def index | ||
6 | + @circles = profile.circles | ||
7 | + end | ||
8 | + | ||
9 | + def new | ||
10 | + @circle = Circle.new | ||
11 | + end | ||
12 | + | ||
13 | + def create | ||
14 | + @circle = Circle.new(params[:circle].merge({ :person => profile })) | ||
15 | + if @circle.save | ||
16 | + redirect_to :action => 'index' | ||
17 | + else | ||
18 | + render :action => 'new' | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
22 | + def xhr_create | ||
23 | + if request.xhr? | ||
24 | + circle = Circle.new(params[:circle].merge({:person => profile })) | ||
25 | + if circle.save | ||
26 | + render :partial => "circle_checkbox", :locals => { :circle => circle }, | ||
27 | + :status => 201 | ||
28 | + else | ||
29 | + render :text => _('The circle could not be saved'), :status => 400 | ||
30 | + end | ||
31 | + else | ||
32 | + render_not_found | ||
33 | + end | ||
34 | + end | ||
35 | + | ||
36 | + def edit | ||
37 | + @circle = Circle.find_by_id(params[:id]) | ||
38 | + render_not_found if @circle.nil? | ||
39 | + end | ||
40 | + | ||
41 | + def update | ||
42 | + @circle = Circle.find_by_id(params[:id]) | ||
43 | + return render_not_found if @circle.nil? | ||
44 | + | ||
45 | + if @circle.update(params[:circle]) | ||
46 | + redirect_to :action => 'index' | ||
47 | + else | ||
48 | + render :action => 'edit' | ||
49 | + end | ||
50 | + end | ||
51 | + | ||
52 | + def destroy | ||
53 | + @circle = Circle.find_by_id(params[:id]) | ||
54 | + return render_not_found if @circle.nil? | ||
55 | + @circle.destroy | ||
56 | + redirect_to :action => 'index' | ||
57 | + end | ||
58 | +end |
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +class FollowersController < MyProfileController | ||
2 | + | ||
3 | + before_action :only_for_person, :only => :index | ||
4 | + before_action :accept_only_post, :only => [:update_category] | ||
5 | + | ||
6 | + def index | ||
7 | + @followed_people = profile.followed_profiles.order(:type) | ||
8 | + @profile_types = {_('All profiles') => nil}.merge(Circle.profile_types).to_a | ||
9 | + | ||
10 | + if params['filter'].present? | ||
11 | + @followed_people = @followed_people.where(:type => params['filter']) | ||
12 | + @active_filter = params['filter'] | ||
13 | + end | ||
14 | + | ||
15 | + @followed_people = @followed_people.paginate(:per_page => 15, :page => params[:npage]) | ||
16 | + end | ||
17 | + | ||
18 | + def set_category_modal | ||
19 | + followed_profile = Profile.find(params[:followed_profile_id]) | ||
20 | + circles = Circle.where(:person => profile, :profile_type => followed_profile.class.name) | ||
21 | + render :partial => 'followers/edit_circles_modal', :locals => { :circles => circles, :followed_profile => followed_profile } | ||
22 | + end | ||
23 | + | ||
24 | + def update_category | ||
25 | + followed_profile = Profile.find_by(:id => params["followed_profile_id"]) | ||
26 | + | ||
27 | + selected_circles = params[:circles].map{ |circle_name, circle_id| Circle.find_by(:id => circle_id) }.select{ |c| c.present? } | ||
28 | + | ||
29 | + if followed_profile | ||
30 | + profile.update_profile_circles(followed_profile, selected_circles) | ||
31 | + render :text => _("Circles of %s updated successfully") % followed_profile.name, :status => 200 | ||
32 | + else | ||
33 | + render :text => _("Error: No profile to follow."), :status => 400 | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | + protected | ||
38 | + | ||
39 | + def only_for_person | ||
40 | + render_not_found unless profile.person? | ||
41 | + end | ||
42 | + | ||
43 | +end |
app/controllers/my_profile/tasks_controller.rb
@@ -14,7 +14,7 @@ class TasksController < MyProfileController | @@ -14,7 +14,7 @@ class TasksController < MyProfileController | ||
14 | @filter_text = params[:filter_text].presence | 14 | @filter_text = params[:filter_text].presence |
15 | @filter_responsible = params[:filter_responsible] | 15 | @filter_responsible = params[:filter_responsible] |
16 | @task_types = Task.pending_types_for(profile) | 16 | @task_types = Task.pending_types_for(profile) |
17 | - @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) | 17 | + @tasks = Task.pending_all_by_filter(profile, @filter_type, @filter_text).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) |
18 | @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present? | 18 | @tasks = @tasks.where(:responsible_id => @filter_responsible.to_i != -1 ? @filter_responsible : nil) if @filter_responsible.present? |
19 | @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) | 19 | @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) |
20 | @failed = params ? params[:failed] : {} | 20 | @failed = params ? params[:failed] : {} |
@@ -101,7 +101,7 @@ class TasksController < MyProfileController | @@ -101,7 +101,7 @@ class TasksController < MyProfileController | ||
101 | def search_tasks | 101 | def search_tasks |
102 | filter_type = params[:filter_type].presence | 102 | filter_type = params[:filter_type].presence |
103 | filter_text = params[:filter_text].presence | 103 | filter_text = params[:filter_text].presence |
104 | - result = Task.pending_all(profile,filter_type, filter_text) | 104 | + result = Task.pending_all_by_filter(profile,filter_type, filter_text) |
105 | 105 | ||
106 | render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} } | 106 | render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} } |
107 | end | 107 | end |
app/controllers/public/account_controller.rb
@@ -205,7 +205,7 @@ class AccountController < ApplicationController | @@ -205,7 +205,7 @@ class AccountController < ApplicationController | ||
205 | if params[:value].blank? | 205 | if params[:value].blank? |
206 | @change_password.errors[:base] << _('Can not recover user password with blank value.') | 206 | @change_password.errors[:base] << _('Can not recover user password with blank value.') |
207 | else | 207 | else |
208 | - @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".') % [fields_label, params[:value]] | 208 | + @change_password.errors[:base] << _('Could not find any user with %s equal to "%s".').html_safe % [fields_label, params[:value]] |
209 | end | 209 | end |
210 | rescue ActiveRecord::RecordInvalid | 210 | rescue ActiveRecord::RecordInvalid |
211 | @change_password.errors[:base] << _('Could not perform password recovery for the user.') | 211 | @change_password.errors[:base] << _('Could not perform password recovery for the user.') |
app/controllers/public/content_viewer_controller.rb
@@ -128,9 +128,9 @@ class ContentViewerController < ApplicationController | @@ -128,9 +128,9 @@ class ContentViewerController < ApplicationController | ||
128 | end | 128 | end |
129 | 129 | ||
130 | unless @page.display_to?(user) | 130 | unless @page.display_to?(user) |
131 | - if !profile.visible? || profile.secret? || (user && user.follows?(profile)) || user.blank? | 131 | + if !profile.visible? || profile.secret? || (user && profile.in_social_circle?(user)) || user.blank? |
132 | render_access_denied | 132 | render_access_denied |
133 | - else #!profile.public? | 133 | + else |
134 | private_profile_partial_parameters | 134 | private_profile_partial_parameters |
135 | render :template => 'profile/_private_profile', :status => 403, :formats => [:html] | 135 | render :template => 'profile/_private_profile', :status => 403, :formats => [:html] |
136 | end | 136 | end |
app/controllers/public/profile_controller.rb
@@ -3,7 +3,9 @@ class ProfileController < PublicController | @@ -3,7 +3,9 @@ class ProfileController < PublicController | ||
3 | needs_profile | 3 | needs_profile |
4 | before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] | 4 | before_filter :check_access_to_profile, :except => [:join, :join_not_logged, :index, :add] |
5 | before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail] | 5 | before_filter :store_location, :only => [:join, :join_not_logged, :report_abuse, :send_mail] |
6 | - before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail] | 6 | + before_filter :login_required, :only => [:add, :join, :leave, :unblock, :leave_scrap, :remove_scrap, :remove_activity, :view_more_activities, :view_more_network_activities, :report_abuse, :register_report, :leave_comment_on_activity, :send_mail, :follow, :unfollow] |
7 | + before_filter :allow_followers?, :only => [:follow, :unfollow] | ||
8 | + before_filter :accept_only_post, :only => [:follow, :unfollow] | ||
7 | 9 | ||
8 | helper TagsHelper | 10 | helper TagsHelper |
9 | helper ActionTrackerHelper | 11 | helper ActionTrackerHelper |
@@ -42,8 +44,8 @@ class ProfileController < PublicController | @@ -42,8 +44,8 @@ class ProfileController < PublicController | ||
42 | feed_writer = FeedWriter.new | 44 | feed_writer = FeedWriter.new |
43 | data = feed_writer.write( | 45 | data = feed_writer.write( |
44 | tagged, | 46 | tagged, |
45 | - :title => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], | ||
46 | - :description => _("%s's contents tagged with \"%s\"") % [profile.name, @tag], | 47 | + :title => _("%s's contents tagged with \"%s\"").html_safe % [profile.name, @tag], |
48 | + :description => _("%s's contents tagged with \"%s\"").html_safe % [profile.name, @tag], | ||
47 | :link => url_for(profile.url) | 49 | :link => url_for(profile.url) |
48 | ) | 50 | ) |
49 | render :text => data, :content_type => "text/xml" | 51 | render :text => data, :content_type => "text/xml" |
@@ -65,6 +67,14 @@ class ProfileController < PublicController | @@ -65,6 +67,14 @@ class ProfileController < PublicController | ||
65 | end | 67 | end |
66 | end | 68 | end |
67 | 69 | ||
70 | + def following | ||
71 | + @followed_people = profile.followed_profiles.paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.followed_profiles.count) | ||
72 | + end | ||
73 | + | ||
74 | + def followed | ||
75 | + @followed_by = profile.followers.paginate(:per_page => per_page, :page => params[:npage], :total_entries => profile.followers.count) | ||
76 | + end | ||
77 | + | ||
68 | def members | 78 | def members |
69 | if is_cache_expired?(profile.members_cache_key(params)) | 79 | if is_cache_expired?(profile.members_cache_key(params)) |
70 | sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' | 80 | sort = (params[:sort] == 'desc') ? params[:sort] : 'asc' |
@@ -88,7 +98,7 @@ class ProfileController < PublicController | @@ -88,7 +98,7 @@ class ProfileController < PublicController | ||
88 | 98 | ||
89 | def join_modal | 99 | def join_modal |
90 | profile.add_member(user) | 100 | profile.add_member(user) |
91 | - session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name | 101 | + session[:notice] = _('%s administrator still needs to accept you as member.').html_safe % profile.name |
92 | redirect_to :action => :index | 102 | redirect_to :action => :index |
93 | end | 103 | end |
94 | 104 | ||
@@ -98,12 +108,12 @@ class ProfileController < PublicController | @@ -98,12 +108,12 @@ class ProfileController < PublicController | ||
98 | 108 | ||
99 | profile.add_member(user) | 109 | profile.add_member(user) |
100 | if !profile.members.include?(user) | 110 | if !profile.members.include?(user) |
101 | - render :text => {:message => _('%s administrator still needs to accept you as member.') % profile.name}.to_json | 111 | + render :text => {:message => _('%s administrator still needs to accept you as member.').html_safe % profile.name}.to_json |
102 | else | 112 | else |
103 | - render :text => {:message => _('You just became a member of %s.') % profile.name}.to_json | 113 | + render :text => {:message => _('You just became a member of %s.').html_safe % profile.name}.to_json |
104 | end | 114 | end |
105 | else | 115 | else |
106 | - render :text => {:message => _('You are already a member of %s.') % profile.name}.to_json | 116 | + render :text => {:message => _('You are already a member of %s.').html_safe % profile.name}.to_json |
107 | end | 117 | end |
108 | end | 118 | end |
109 | 119 | ||
@@ -125,7 +135,7 @@ class ProfileController < PublicController | @@ -125,7 +135,7 @@ class ProfileController < PublicController | ||
125 | render :text => current_person.leave(profile, params[:reload]) | 135 | render :text => current_person.leave(profile, params[:reload]) |
126 | end | 136 | end |
127 | else | 137 | else |
128 | - render :text => {:message => _('You are not a member of %s.') % profile.name}.to_json | 138 | + render :text => {:message => _('You are not a member of %s.').html_safe % profile.name}.to_json |
129 | end | 139 | end |
130 | end | 140 | end |
131 | 141 | ||
@@ -145,12 +155,41 @@ class ProfileController < PublicController | @@ -145,12 +155,41 @@ class ProfileController < PublicController | ||
145 | # FIXME this shouldn't be in Person model? | 155 | # FIXME this shouldn't be in Person model? |
146 | if !user.memberships.include?(profile) | 156 | if !user.memberships.include?(profile) |
147 | AddFriend.create!(:person => user, :friend => profile) | 157 | AddFriend.create!(:person => user, :friend => profile) |
148 | - render :text => _('%s still needs to accept being your friend.') % profile.name | 158 | + render :text => _('%s still needs to accept being your friend.').html_safe % profile.name |
149 | else | 159 | else |
150 | - render :text => _('You are already a friend of %s.') % profile.name | 160 | + render :text => _('You are already a friend of %s.').html_safe % profile.name |
161 | + end | ||
162 | + end | ||
163 | + | ||
164 | + def follow | ||
165 | + if profile.followed_by?(current_person) | ||
166 | + render :text => _("You are already following %s.") % profile.name, :status => 400 | ||
167 | + else | ||
168 | + selected_circles = params[:circles].map{ |circle_name, circle_id| Circle.find_by(:id => circle_id) }.select{ |c| c.present? } | ||
169 | + if selected_circles.present? | ||
170 | + current_person.follow(profile, selected_circles) | ||
171 | + render :text => _("You are now following %s") % profile.name, :status => 200 | ||
172 | + else | ||
173 | + render :text => _("Select at least one circle to follow %s.") % profile.name, :status => 400 | ||
174 | + end | ||
151 | end | 175 | end |
152 | end | 176 | end |
153 | 177 | ||
178 | + def find_profile_circles | ||
179 | + circles = Circle.where(:person => current_person, :profile_type => profile.class.name) | ||
180 | + render :partial => 'blocks/profile_info_actions/circles', :locals => { :circles => circles, :profile_types => Circle.profile_types.to_a } | ||
181 | + end | ||
182 | + | ||
183 | + def unfollow | ||
184 | + follower = params[:follower_id].present? ? Person.find_by(id: params[:follower_id]) : current_person | ||
185 | + | ||
186 | + if follower && follower.follows?(profile) | ||
187 | + follower.unfollow(profile) | ||
188 | + end | ||
189 | + redirect_url = params["redirect_to"] ? params["redirect_to"] : profile.url | ||
190 | + redirect_to redirect_url | ||
191 | + end | ||
192 | + | ||
154 | def check_friendship | 193 | def check_friendship |
155 | unless logged_in? | 194 | unless logged_in? |
156 | render :text => '' | 195 | render :text => '' |
@@ -178,7 +217,7 @@ class ProfileController < PublicController | @@ -178,7 +217,7 @@ class ProfileController < PublicController | ||
178 | def unblock | 217 | def unblock |
179 | if current_user.person.is_admin?(profile.environment) | 218 | if current_user.person.is_admin?(profile.environment) |
180 | profile.unblock | 219 | profile.unblock |
181 | - session[:notice] = _("You have unblocked %s successfully. ") % profile.name | 220 | + session[:notice] = _("You have unblocked %s successfully. ").html_safe % profile.name |
182 | redirect_to :controller => 'profile', :action => 'index' | 221 | redirect_to :controller => 'profile', :action => 'index' |
183 | else | 222 | else |
184 | message = _('You are not allowed to unblock enterprises in this environment.') | 223 | message = _('You are not allowed to unblock enterprises in this environment.') |
@@ -437,4 +476,8 @@ class ProfileController < PublicController | @@ -437,4 +476,8 @@ class ProfileController < PublicController | ||
437 | [:image, :domains, :preferred_domain, :environment] | 476 | [:image, :domains, :preferred_domain, :environment] |
438 | end | 477 | end |
439 | 478 | ||
479 | + def allow_followers? | ||
480 | + render_not_found unless profile.allow_followers? | ||
481 | + end | ||
482 | + | ||
440 | end | 483 | end |
app/helpers/action_tracker_helper.rb
@@ -14,13 +14,23 @@ module ActionTrackerHelper | @@ -14,13 +14,23 @@ module ActionTrackerHelper | ||
14 | } | 14 | } |
15 | end | 15 | end |
16 | 16 | ||
17 | + def new_follower_description ta | ||
18 | + n_('has 1 new follower:<br />%{name}', 'has %{num} new followers:<br />%{name}', ta.get_follower_name.size).html_safe % { | ||
19 | + num: ta.get_follower_name.size, | ||
20 | + name: safe_join(ta.collect_group_with_index(:follower_name) do |n,i| | ||
21 | + link_to image_tag(ta.get_follower_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")), | ||
22 | + ta.get_follower_url[i], title: n | ||
23 | + end) | ||
24 | + } | ||
25 | + end | ||
26 | + | ||
17 | def join_community_description ta | 27 | def join_community_description ta |
18 | - n_('has joined 1 community:<br />%{name}'.html_safe, 'has joined %{num} communities:<br />%{name}'.html_safe, ta.get_resource_name.size) % { | 28 | + n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size).html_safe % { |
19 | num: ta.get_resource_name.size, | 29 | num: ta.get_resource_name.size, |
20 | - name: ta.collect_group_with_index(:resource_name) do |n,i| | 30 | + name: safe_join(ta.collect_group_with_index(:resource_name) do |n,i| |
21 | link = link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")), | 31 | link = link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")), |
22 | ta.get_resource_url[i], title: n | 32 | ta.get_resource_url[i], title: n |
23 | - end.join.html_safe | 33 | + end) |
24 | } | 34 | } |
25 | end | 35 | end |
26 | 36 | ||
@@ -68,9 +78,9 @@ module ActionTrackerHelper | @@ -68,9 +78,9 @@ module ActionTrackerHelper | ||
68 | end | 78 | end |
69 | 79 | ||
70 | def favorite_enterprise_description ta | 80 | def favorite_enterprise_description ta |
71 | - _('favorited enterprise %{title}') % { | 81 | + (_('favorited enterprise %{title}') % { |
72 | title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url), | 82 | title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url), |
73 | - } | 83 | + }).html_safe |
74 | end | 84 | end |
75 | 85 | ||
76 | end | 86 | end |
app/helpers/application_helper.rb
@@ -880,7 +880,7 @@ module ApplicationHelper | @@ -880,7 +880,7 @@ module ApplicationHelper | ||
880 | link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => user.identifier) | 880 | link_to_all = link_to(content_tag('strong', _('See all')), :controller => 'memberships', :profile => user.identifier) |
881 | end | 881 | end |
882 | link = list.map do |element| | 882 | link = list.map do |element| |
883 | - link_to(content_tag('strong', _('<span>Manage</span> %s') % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s') % element.short_name) | 883 | + link_to(content_tag('strong', _('<span>Manage</span> %s').html_safe % element.short_name(25)), element.admin_url, :class => "icon-menu-"+element.class.identification.underscore, :title => _('Manage %s').html_safe % element.short_name) |
884 | end | 884 | end |
885 | if link_to_all | 885 | if link_to_all |
886 | link << link_to_all | 886 | link << link_to_all |
@@ -921,7 +921,7 @@ module ApplicationHelper | @@ -921,7 +921,7 @@ module ApplicationHelper | ||
921 | logout_link = link_to(logout_icon.html_safe, { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) | 921 | logout_link = link_to(logout_icon.html_safe, { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) |
922 | join_result = safe_join( | 922 | join_result = safe_join( |
923 | [welcome_span.html_safe, render_environment_features(:usermenu).html_safe, admin_link.html_safe, | 923 | [welcome_span.html_safe, render_environment_features(:usermenu).html_safe, admin_link.html_safe, |
924 | - manage_enterprises.html_safe, manage_communities.html_safe, ctrl_panel_link.html_safe, | 924 | + manage_enterprises, manage_communities, ctrl_panel_link.html_safe, |
925 | pending_tasks_count.html_safe, logout_link.html_safe], "") | 925 | pending_tasks_count.html_safe, logout_link.html_safe], "") |
926 | join_result | 926 | join_result |
927 | end | 927 | end |
app/helpers/boxes_helper.rb
@@ -285,7 +285,7 @@ module BoxesHelper | @@ -285,7 +285,7 @@ module BoxesHelper | ||
285 | end | 285 | end |
286 | 286 | ||
287 | if block.respond_to?(:help) | 287 | if block.respond_to?(:help) |
288 | - buttons << modal_inline_icon(:help, _('Help on this block'), {}, "#help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help, :style => 'margin-bottom: 1em;') + modal_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}") | 288 | + buttons << modal_inline_icon(:help, _('Help on this block'), {}, "#help-on-box-#{block.id}") << content_tag('div', content_tag('h2', _('Help')) + content_tag('div', block.help.html_safe, :style => 'margin-bottom: 1em;') + modal_close_button(_('Close')), :style => 'display: none;', :id => "help-on-box-#{block.id}") |
289 | end | 289 | end |
290 | 290 | ||
291 | if block.embedable? | 291 | if block.embedable? |
app/helpers/forms_helper.rb
@@ -128,14 +128,14 @@ module FormsHelper | @@ -128,14 +128,14 @@ module FormsHelper | ||
128 | counter += 1 | 128 | counter += 1 |
129 | row << item | 129 | row << item |
130 | if counter % per_row == 0 | 130 | if counter % per_row == 0 |
131 | - rows << content_tag('tr', row.join("\n")) | 131 | + rows << content_tag('tr', row.join("\n").html_safe) |
132 | counter = 0 | 132 | counter = 0 |
133 | row = [] | 133 | row = [] |
134 | end | 134 | end |
135 | end | 135 | end |
136 | - rows << content_tag('tr', row.join("\n")) | 136 | + rows << content_tag('tr', row.join("\n").html_safe) |
137 | 137 | ||
138 | - content_tag('table',rows.join("\n")) | 138 | + content_tag('table',rows.join("\n").html_safe) |
139 | end | 139 | end |
140 | 140 | ||
141 | def date_field(name, value, datepicker_options = {}, html_options = {}) | 141 | def date_field(name, value, datepicker_options = {}, html_options = {}) |
app/helpers/profile_helper.rb
@@ -11,7 +11,7 @@ module ProfileHelper | @@ -11,7 +11,7 @@ module ProfileHelper | ||
11 | PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality] | 11 | PERSON_CATEGORIES[:location] = [:address, :address_reference, :zip_code, :city, :state, :district, :country, :nationality] |
12 | PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity] | 12 | PERSON_CATEGORIES[:work] = [:organization, :organization_website, :professional_activity] |
13 | PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study] | 13 | PERSON_CATEGORIES[:study] = [:schooling, :formation, :area_of_study] |
14 | - PERSON_CATEGORIES[:network] = [:friends, :communities, :enterprises] | 14 | + PERSON_CATEGORIES[:network] = [:friends, :followers, :followed_profiles, :communities, :enterprises] |
15 | PERSON_CATEGORIES.merge!(COMMON_CATEGORIES) | 15 | PERSON_CATEGORIES.merge!(COMMON_CATEGORIES) |
16 | 16 | ||
17 | ORGANIZATION_CATEGORIES = {} | 17 | ORGANIZATION_CATEGORIES = {} |
@@ -42,7 +42,8 @@ module ProfileHelper | @@ -42,7 +42,8 @@ module ProfileHelper | ||
42 | :created_at => _('Profile created at'), | 42 | :created_at => _('Profile created at'), |
43 | :members_count => _('Members'), | 43 | :members_count => _('Members'), |
44 | :privacy_setting => _('Privacy setting'), | 44 | :privacy_setting => _('Privacy setting'), |
45 | - :article_tags => _('Tags') | 45 | + :article_tags => _('Tags'), |
46 | + :followed_profiles => _('Following') | ||
46 | } | 47 | } |
47 | 48 | ||
48 | EXCEPTION = { | 49 | EXCEPTION = { |
@@ -144,6 +145,14 @@ module ProfileHelper | @@ -144,6 +145,14 @@ module ProfileHelper | ||
144 | link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) | 145 | link_to(n_('One picture', '%{num} pictures', gallery.images.published.count) % { :num => gallery.images.published.count }, gallery.url) |
145 | end | 146 | end |
146 | 147 | ||
148 | + def treat_followers(followers) | ||
149 | + link_to(profile.followers.count, {:action=>"followed", :controller=>"profile", :profile=>"#{profile.identifier}"}) | ||
150 | + end | ||
151 | + | ||
152 | + def treat_followed_profiles(followed_profiles) | ||
153 | + link_to(profile.followed_profiles.count, {:action=>"following", :controller=>"profile", :profile=>"#{profile.identifier}"}) | ||
154 | + end | ||
155 | + | ||
147 | def treat_events(events) | 156 | def treat_events(events) |
148 | link_to events.published.count, :controller => 'events', :action => 'events' | 157 | link_to events.published.count, :controller => 'events', :action => 'events' |
149 | end | 158 | end |
app/jobs/notify_activity_to_profiles_job.rb
@@ -19,8 +19,8 @@ class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id) | @@ -19,8 +19,8 @@ class NotifyActivityToProfilesJob < Struct.new(:tracked_action_id) | ||
19 | # Notify the user | 19 | # Notify the user |
20 | ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id) | 20 | ActionTrackerNotification.create(:profile_id => tracked_action.user.id, :action_tracker_id => tracked_action.id) |
21 | 21 | ||
22 | - # Notify all friends | ||
23 | - ActionTrackerNotification.connection.execute("insert into action_tracker_notifications(profile_id, action_tracker_id) select f.friend_id, #{tracked_action.id} from friendships as f where person_id=#{tracked_action.user.id} and f.friend_id not in (select atn.profile_id from action_tracker_notifications as atn where atn.action_tracker_id = #{tracked_action.id})") | 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}))") | ||
24 | 24 | ||
25 | if tracked_action.user.is_a? Organization | 25 | if tracked_action.user.is_a? Organization |
26 | ActionTrackerNotification.connection.execute "insert into action_tracker_notifications(profile_id, action_tracker_id) " + | 26 | ActionTrackerNotification.connection.execute "insert into action_tracker_notifications(profile_id, action_tracker_id) " + |
app/mailers/contact.rb
@@ -47,8 +47,8 @@ class Contact | @@ -47,8 +47,8 @@ class Contact | ||
47 | content_type: 'text/html', | 47 | content_type: 'text/html', |
48 | to: contact.dest.notification_emails, | 48 | to: contact.dest.notification_emails, |
49 | reply_to: contact.email, | 49 | reply_to: contact.email, |
50 | - subject: "[#{contact.dest.short_name(30)}] " + contact.subject, | ||
51 | - from: "#{contact.name} <#{contact.dest.environment.noreply_email}>" | 50 | + subject: "[#{contact.dest.short_name(30)}] #{contact.subject}".html_safe, |
51 | + from: "#{contact.name} <#{contact.dest.environment.noreply_email}>".html_safe | ||
52 | } | 52 | } |
53 | 53 | ||
54 | if contact.sender | 54 | if contact.sender |
app/mailers/environment_mailing.rb
@@ -30,7 +30,7 @@ class EnvironmentMailing < Mailing | @@ -30,7 +30,7 @@ class EnvironmentMailing < Mailing | ||
30 | end | 30 | end |
31 | 31 | ||
32 | def signature_message | 32 | def signature_message |
33 | - _('Sent by %s.') % source.name | 33 | + _('Sent by %s.').html_safe % source.name |
34 | end | 34 | end |
35 | 35 | ||
36 | def url | 36 | def url |
app/mailers/mailing.rb
@@ -2,7 +2,8 @@ require_dependency 'mailing_job' | @@ -2,7 +2,8 @@ require_dependency 'mailing_job' | ||
2 | 2 | ||
3 | class Mailing < ApplicationRecord | 3 | class Mailing < ApplicationRecord |
4 | 4 | ||
5 | - acts_as_having_settings :field => :data | 5 | + extend ActsAsHavingSettings::ClassMethods |
6 | + acts_as_having_settings field: :data | ||
6 | 7 | ||
7 | attr_accessible :subject, :body, :data | 8 | attr_accessible :subject, :body, :data |
8 | 9 | ||
@@ -23,11 +24,11 @@ class Mailing < ApplicationRecord | @@ -23,11 +24,11 @@ class Mailing < ApplicationRecord | ||
23 | end | 24 | end |
24 | 25 | ||
25 | def generate_from | 26 | def generate_from |
26 | - "#{source.name} <#{if source.is_a? Environment then source.noreply_email else source.contact_email end}>" | 27 | + "#{source.name} <#{if source.is_a? Environment then source.noreply_email else source.contact_email end}>".html_safe |
27 | end | 28 | end |
28 | 29 | ||
29 | def generate_subject | 30 | def generate_subject |
30 | - '[%s] %s' % [source.name, subject] | 31 | + '[%s] %s'.html_safe % [source.name, subject] |
31 | end | 32 | end |
32 | 33 | ||
33 | def signature_message | 34 | def signature_message |
app/mailers/organization_mailing.rb
@@ -30,7 +30,7 @@ class OrganizationMailing < Mailing | @@ -30,7 +30,7 @@ class OrganizationMailing < Mailing | ||
30 | end | 30 | end |
31 | 31 | ||
32 | def signature_message | 32 | def signature_message |
33 | - _('Sent by community %s.') % source.name | 33 | + _('Sent by community %s.').html_safe % source.name |
34 | end | 34 | end |
35 | 35 | ||
36 | include Rails.application.routes.url_helpers | 36 | include Rails.application.routes.url_helpers |
app/mailers/pending_task_notifier.rb
@@ -12,8 +12,8 @@ class PendingTaskNotifier < ApplicationMailer | @@ -12,8 +12,8 @@ class PendingTaskNotifier < ApplicationMailer | ||
12 | 12 | ||
13 | mail( | 13 | mail( |
14 | to: person.email, | 14 | to: person.email, |
15 | - from: "#{person.environment.name} <#{person.environment.noreply_email}>", | ||
16 | - subject: _("[%s] Pending tasks") % person.environment.name | 15 | + from: "#{person.environment.name} <#{person.environment.noreply_email}>".html_safe, |
16 | + subject: _("[%s] Pending tasks").html_safe % person.environment.name | ||
17 | ) | 17 | ) |
18 | end | 18 | end |
19 | 19 |
app/mailers/scrap_notifier.rb
@@ -14,8 +14,8 @@ class ScrapNotifier < ApplicationMailer | @@ -14,8 +14,8 @@ class ScrapNotifier < ApplicationMailer | ||
14 | @url = sender.environment.top_url | 14 | @url = sender.environment.top_url |
15 | mail( | 15 | mail( |
16 | to: receiver.email, | 16 | to: receiver.email, |
17 | - from: "#{sender.environment.name} <#{sender.environment.noreply_email}>", | ||
18 | - subject: _("[%s] You received a scrap!") % [sender.environment.name] | 17 | + from: "#{sender.environment.name} <#{sender.environment.noreply_email}>".html_safe, |
18 | + subject: _("[%s] You received a scrap!").html_safe % [sender.environment.name] | ||
19 | ) | 19 | ) |
20 | end | 20 | end |
21 | end | 21 | end |
app/mailers/task_mailer.rb
@@ -14,7 +14,7 @@ class TaskMailer < ApplicationMailer | @@ -14,7 +14,7 @@ class TaskMailer < ApplicationMailer | ||
14 | mail( | 14 | mail( |
15 | to: task.target.notification_emails.compact, | 15 | to: task.target.notification_emails.compact, |
16 | from: self.class.generate_from(task), | 16 | from: self.class.generate_from(task), |
17 | - subject: "[%s] %s" % [task.environment.name, task.target_notification_description] | 17 | + subject: "[%s] %s".html_safe % [task.environment.name, task.target_notification_description] |
18 | ) | 18 | ) |
19 | end | 19 | end |
20 | 20 | ||
@@ -27,7 +27,7 @@ class TaskMailer < ApplicationMailer | @@ -27,7 +27,7 @@ class TaskMailer < ApplicationMailer | ||
27 | mail( | 27 | mail( |
28 | to: task.friend_email, | 28 | to: task.friend_email, |
29 | from: self.class.generate_from(task), | 29 | from: self.class.generate_from(task), |
30 | - subject: '[%s] %s' % [ task.requestor.environment.name, task.target_notification_description ] | 30 | + subject: '[%s] %s'.html_safe % [ task.requestor.environment.name, task.target_notification_description ] |
31 | ) | 31 | ) |
32 | end | 32 | end |
33 | 33 | ||
@@ -43,7 +43,7 @@ class TaskMailer < ApplicationMailer | @@ -43,7 +43,7 @@ class TaskMailer < ApplicationMailer | ||
43 | mail_with_template( | 43 | mail_with_template( |
44 | to: task.requestor.notification_emails, | 44 | to: task.requestor.notification_emails, |
45 | from: self.class.generate_from(task), | 45 | from: self.class.generate_from(task), |
46 | - subject: '[%s] %s' % [task.requestor.environment.name, task.target_notification_description], | 46 | + subject: '[%s] %s'.html_safe % [task.requestor.environment.name, task.target_notification_description], |
47 | email_template: task.email_template, | 47 | email_template: task.email_template, |
48 | template_params: {:environment => task.requestor.environment, :task => task, :message => @message, :url => @url, :requestor => task.requestor} | 48 | template_params: {:environment => task.requestor.environment, :task => task, :message => @message, :url => @url, :requestor => task.requestor} |
49 | ) | 49 | ) |
app/mailers/user_mailer.rb
@@ -13,8 +13,8 @@ class UserMailer < ApplicationMailer | @@ -13,8 +13,8 @@ class UserMailer < ApplicationMailer | ||
13 | 13 | ||
14 | mail( | 14 | mail( |
15 | to: user_email, | 15 | to: user_email, |
16 | - from: "#{user.environment.name} <#{user.environment.contact_email}>", | ||
17 | - subject: _("[%{environment}] Welcome to %{environment} mail!") % { :environment => user.environment.name } | 16 | + from: "#{user.environment.name} <#{user.environment.contact_email}>".html_safe, |
17 | + subject: _("[%{environment}] Welcome to %{environment} mail!").html_safe % { :environment => user.environment.name } | ||
18 | ) | 18 | ) |
19 | end | 19 | end |
20 | 20 | ||
@@ -30,7 +30,7 @@ class UserMailer < ApplicationMailer | @@ -30,7 +30,7 @@ class UserMailer < ApplicationMailer | ||
30 | mail_with_template( | 30 | mail_with_template( |
31 | from: "#{user.environment.name} <#{user.environment.contact_email}>", | 31 | from: "#{user.environment.name} <#{user.environment.contact_email}>", |
32 | to: user.email, | 32 | to: user.email, |
33 | - subject: _("[%s] Activate your account") % [user.environment.name], | 33 | + subject: _("[%s] Activate your account").html_safe % [user.environment.name], |
34 | template_params: {:environment => user.environment, :activation_code => @activation_code, :redirection => @redirection, :join => @join, :person => user.person, :url => @url}, | 34 | template_params: {:environment => user.environment, :activation_code => @activation_code, :redirection => @redirection, :join => @join, :person => user.person, :url => @url}, |
35 | email_template: user.environment.email_templates.find_by_template_type(:user_activation), | 35 | email_template: user.environment.email_templates.find_by_template_type(:user_activation), |
36 | ) | 36 | ) |
@@ -44,8 +44,8 @@ class UserMailer < ApplicationMailer | @@ -44,8 +44,8 @@ class UserMailer < ApplicationMailer | ||
44 | mail( | 44 | mail( |
45 | content_type: 'text/html', | 45 | content_type: 'text/html', |
46 | to: user.email, | 46 | to: user.email, |
47 | - from: "#{user.environment.name} <#{user.environment.contact_email}>", | ||
48 | - subject: email_subject.blank? ? _("Welcome to environment %s") % [user.environment.name] : email_subject, | 47 | + from: "#{user.environment.name} <#{user.environment.contact_email}>".html_safe, |
48 | + subject: email_subject.blank? ? _("Welcome to environment %s").html_safe % [user.environment.name] : email_subject, | ||
49 | body: @body | 49 | body: @body |
50 | ) | 50 | ) |
51 | end | 51 | end |
@@ -63,8 +63,8 @@ class UserMailer < ApplicationMailer | @@ -63,8 +63,8 @@ class UserMailer < ApplicationMailer | ||
63 | mail( | 63 | mail( |
64 | content_type: 'text/html', | 64 | content_type: 'text/html', |
65 | to: user.email, | 65 | to: user.email, |
66 | - from: "#{user.environment.name} <#{user.environment.contact_email}>", | ||
67 | - subject: _("[%s] What about grow up your network?") % user.environment.name | 66 | + from: "#{user.environment.name} <#{user.environment.contact_email}>".html_safe, |
67 | + subject: _("[%s] What about grow up your network?").html_safe % user.environment.name | ||
68 | ) | 68 | ) |
69 | end | 69 | end |
70 | 70 |
app/models/abuse_complaint.rb
@@ -25,7 +25,7 @@ class AbuseComplaint < Task | @@ -25,7 +25,7 @@ class AbuseComplaint < Task | ||
25 | end | 25 | end |
26 | 26 | ||
27 | def title | 27 | def title |
28 | - abuse_reports.count > 1 ? (_('Abuse complaint (%s)') % abuse_reports.count) :_('Abuse complaint') | 28 | + abuse_reports.count > 1 ? (_('Abuse complaint (%s)').html_safe % abuse_reports.count) :_('Abuse complaint') |
29 | end | 29 | end |
30 | 30 | ||
31 | def linked_subject | 31 | def linked_subject |
@@ -57,15 +57,15 @@ class AbuseComplaint < Task | @@ -57,15 +57,15 @@ class AbuseComplaint < Task | ||
57 | end | 57 | end |
58 | 58 | ||
59 | def task_activated_message | 59 | def task_activated_message |
60 | - _('Your profile was reported by the users of %s due to inappropriate behavior. The administrators of the environment are now reviewing the report. To solve this misunderstanding, please contact the administrators.') % environment.name | 60 | + _('Your profile was reported by the users of %s due to inappropriate behavior. The administrators of the environment are now reviewing the report. To solve this misunderstanding, please contact the administrators.').html_safe % environment.name |
61 | end | 61 | end |
62 | 62 | ||
63 | def task_finished_message | 63 | def task_finished_message |
64 | - _('Your profile was disabled by the administrators of %s due to inappropriate behavior. To solve this misunderstanding please contact them.') % environment.name | 64 | + _('Your profile was disabled by the administrators of %s due to inappropriate behavior. To solve this misunderstanding please contact them.').html_safe % environment.name |
65 | end | 65 | end |
66 | 66 | ||
67 | def target_notification_description | 67 | def target_notification_description |
68 | - _('%s was reported due to inappropriate behavior.') % reported.name | 68 | + _('%s was reported due to inappropriate behavior.').html_safe % reported.name |
69 | end | 69 | end |
70 | 70 | ||
71 | def target_notification_message | 71 | def target_notification_message |
app/models/add_member.rb
@@ -22,6 +22,7 @@ class AddMember < Task | @@ -22,6 +22,7 @@ class AddMember < Task | ||
22 | self.roles = [Profile::Roles.member(organization.environment.id).id] | 22 | self.roles = [Profile::Roles.member(organization.environment.id).id] |
23 | end | 23 | end |
24 | target.affiliate(requestor, self.roles.select{|r| !r.to_i.zero? }.map{|i| Role.find(i)}) | 24 | target.affiliate(requestor, self.roles.select{|r| !r.to_i.zero? }.map{|i| Role.find(i)}) |
25 | + person.follow(organization, Circle.find_or_create_by(:person => person, :name =>_('memberships'), :profile_type => 'Community')) | ||
25 | end | 26 | end |
26 | 27 | ||
27 | def title | 28 | def title |
@@ -56,7 +57,7 @@ class AddMember < Task | @@ -56,7 +57,7 @@ class AddMember < Task | ||
56 | def target_notification_description | 57 | def target_notification_description |
57 | requestor_email = " (#{requestor.email})" if requestor.may_display_field_to?("email") | 58 | requestor_email = " (#{requestor.email})" if requestor.may_display_field_to?("email") |
58 | 59 | ||
59 | - _("%{requestor}%{requestor_email} wants to be a member of '%{organization}'.") % {:requestor => requestor.name, :requestor_email => requestor_email, :organization => organization.name} | 60 | + _("%{requestor}%{requestor_email} wants to be a member of '%{organization}'.").html_safe % {:requestor => requestor.name, :requestor_email => requestor_email, :organization => organization.name} |
60 | end | 61 | end |
61 | 62 | ||
62 | def target_notification_message | 63 | def target_notification_message |
app/models/article.rb
@@ -13,7 +13,9 @@ class Article < ApplicationRecord | @@ -13,7 +13,9 @@ class Article < ApplicationRecord | ||
13 | :image_builder, :show_to_followers, :archived, | 13 | :image_builder, :show_to_followers, :archived, |
14 | :author, :display_preview, :published_at, :person_followers | 14 | :author, :display_preview, :published_at, :person_followers |
15 | 15 | ||
16 | + extend ActsAsHavingImage::ClassMethods | ||
16 | acts_as_having_image | 17 | acts_as_having_image |
18 | + | ||
17 | include Noosfero::Plugin::HotSpot | 19 | include Noosfero::Plugin::HotSpot |
18 | 20 | ||
19 | SEARCHABLE_FIELDS = { | 21 | SEARCHABLE_FIELDS = { |
@@ -91,7 +93,8 @@ class Article < ApplicationRecord | @@ -91,7 +93,8 @@ class Article < ApplicationRecord | ||
91 | has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization' | 93 | has_many :article_categorizations_including_virtual, :class_name => 'ArticleCategorization' |
92 | has_many :categories_including_virtual, :through => :article_categorizations_including_virtual, :source => :category | 94 | has_many :categories_including_virtual, :through => :article_categorizations_including_virtual, :source => :category |
93 | 95 | ||
94 | - acts_as_having_settings :field => :setting | 96 | + extend ActsAsHavingSettings::ClassMethods |
97 | + acts_as_having_settings field: :setting | ||
95 | 98 | ||
96 | settings_items :display_hits, :type => :boolean, :default => true | 99 | settings_items :display_hits, :type => :boolean, :default => true |
97 | settings_items :author_name, :type => :string, :default => "" | 100 | settings_items :author_name, :type => :string, :default => "" |
@@ -242,6 +245,7 @@ class Article < ApplicationRecord | @@ -242,6 +245,7 @@ class Article < ApplicationRecord | ||
242 | acts_as_taggable | 245 | acts_as_taggable |
243 | N_('Tag list') | 246 | N_('Tag list') |
244 | 247 | ||
248 | + extend ActsAsFilesystem::ActsMethods | ||
245 | acts_as_filesystem | 249 | acts_as_filesystem |
246 | 250 | ||
247 | acts_as_versioned | 251 | acts_as_versioned |
@@ -534,13 +538,13 @@ class Article < ApplicationRecord | @@ -534,13 +538,13 @@ class Article < ApplicationRecord | ||
534 | 538 | ||
535 | scope :display_filter, lambda {|user, profile| | 539 | scope :display_filter, lambda {|user, profile| |
536 | return published if (user.nil? && profile && profile.public?) | 540 | return published if (user.nil? && profile && profile.public?) |
537 | - return [] if user.nil? || (profile && !profile.public? && !user.follows?(profile)) | 541 | + return [] if user.nil? || (profile && !profile.public? && !profile.in_social_circle?(user)) |
538 | where( | 542 | where( |
539 | [ | 543 | [ |
540 | "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ? | 544 | "published = ? OR last_changed_by_id = ? OR profile_id = ? OR ? |
541 | OR (show_to_followers = ? AND ? AND profile_id IN (?))", true, user.id, user.id, | 545 | OR (show_to_followers = ? AND ? AND profile_id IN (?))", true, user.id, user.id, |
542 | profile.nil? ? false : user.has_permission?(:view_private_content, profile), | 546 | profile.nil? ? false : user.has_permission?(:view_private_content, profile), |
543 | - true, (profile.nil? ? true : user.follows?(profile)), ( profile.nil? ? (user.friends.select('profiles.id')) : [profile.id]) | 547 | + true, (profile.nil? ? true : profile.in_social_circle?(user)), ( profile.nil? ? (user.friends.select('profiles.id')) : [profile.id]) |
544 | ] | 548 | ] |
545 | ) | 549 | ) |
546 | } | 550 | } |
app/models/block.rb
@@ -17,6 +17,7 @@ class Block < ApplicationRecord | @@ -17,6 +17,7 @@ class Block < ApplicationRecord | ||
17 | belongs_to :mirror_block, :class_name => "Block" | 17 | belongs_to :mirror_block, :class_name => "Block" |
18 | has_many :observers, :class_name => "Block", :foreign_key => "mirror_block_id" | 18 | has_many :observers, :class_name => "Block", :foreign_key => "mirror_block_id" |
19 | 19 | ||
20 | + extend ActsAsHavingSettings::ClassMethods | ||
20 | acts_as_having_settings | 21 | acts_as_having_settings |
21 | 22 | ||
22 | scope :enabled, -> { where :enabled => true } | 23 | scope :enabled, -> { where :enabled => true } |
@@ -88,7 +89,7 @@ class Block < ApplicationRecord | @@ -88,7 +89,7 @@ class Block < ApplicationRecord | ||
88 | end | 89 | end |
89 | 90 | ||
90 | def display_to_user?(user) | 91 | def display_to_user?(user) |
91 | - display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && user.follows?(owner)) | 92 | + display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && owner.in_social_circle?(user)) |
92 | end | 93 | end |
93 | 94 | ||
94 | def display_always(context) | 95 | def display_always(context) |
app/models/blog.rb
@@ -2,7 +2,9 @@ class Blog < Folder | @@ -2,7 +2,9 @@ class Blog < Folder | ||
2 | 2 | ||
3 | attr_accessible :visualization_format | 3 | attr_accessible :visualization_format |
4 | 4 | ||
5 | + extend ActsAsHavingPosts::ClassMethods | ||
5 | acts_as_having_posts | 6 | acts_as_having_posts |
7 | + | ||
6 | include PostsLimit | 8 | include PostsLimit |
7 | 9 | ||
8 | #FIXME This should be used until there is a migration to fix all blogs that | 10 | #FIXME This should be used until there is a migration to fix all blogs that |
app/models/category.rb
@@ -21,6 +21,7 @@ class Category < ApplicationRecord | @@ -21,6 +21,7 @@ class Category < ApplicationRecord | ||
21 | 21 | ||
22 | scope :on_level, -> parent { where :parent_id => parent } | 22 | scope :on_level, -> parent { where :parent_id => parent } |
23 | 23 | ||
24 | + extend ActsAsFilesystem::ActsMethods | ||
24 | acts_as_filesystem | 25 | acts_as_filesystem |
25 | 26 | ||
26 | has_many :article_categorizations | 27 | has_many :article_categorizations |
@@ -35,6 +36,7 @@ class Category < ApplicationRecord | @@ -35,6 +36,7 @@ class Category < ApplicationRecord | ||
35 | has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' | 36 | has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' |
36 | has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community' | 37 | has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community' |
37 | 38 | ||
39 | + extend ActsAsHavingImage::ClassMethods | ||
38 | acts_as_having_image | 40 | acts_as_having_image |
39 | 41 | ||
40 | before_save :normalize_display_color | 42 | before_save :normalize_display_color |
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +class Circle < ApplicationRecord | ||
2 | + has_many :profile_followers | ||
3 | + belongs_to :person | ||
4 | + | ||
5 | + attr_accessible :name, :person, :profile_type | ||
6 | + | ||
7 | + validates :name, presence: true | ||
8 | + validates :person_id, presence: true | ||
9 | + validates :profile_type, presence: true | ||
10 | + validates :person_id, :uniqueness => {:scope => :name, :message => "can't add two circles with the same name"} | ||
11 | + | ||
12 | + validate :profile_type_must_be_in_list | ||
13 | + | ||
14 | + scope :by_owner, -> person{ | ||
15 | + where(:person => person) | ||
16 | + } | ||
17 | + | ||
18 | + scope :with_name, -> name{ | ||
19 | + where(:name => name) | ||
20 | + } | ||
21 | + | ||
22 | + def self.profile_types | ||
23 | + { | ||
24 | + _("Person") => Person.name, | ||
25 | + _("Community") => Community.name, | ||
26 | + _("Enterprise") => Enterprise.name | ||
27 | + } | ||
28 | + end | ||
29 | + | ||
30 | + def profile_type_must_be_in_list | ||
31 | + valid_profile_types = Circle.profile_types.values | ||
32 | + unless self.profile_type.in? valid_profile_types | ||
33 | + self.errors.add(:profile_type, "invalid profile type") | ||
34 | + end | ||
35 | + end | ||
36 | + | ||
37 | +end |
app/models/comment.rb
@@ -38,6 +38,7 @@ class Comment < ApplicationRecord | @@ -38,6 +38,7 @@ class Comment < ApplicationRecord | ||
38 | 38 | ||
39 | validate :article_archived? | 39 | validate :article_archived? |
40 | 40 | ||
41 | + extend ActsAsHavingSettings::ClassMethods | ||
41 | acts_as_having_settings | 42 | acts_as_having_settings |
42 | 43 | ||
43 | xss_terminate :only => [ :body, :title, :name ], :on => 'validation' | 44 | xss_terminate :only => [ :body, :title, :name ], :on => 'validation' |
@@ -0,0 +1,265 @@ | @@ -0,0 +1,265 @@ | ||
1 | +module ActsAsFilesystem | ||
2 | + | ||
3 | + module ActsMethods | ||
4 | + | ||
5 | + # Declares the ActiveRecord model to acts like a filesystem: objects are | ||
6 | + # arranged in a tree (liks acts_as_tree), and . The underlying table must | ||
7 | + # have the following fields: | ||
8 | + # | ||
9 | + # * name (+:string+) - the title of the object | ||
10 | + # * slug (+:string+)- the title turned in a URL-friendly string (downcased, | ||
11 | + # non-ascii chars transliterated into ascii, all sequences of | ||
12 | + # non-alphanumericd characters changed into dashed) | ||
13 | + # * path (+:text+)- stores the full path of the object (the full path of | ||
14 | + # the parent, a "/" and the slug of the object) | ||
15 | + # * children_count - a cache of the number of children elements. | ||
16 | + def acts_as_filesystem | ||
17 | + # a filesystem is a tree | ||
18 | + acts_as_tree :counter_cache => :children_count | ||
19 | + | ||
20 | + extend ClassMethods | ||
21 | + include InstanceMethods | ||
22 | + if self.has_path? | ||
23 | + after_update :update_children_path | ||
24 | + before_create :set_path | ||
25 | + include InstanceMethods::PathMethods | ||
26 | + end | ||
27 | + | ||
28 | + before_save :set_ancestry | ||
29 | + end | ||
30 | + | ||
31 | + end | ||
32 | + | ||
33 | + module ClassMethods | ||
34 | + | ||
35 | + def build_ancestry(parent_id = nil, ancestry = '') | ||
36 | + ActiveRecord::Base.transaction do | ||
37 | + self.base_class.where(parent_id: parent_id).each do |node| | ||
38 | + node.update_column :ancestry, ancestry | ||
39 | + | ||
40 | + build_ancestry node.id, (ancestry.empty? ? "#{node.formatted_ancestry_id}" : | ||
41 | + "#{ancestry}#{node.ancestry_sep}#{node.formatted_ancestry_id}") | ||
42 | + end | ||
43 | + end | ||
44 | + | ||
45 | + #raise "Couldn't reach and set ancestry on every record" if self.base_class.where('ancestry is null').count != 0 | ||
46 | + end | ||
47 | + | ||
48 | + def has_path? | ||
49 | + (['name', 'slug', 'path'] - self.column_names).blank? | ||
50 | + end | ||
51 | + | ||
52 | + end | ||
53 | + | ||
54 | + module InstanceMethods | ||
55 | + | ||
56 | + def ancestry_column | ||
57 | + 'ancestry' | ||
58 | + end | ||
59 | + def ancestry_sep | ||
60 | + '.' | ||
61 | + end | ||
62 | + def has_ancestry? | ||
63 | + self.class.column_names.include? self.ancestry_column | ||
64 | + end | ||
65 | + | ||
66 | + def formatted_ancestry_id | ||
67 | + "%010d" % self.id if self.id | ||
68 | + end | ||
69 | + | ||
70 | + def ancestry | ||
71 | + self[ancestry_column] | ||
72 | + end | ||
73 | + def ancestor_ids | ||
74 | + return nil if !has_ancestry? or ancestry.nil? | ||
75 | + @ancestor_ids ||= ancestry.split(ancestry_sep).map{ |id| id.to_i } | ||
76 | + end | ||
77 | + | ||
78 | + def ancestry=(value) | ||
79 | + self[ancestry_column] = value | ||
80 | + end | ||
81 | + def set_ancestry | ||
82 | + return unless self.has_ancestry? | ||
83 | + if self.ancestry.nil? or (new_record? or parent_id_changed?) or recalculate_path | ||
84 | + self.ancestry = self.hierarchy(true)[0...-1].map{ |p| p.formatted_ancestry_id }.join(ancestry_sep) | ||
85 | + end | ||
86 | + end | ||
87 | + | ||
88 | + def descendents_options | ||
89 | + ["#{self.ancestry_column} LIKE ?", "%#{self.formatted_ancestry_id}%"] | ||
90 | + end | ||
91 | + def descendents | ||
92 | + self.class.where descendents_options | ||
93 | + end | ||
94 | + | ||
95 | + # calculates the level of the record in the records hierarchy. Top-level | ||
96 | + # records have level 0; the children of the top-level records have | ||
97 | + # level 1; the children of records with level 1 have level 2, and so on. | ||
98 | + # | ||
99 | + # A level 0 | ||
100 | + # / \ | ||
101 | + # B C level 1 | ||
102 | + # / \ / \ | ||
103 | + # E F G H level 2 | ||
104 | + # ... | ||
105 | + def level | ||
106 | + self.hierarchy.size - 1 | ||
107 | + end | ||
108 | + | ||
109 | + # Is this record a top-level record? | ||
110 | + def top_level? | ||
111 | + self.parent.nil? | ||
112 | + end | ||
113 | + | ||
114 | + # Is this record a leaf in the hierarchy tree of records? | ||
115 | + # | ||
116 | + # Being a leaf means that this record has no subrecord. | ||
117 | + def leaf? | ||
118 | + self.children.empty? | ||
119 | + end | ||
120 | + | ||
121 | + def top_ancestor | ||
122 | + if has_ancestry? and !ancestry.blank? | ||
123 | + self.class.base_class.find_by id: self.top_ancestor_id | ||
124 | + else | ||
125 | + self.hierarchy.first | ||
126 | + end | ||
127 | + end | ||
128 | + def top_ancestor_id | ||
129 | + if has_ancestry? and !ancestry.nil? | ||
130 | + self.ancestor_ids.first | ||
131 | + else | ||
132 | + self.hierarchy.first.id | ||
133 | + end | ||
134 | + end | ||
135 | + | ||
136 | + # returns the full hierarchy from the top-level item to this one. For | ||
137 | + # example, if item1 has a children item2 and item2 has a children item3, | ||
138 | + # then item3's hierarchy would be [item1, item2, item3]. | ||
139 | + # | ||
140 | + # If +reload+ is passed as +true+, then the hierarchy is reload (usefull | ||
141 | + # when the ActiveRecord object was modified in some way, or just after | ||
142 | + # changing parent) | ||
143 | + def hierarchy(reload = false) | ||
144 | + @hierarchy = nil if reload or recalculate_path | ||
145 | + | ||
146 | + if @hierarchy.nil? | ||
147 | + @hierarchy = [] | ||
148 | + | ||
149 | + if !reload and !recalculate_path and ancestor_ids | ||
150 | + objects = self.class.base_class.where(id: ancestor_ids) | ||
151 | + ancestor_ids.each{ |id| @hierarchy << objects.find{ |t| t.id == id } } | ||
152 | + @hierarchy << self | ||
153 | + else | ||
154 | + item = self | ||
155 | + while item | ||
156 | + @hierarchy.unshift(item) | ||
157 | + item = item.parent | ||
158 | + end | ||
159 | + end | ||
160 | + end | ||
161 | + | ||
162 | + @hierarchy | ||
163 | + end | ||
164 | + | ||
165 | + def map_traversal(&block) | ||
166 | + result = [] | ||
167 | + current_level = [self] | ||
168 | + | ||
169 | + while !current_level.empty? | ||
170 | + result += current_level | ||
171 | + ids = current_level.select {|item| item.children_count > 0}.map(&:id) | ||
172 | + break if ids.empty? | ||
173 | + current_level = self.class.base_class.where(parent_id: ids) | ||
174 | + end | ||
175 | + block ||= (lambda { |x| x }) | ||
176 | + result.map(&block) | ||
177 | + end | ||
178 | + | ||
179 | + def all_children | ||
180 | + res = map_traversal | ||
181 | + res.shift | ||
182 | + res | ||
183 | + end | ||
184 | + | ||
185 | + ##### | ||
186 | + # Path methods | ||
187 | + # These methods are used when _path_, _name_ and _slug_ attributes exist | ||
188 | + # and should be calculated based on the tree | ||
189 | + ##### | ||
190 | + module PathMethods | ||
191 | + # used to know when to trigger batch renaming | ||
192 | + attr_accessor :recalculate_path | ||
193 | + | ||
194 | + # calculates the full path to this record using parent's path. | ||
195 | + def calculate_path | ||
196 | + self.hierarchy.map{ |obj| obj.slug }.join('/') | ||
197 | + end | ||
198 | + def set_path | ||
199 | + if self.path == self.slug && !self.top_level? | ||
200 | + self.path = self.calculate_path | ||
201 | + end | ||
202 | + end | ||
203 | + def explode_path | ||
204 | + path.split(/\//) | ||
205 | + end | ||
206 | + | ||
207 | + def update_children_path | ||
208 | + if self.recalculate_path | ||
209 | + self.children.each do |child| | ||
210 | + child.path = child.calculate_path | ||
211 | + child.recalculate_path = true | ||
212 | + child.save! | ||
213 | + end | ||
214 | + end | ||
215 | + self.recalculate_path = false | ||
216 | + end | ||
217 | + | ||
218 | + # calculates the full name of a record by accessing the name of all its | ||
219 | + # ancestors. | ||
220 | + # | ||
221 | + # If you have this record hierarchy: | ||
222 | + # Record "A" | ||
223 | + # Record "B" | ||
224 | + # Record "C" | ||
225 | + # | ||
226 | + # Then Record "C" will have "A/B/C" as its full name. | ||
227 | + def full_name(sep = '/') | ||
228 | + self.hierarchy.map {|item| item.name || '?' }.join(sep) | ||
229 | + end | ||
230 | + | ||
231 | + # gets the name without leading parents. Useful when dividing records | ||
232 | + # in top-level groups and full names must not include the top-level | ||
233 | + # record which is already a emphasized label | ||
234 | + def full_name_without_leading(count, sep = '/') | ||
235 | + parts = self.full_name(sep).split(sep) | ||
236 | + count.times { parts.shift } | ||
237 | + parts.join(sep) | ||
238 | + end | ||
239 | + | ||
240 | + def set_name(value) | ||
241 | + if self.name != value | ||
242 | + self.recalculate_path = true | ||
243 | + end | ||
244 | + self[:name] = value | ||
245 | + end | ||
246 | + | ||
247 | + # sets the name of the record. Also sets #slug accordingly. | ||
248 | + def name=(value) | ||
249 | + self.set_name(value) | ||
250 | + unless self.name.blank? | ||
251 | + self.slug = self.name.to_slug | ||
252 | + end | ||
253 | + end | ||
254 | + | ||
255 | + # sets the slug of the record. Also sets the path with the new slug value. | ||
256 | + def slug=(value) | ||
257 | + self[:slug] = value | ||
258 | + unless self.slug.blank? | ||
259 | + self.path = self.calculate_path | ||
260 | + end | ||
261 | + end | ||
262 | + end | ||
263 | + end | ||
264 | +end | ||
265 | + |
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +module ActsAsHavingBoxes | ||
2 | + | ||
3 | + module ClassMethods | ||
4 | + def acts_as_having_boxes | ||
5 | + has_many :boxes, -> { order :position }, as: :owner, dependent: :destroy | ||
6 | + self.send(:include, ActsAsHavingBoxes) | ||
7 | + end | ||
8 | + end | ||
9 | + | ||
10 | + module BlockArray | ||
11 | + def find(id) | ||
12 | + select { |item| item.id == id.to_i }.first | ||
13 | + end | ||
14 | + end | ||
15 | + | ||
16 | + def blocks(reload = false) | ||
17 | + if (reload) | ||
18 | + @blocks = nil | ||
19 | + end | ||
20 | + if @blocks.nil? | ||
21 | + @blocks = boxes.includes(:blocks).inject([]) do |acc,obj| | ||
22 | + acc.concat(obj.blocks) | ||
23 | + end | ||
24 | + @blocks.send(:extend, BlockArray) | ||
25 | + end | ||
26 | + @blocks | ||
27 | + end | ||
28 | + | ||
29 | + # returns 3 unless the class table has a boxes_limit column. In that case | ||
30 | + # return the value of the column. | ||
31 | + def boxes_limit layout_template = nil | ||
32 | + layout_template ||= self.layout_template | ||
33 | + @boxes_limit ||= LayoutTemplate.find(layout_template).number_of_boxes || 3 | ||
34 | + end | ||
35 | + | ||
36 | +end | ||
37 | + |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +module ActsAsHavingImage | ||
2 | + | ||
3 | + module ClassMethods | ||
4 | + def acts_as_having_image | ||
5 | + belongs_to :image, dependent: :destroy | ||
6 | + scope :with_image, -> { where "#{table_name}.image_id IS NOT NULL" } | ||
7 | + scope :without_image, -> { where "#{table_name}.image_id IS NULL" } | ||
8 | + attr_accessible :image_builder | ||
9 | + include ActsAsHavingImage | ||
10 | + end | ||
11 | + end | ||
12 | + | ||
13 | + def image_builder=(img) | ||
14 | + if image && image.id == img[:id] | ||
15 | + image.attributes = img | ||
16 | + else | ||
17 | + build_image(img) | ||
18 | + end unless img[:uploaded_data].blank? | ||
19 | + if img[:remove_image] == 'true' | ||
20 | + self.image_id = nil | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | +end | ||
25 | + |
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +module ActsAsHavingPosts | ||
2 | + | ||
3 | + module ClassMethods | ||
4 | + def acts_as_having_posts(scope = nil) | ||
5 | + has_many :posts, -> { | ||
6 | + s = order('published_at DESC, id DESC').where('articles.type != ?', 'RssFeed') | ||
7 | + s = s.instance_exec(&scope) if scope | ||
8 | + s | ||
9 | + }, class_name: 'Article', foreign_key: 'parent_id', source: :children | ||
10 | + | ||
11 | + attr_accessor :feed_attrs | ||
12 | + | ||
13 | + after_create do |blog| | ||
14 | + blog.children << RssFeed.new(:name => 'feed', :profile => blog.profile) | ||
15 | + blog.feed = blog.feed_attrs | ||
16 | + end | ||
17 | + | ||
18 | + settings_items :posts_per_page, :type => :integer, :default => 5 | ||
19 | + | ||
20 | + self.send(:include, ActsAsHavingPosts) | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + def has_posts? | ||
25 | + true | ||
26 | + end | ||
27 | + | ||
28 | + def feed | ||
29 | + children.where(:type => 'RssFeed').first | ||
30 | + end | ||
31 | + | ||
32 | + def feed=(attrs) | ||
33 | + if attrs | ||
34 | + if self.feed | ||
35 | + self.feed.update(attrs) | ||
36 | + else | ||
37 | + self.feed_attrs = attrs | ||
38 | + end | ||
39 | + end | ||
40 | + self.feed | ||
41 | + end | ||
42 | + | ||
43 | + def name=(value) | ||
44 | + self.set_name(value) | ||
45 | + self.slug = self.slug.blank? ? self.name.to_slug : self.slug.to_slug | ||
46 | + end | ||
47 | + | ||
48 | +end | ||
49 | + |
@@ -0,0 +1,89 @@ | @@ -0,0 +1,89 @@ | ||
1 | +# declare missing types | ||
2 | +module ActiveRecord | ||
3 | + module Type | ||
4 | + class Symbol < Value | ||
5 | + def cast_value value | ||
6 | + value.to_sym | ||
7 | + end | ||
8 | + end | ||
9 | + class Array < Value | ||
10 | + def cast_value value | ||
11 | + ::Array.wrap(value) | ||
12 | + end | ||
13 | + end | ||
14 | + class Hash < Value | ||
15 | + def cast_value value | ||
16 | + h = ::Hash[value] | ||
17 | + h.symbolize_keys! | ||
18 | + h | ||
19 | + end | ||
20 | + end | ||
21 | + end | ||
22 | +end | ||
23 | + | ||
24 | +module ActsAsHavingSettings | ||
25 | + | ||
26 | + def self.type_cast value, type | ||
27 | + # do not cast nil | ||
28 | + return value if value.nil? | ||
29 | + type.send :cast_value, value | ||
30 | + end | ||
31 | + | ||
32 | + module ClassMethods | ||
33 | + | ||
34 | + def acts_as_having_settings(*args) | ||
35 | + options = args.last.is_a?(Hash) ? args.pop : {} | ||
36 | + field = (options[:field] || :settings).to_sym | ||
37 | + | ||
38 | + serialize field, Hash | ||
39 | + class_attribute :settings_field | ||
40 | + self.settings_field = field | ||
41 | + | ||
42 | + class_eval do | ||
43 | + def settings_field | ||
44 | + self[self.class.settings_field] ||= Hash.new | ||
45 | + end | ||
46 | + | ||
47 | + def setting_changed? setting_field | ||
48 | + setting_field = setting_field.to_sym | ||
49 | + changed_settings = self.changes[self.class.settings_field] | ||
50 | + return false if changed_settings.nil? | ||
51 | + | ||
52 | + old_setting_value = changed_settings.first.nil? ? nil : changed_settings.first[setting_field] | ||
53 | + new_setting_value = changed_settings.last[setting_field] | ||
54 | + old_setting_value != new_setting_value | ||
55 | + end | ||
56 | + end | ||
57 | + | ||
58 | + settings_items *args | ||
59 | + end | ||
60 | + | ||
61 | + def settings_items *names | ||
62 | + | ||
63 | + options = names.extract_options! | ||
64 | + default = options[:default] | ||
65 | + type = options[:type] | ||
66 | + type = if type.present? then ActiveRecord::Type.const_get(type.to_s.camelize.to_sym).new else nil end | ||
67 | + | ||
68 | + names.each do |setting| | ||
69 | + # symbolize key | ||
70 | + setting = setting.to_sym | ||
71 | + | ||
72 | + define_method setting do | ||
73 | + h = send self.class.settings_field | ||
74 | + val = h[setting] | ||
75 | + # translate default value if it is used | ||
76 | + if not val.nil? then val elsif default.is_a? String then gettext default else default end | ||
77 | + end | ||
78 | + | ||
79 | + define_method "#{setting}=" do |value| | ||
80 | + h = send self.class.settings_field | ||
81 | + h[setting] = if type then ActsAsHavingSettings.type_cast value, type else value end | ||
82 | + end | ||
83 | + end | ||
84 | + end | ||
85 | + | ||
86 | + end | ||
87 | + | ||
88 | +end | ||
89 | + |
@@ -0,0 +1,57 @@ | @@ -0,0 +1,57 @@ | ||
1 | +module CodeNumbering | ||
2 | + module ClassMethods | ||
3 | + def code_numbering field, options = {} | ||
4 | + class_attribute :code_numbering_field | ||
5 | + class_attribute :code_numbering_options | ||
6 | + | ||
7 | + self.code_numbering_field = field | ||
8 | + self.code_numbering_options = options | ||
9 | + | ||
10 | + before_create :create_code_numbering | ||
11 | + | ||
12 | + include CodeNumbering::InstanceMethods | ||
13 | + end | ||
14 | + end | ||
15 | + | ||
16 | + module InstanceMethods | ||
17 | + | ||
18 | + def code | ||
19 | + self.attributes[self.code_numbering_field.to_s] | ||
20 | + end | ||
21 | + | ||
22 | + def code_scope | ||
23 | + scope = self.code_numbering_options[:scope] | ||
24 | + case scope | ||
25 | + when Symbol | ||
26 | + self.send scope | ||
27 | + when Proc | ||
28 | + instance_exec &scope | ||
29 | + else | ||
30 | + self.class | ||
31 | + end | ||
32 | + end | ||
33 | + | ||
34 | + def code_maximum | ||
35 | + self.code_scope.maximum(self.code_numbering_field) || 0 | ||
36 | + end | ||
37 | + | ||
38 | + def create_code_numbering | ||
39 | + max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] | ||
40 | + max = self.code_maximum | ||
41 | + self.send "#{self.code_numbering_field}=", max+1 | ||
42 | + end | ||
43 | + | ||
44 | + def reset_scope_code_numbering | ||
45 | + max = self.code_numbering_options[:start].to_i - 1 if self.code_numbering_options[:start] | ||
46 | + max ||= 1 | ||
47 | + | ||
48 | + self.code_scope.order(:created_at).each do |record| | ||
49 | + record.update_column self.code_numbering_field, max | ||
50 | + max += 1 | ||
51 | + end | ||
52 | + self.reload | ||
53 | + end | ||
54 | + | ||
55 | + end | ||
56 | +end | ||
57 | + |
@@ -0,0 +1,124 @@ | @@ -0,0 +1,124 @@ | ||
1 | +module Customizable | ||
2 | + | ||
3 | + def self.included(base) | ||
4 | + base.attr_accessible :custom_values | ||
5 | + base.extend ClassMethods | ||
6 | + end | ||
7 | + | ||
8 | + module ClassMethods | ||
9 | + def acts_as_customizable(options = {}) | ||
10 | + attr_accessor :custom_values | ||
11 | + has_many :custom_field_values, :dependent => :delete_all, :as => :customized | ||
12 | + send :include, Customizable::InstanceMethods | ||
13 | + after_save :save_custom_values | ||
14 | + validate :valid_custom_values? | ||
15 | + end | ||
16 | + | ||
17 | + def active_custom_fields environment | ||
18 | + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.active} | ||
19 | + end | ||
20 | + | ||
21 | + def required_custom_fields environment | ||
22 | + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.required} | ||
23 | + end | ||
24 | + | ||
25 | + def signup_custom_fields environment | ||
26 | + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type) && cf.signup} | ||
27 | + end | ||
28 | + | ||
29 | + def custom_fields environment | ||
30 | + environment.custom_fields.select{|cf| customized_ancestors_list.include?(cf.customized_type)} | ||
31 | + end | ||
32 | + | ||
33 | + def customized_ancestors_list | ||
34 | + current=self | ||
35 | + result=[] | ||
36 | + while current.instance_methods.include? :custom_value do | ||
37 | + result << current.name | ||
38 | + current=current.superclass | ||
39 | + end | ||
40 | + result | ||
41 | + end | ||
42 | + | ||
43 | + end | ||
44 | + | ||
45 | + module InstanceMethods | ||
46 | + | ||
47 | + def valid_custom_values? | ||
48 | + is_valid = true | ||
49 | + parse_custom_values.each do |cv| | ||
50 | + unless cv.valid? | ||
51 | + name = cv.custom_field.name | ||
52 | + errors.add(name, cv.errors.messages[name.to_sym].first) | ||
53 | + is_valid = false | ||
54 | + end | ||
55 | + end | ||
56 | + is_valid | ||
57 | + end | ||
58 | + | ||
59 | + def customized_class | ||
60 | + current=self.class | ||
61 | + while current.instance_methods.include? :custom_fields do | ||
62 | + result=current | ||
63 | + current=current.superclass | ||
64 | + end | ||
65 | + result.name | ||
66 | + end | ||
67 | + | ||
68 | + def is_public(field_name) | ||
69 | + cv = self.custom_field_values.detect{|cv| cv.custom_field.name==field_name} | ||
70 | + cv.nil? ? false : cv.public | ||
71 | + end | ||
72 | + | ||
73 | + def public_values | ||
74 | + self.custom_field_values.select{|cv| cv.public} | ||
75 | + end | ||
76 | + | ||
77 | + def custom_value(field_name) | ||
78 | + cv = self.custom_field_values.detect{|cv| cv.custom_field.name==field_name} | ||
79 | + cv.nil? ? default_value_for(field_name) : cv.value | ||
80 | + end | ||
81 | + | ||
82 | + def default_value_for(field_name) | ||
83 | + field=self.class.custom_fields(environment).detect {|c| c.name == field_name} | ||
84 | + field.nil? ? nil : field.default_value | ||
85 | + end | ||
86 | + | ||
87 | + def parse_custom_values | ||
88 | + return_list = [] | ||
89 | + return return_list if custom_values.blank? | ||
90 | + custom_values.each_pair do |key, value| | ||
91 | + custom_field = environment.custom_fields.detect{|cf|cf.name==key} | ||
92 | + next if custom_field.blank? | ||
93 | + custom_field_value = self.custom_field_values(true).detect{|cv| cv.custom_field.name==key} | ||
94 | + | ||
95 | + if custom_field_value.nil? | ||
96 | + custom_field_value = CustomFieldValue.new | ||
97 | + custom_field_value.custom_field = custom_field | ||
98 | + custom_field_value.customized = self | ||
99 | + end | ||
100 | + | ||
101 | + if value.is_a?(Hash) | ||
102 | + custom_field_value.value = value['value'].to_s | ||
103 | + if value.has_key?('public') | ||
104 | + is_public = value['public']=="true" || value['public']==true | ||
105 | + custom_field_value.public = is_public | ||
106 | + else | ||
107 | + custom_field_value.public = false | ||
108 | + end | ||
109 | + else | ||
110 | + custom_field_value.value = value.to_s | ||
111 | + custom_field_value.public = false | ||
112 | + end | ||
113 | + return_list << custom_field_value | ||
114 | + end | ||
115 | + return_list | ||
116 | + end | ||
117 | + | ||
118 | + def save_custom_values | ||
119 | + parse_custom_values.each(&:save) | ||
120 | + end | ||
121 | + | ||
122 | + end | ||
123 | +end | ||
124 | + |
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +module DelayedAttachmentFu | ||
2 | + | ||
3 | + module ClassMethods | ||
4 | + def delay_attachment_fu_thumbnails | ||
5 | + include DelayedAttachmentFu::InstanceMethods | ||
6 | + after_create do |file| | ||
7 | + if file.thumbnailable? | ||
8 | + Delayed::Job.enqueue CreateThumbnailsJob.new(file.class.name, file.id) | ||
9 | + end | ||
10 | + end | ||
11 | + end | ||
12 | + end | ||
13 | + | ||
14 | + module InstanceMethods | ||
15 | + # skip processing with RMagick | ||
16 | + def process_attachment | ||
17 | + end | ||
18 | + | ||
19 | + def after_process_attachment | ||
20 | + save_to_storage | ||
21 | + @temp_paths.clear | ||
22 | + @saved_attachment = nil | ||
23 | + run_callbacks :after_attachment_saved | ||
24 | + end | ||
25 | + | ||
26 | + def create_thumbnails | ||
27 | + if thumbnailable? | ||
28 | + self.class.with_image(full_filename) do |img| | ||
29 | + self.width = img.columns | ||
30 | + self.height = img.rows | ||
31 | + self.save! | ||
32 | + end | ||
33 | + self.class.attachment_options[:thumbnails].each do |suffix, size| | ||
34 | + self.create_or_update_thumbnail(self.full_filename, suffix, size) | ||
35 | + end | ||
36 | + self.thumbnails_processed = true | ||
37 | + self.save! | ||
38 | + end | ||
39 | + end | ||
40 | + | ||
41 | + def public_filename(size=nil) | ||
42 | + force, size = true, nil if size == :uploaded | ||
43 | + if !self.thumbnailable? || self.thumbnails_processed || force | ||
44 | + super size | ||
45 | + else | ||
46 | + size ||= :thumb | ||
47 | + '/images/icons-app/image-loading-%s.png' % size | ||
48 | + end | ||
49 | + end | ||
50 | + | ||
51 | + | ||
52 | + end | ||
53 | +end | ||
54 | + | ||
55 | + |
app/models/concerns/set_profile_region_from_city_state.rb
0 → 100644
@@ -0,0 +1,44 @@ | @@ -0,0 +1,44 @@ | ||
1 | +module SetProfileRegionFromCityState | ||
2 | + | ||
3 | + module ClassMethods | ||
4 | + def set_profile_region_from_city_state | ||
5 | + before_save :region_from_city_and_state | ||
6 | + | ||
7 | + include InstanceMethods | ||
8 | + alias_method_chain :city=, :region | ||
9 | + alias_method_chain :state=, :region | ||
10 | + end | ||
11 | + end | ||
12 | + | ||
13 | + module InstanceMethods | ||
14 | + include Noosfero::Plugin::HotSpot | ||
15 | + | ||
16 | + def city_with_region=(value) | ||
17 | + self.city_without_region = value | ||
18 | + @change_region = true | ||
19 | + end | ||
20 | + | ||
21 | + def state_with_region=(value) | ||
22 | + self.state_without_region = value | ||
23 | + @change_region = true | ||
24 | + end | ||
25 | + | ||
26 | + def region_from_city_and_state | ||
27 | + if @change_region | ||
28 | + self.region = nil | ||
29 | + state = search_region(State, self.state) | ||
30 | + self.region = search_region(City.where(:parent_id => state.id), self.city) if state | ||
31 | + end | ||
32 | + end | ||
33 | + | ||
34 | + private | ||
35 | + | ||
36 | + def search_region(scope, query) | ||
37 | + return nil if !query | ||
38 | + query = query.downcase.strip | ||
39 | + scope.where(['lower(name)=? OR lower(abbreviation)=? OR lower(acronym)=?', query, query, query]).first | ||
40 | + end | ||
41 | + | ||
42 | + end | ||
43 | + | ||
44 | +end |
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +module WhiteListFilter | ||
2 | + | ||
3 | + def check_iframe_on_content(content, trusted_sites) | ||
4 | + if content.blank? || !content.include?('iframe') | ||
5 | + return content | ||
6 | + end | ||
7 | + content.gsub!(/<iframe[^>]*>\s*<\/iframe>/i) do |iframe| | ||
8 | + result = '' | ||
9 | + unless iframe =~ /src=['"].*src=['"]/ | ||
10 | + trusted_sites.each do |trusted_site| | ||
11 | + re_dom = trusted_site.gsub('.', '\.') | ||
12 | + if iframe =~ /src=["'](https?:)?\/\/(www\.)?#{re_dom}\// | ||
13 | + result = iframe | ||
14 | + end | ||
15 | + end | ||
16 | + end | ||
17 | + result | ||
18 | + end | ||
19 | + content | ||
20 | + end | ||
21 | + | ||
22 | + module ClassMethods | ||
23 | + def filter_iframes(*opts) | ||
24 | + options = opts.last.is_a?(Hash) && opts.pop || {} | ||
25 | + white_list_method = options[:whitelist] || :iframe_whitelist | ||
26 | + opts.each do |field| | ||
27 | + before_validation do |obj| | ||
28 | + obj.check_iframe_on_content(obj.send(field), obj.send(white_list_method)) | ||
29 | + end | ||
30 | + end | ||
31 | + end | ||
32 | + end | ||
33 | + | ||
34 | + def self.included(c) | ||
35 | + c.send(:extend, WhiteListFilter::ClassMethods) | ||
36 | + end | ||
37 | +end |
app/models/create_community.rb
@@ -12,6 +12,7 @@ class CreateCommunity < Task | @@ -12,6 +12,7 @@ class CreateCommunity < Task | ||
12 | attr_accessible :environment, :requestor, :target | 12 | attr_accessible :environment, :requestor, :target |
13 | attr_accessible :reject_explanation, :template_id | 13 | attr_accessible :reject_explanation, :template_id |
14 | 14 | ||
15 | + extend ActsAsHavingImage::ClassMethods | ||
15 | acts_as_having_image | 16 | acts_as_having_image |
16 | 17 | ||
17 | DATA_FIELDS = Community.fields + ['name', 'closed', 'description'] | 18 | DATA_FIELDS = Community.fields + ['name', 'closed', 'description'] |
app/models/enterprise.rb
app/models/environment.rb
@@ -200,6 +200,7 @@ class Environment < ApplicationRecord | @@ -200,6 +200,7 @@ class Environment < ApplicationRecord | ||
200 | # Relationships and applied behaviour | 200 | # Relationships and applied behaviour |
201 | # ################################################# | 201 | # ################################################# |
202 | 202 | ||
203 | + extend ActsAsHavingBoxes::ClassMethods | ||
203 | acts_as_having_boxes | 204 | acts_as_having_boxes |
204 | 205 | ||
205 | after_create do |env| | 206 | after_create do |env| |
@@ -251,7 +252,8 @@ class Environment < ApplicationRecord | @@ -251,7 +252,8 @@ class Environment < ApplicationRecord | ||
251 | # ################################################# | 252 | # ################################################# |
252 | 253 | ||
253 | # store the Environment settings as YAML-serialized Hash. | 254 | # store the Environment settings as YAML-serialized Hash. |
254 | - acts_as_having_settings :field => :settings | 255 | + extend ActsAsHavingSettings::ClassMethods |
256 | + acts_as_having_settings field: :settings | ||
255 | 257 | ||
256 | # introduce and explain to users something about the signup | 258 | # introduce and explain to users something about the signup |
257 | settings_items :signup_intro, :type => String | 259 | settings_items :signup_intro, :type => String |
app/models/event.rb
1 | -require 'noosfero/translatable_content' | ||
2 | require 'builder' | 1 | require 'builder' |
3 | 2 | ||
4 | class Event < Article | 3 | class Event < Article |
@@ -138,7 +137,7 @@ class Event < Article | @@ -138,7 +137,7 @@ class Event < Article | ||
138 | false | 137 | false |
139 | end | 138 | end |
140 | 139 | ||
141 | - include Noosfero::TranslatableContent | 140 | + include TranslatableContent |
142 | include MaybeAddHttp | 141 | include MaybeAddHttp |
143 | 142 | ||
144 | end | 143 | end |
app/models/favorite_enterprise_person.rb
@@ -7,6 +7,10 @@ class FavoriteEnterprisePerson < ApplicationRecord | @@ -7,6 +7,10 @@ class FavoriteEnterprisePerson < ApplicationRecord | ||
7 | belongs_to :enterprise | 7 | belongs_to :enterprise |
8 | belongs_to :person | 8 | belongs_to :person |
9 | 9 | ||
10 | + after_create do |favorite| | ||
11 | + favorite.person.follow(favorite.enterprise, Circle.find_or_create_by(:person => favorite.person, :name =>_('favorites'), :profile_type => 'Enterprise')) | ||
12 | + end | ||
13 | + | ||
10 | protected | 14 | protected |
11 | 15 | ||
12 | def is_trackable? | 16 | def is_trackable? |
app/models/folder.rb
@@ -10,7 +10,8 @@ class Folder < Article | @@ -10,7 +10,8 @@ class Folder < Article | ||
10 | errors.add(:parent, "A folder should not belong to a blog.") if parent && parent.blog? | 10 | errors.add(:parent, "A folder should not belong to a blog.") if parent && parent.blog? |
11 | end | 11 | end |
12 | 12 | ||
13 | - acts_as_having_settings :field => :setting | 13 | + extend ActsAsHavingSettings::ClassMethods |
14 | + acts_as_having_settings field: :setting | ||
14 | 15 | ||
15 | xss_terminate :only => [ :name, :body ], :with => 'white_list', :on => 'validation' | 16 | xss_terminate :only => [ :name, :body ], :with => 'white_list', :on => 'validation' |
16 | 17 |
app/models/forum.rb
1 | class Forum < Folder | 1 | class Forum < Folder |
2 | 2 | ||
3 | + extend ActsAsHavingPosts::ClassMethods | ||
3 | acts_as_having_posts -> { reorder 'updated_at DESC' } | 4 | acts_as_having_posts -> { reorder 'updated_at DESC' } |
5 | + | ||
4 | include PostsLimit | 6 | include PostsLimit |
5 | 7 | ||
6 | attr_accessible :has_terms_of_use, :terms_of_use, :topic_creation | 8 | attr_accessible :has_terms_of_use, :terms_of_use, :topic_creation |
app/models/friendship.rb
@@ -9,11 +9,22 @@ class Friendship < ApplicationRecord | @@ -9,11 +9,22 @@ class Friendship < ApplicationRecord | ||
9 | after_create do |friendship| | 9 | after_create do |friendship| |
10 | Friendship.update_cache_counter(:friends_count, friendship.person, 1) | 10 | Friendship.update_cache_counter(:friends_count, friendship.person, 1) |
11 | Friendship.update_cache_counter(:friends_count, friendship.friend, 1) | 11 | Friendship.update_cache_counter(:friends_count, friendship.friend, 1) |
12 | + | ||
13 | + circles = friendship.group.blank? ? ['friendships'] : friendship.group.split(',').map(&:strip) | ||
14 | + circles.each do |circle| | ||
15 | + friendship.person.follow(friendship.friend, Circle.find_or_create_by(:person => friendship.person, :name => circle, :profile_type => 'Person')) | ||
16 | + end | ||
12 | end | 17 | end |
13 | 18 | ||
14 | after_destroy do |friendship| | 19 | after_destroy do |friendship| |
15 | Friendship.update_cache_counter(:friends_count, friendship.person, -1) | 20 | Friendship.update_cache_counter(:friends_count, friendship.person, -1) |
16 | Friendship.update_cache_counter(:friends_count, friendship.friend, -1) | 21 | Friendship.update_cache_counter(:friends_count, friendship.friend, -1) |
22 | + | ||
23 | + groups = friendship.group.blank? ? ['friendships'] : friendship.group.split(',').map(&:strip) | ||
24 | + groups.each do |group| | ||
25 | + circle = Circle.find_by(:person => friendship.person, :name => group ) | ||
26 | + friendship.person.remove_profile_from_circle(friendship.friend, circle) if circle | ||
27 | + end | ||
17 | end | 28 | end |
18 | 29 | ||
19 | def self.remove_friendship(person1, person2) | 30 | def self.remove_friendship(person1, person2) |
app/models/image.rb
@@ -23,6 +23,7 @@ class Image < ApplicationRecord | @@ -23,6 +23,7 @@ class Image < ApplicationRecord | ||
23 | 23 | ||
24 | validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n | 24 | validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of 5.0 MB").fix_i18n |
25 | 25 | ||
26 | + extend DelayedAttachmentFu::ClassMethods | ||
26 | delay_attachment_fu_thumbnails | 27 | delay_attachment_fu_thumbnails |
27 | 28 | ||
28 | postgresql_attachment_fu | 29 | postgresql_attachment_fu |
app/models/person.rb
@@ -8,7 +8,6 @@ class Person < Profile | @@ -8,7 +8,6 @@ class Person < Profile | ||
8 | :display => %w[compact] | 8 | :display => %w[compact] |
9 | } | 9 | } |
10 | 10 | ||
11 | - | ||
12 | def self.type_name | 11 | def self.type_name |
13 | _('Person') | 12 | _('Person') |
14 | end | 13 | end |
@@ -93,6 +92,7 @@ class Person < Profile | @@ -93,6 +92,7 @@ class Person < Profile | ||
93 | has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article | 92 | has_many :following_articles, :class_name => 'Article', :through => :article_followers, :source => :article |
94 | has_many :friendships, :dependent => :destroy | 93 | has_many :friendships, :dependent => :destroy |
95 | has_many :friends, :class_name => 'Person', :through => :friendships | 94 | has_many :friends, :class_name => 'Person', :through => :friendships |
95 | + has_many :circles | ||
96 | 96 | ||
97 | scope :online, -> { | 97 | scope :online, -> { |
98 | joins(:user).where("users.chat_status != '' AND users.chat_status_at >= ?", DateTime.now - User.expires_chat_status_every.minutes) | 98 | joins(:user).where("users.chat_status != '' AND users.chat_status_at >= ?", DateTime.now - User.expires_chat_status_every.minutes) |
@@ -200,6 +200,33 @@ class Person < Profile | @@ -200,6 +200,33 @@ class Person < Profile | ||
200 | end | 200 | end |
201 | end | 201 | end |
202 | 202 | ||
203 | + def follow(profile, circles) | ||
204 | + circles = [circles] unless circles.is_a?(Array) | ||
205 | + circles.each do |new_circle| | ||
206 | + ProfileFollower.create(profile: profile, circle: new_circle) | ||
207 | + end | ||
208 | + end | ||
209 | + | ||
210 | + def update_profile_circles(profile, new_circles) | ||
211 | + profile_circles = ProfileFollower.with_profile(profile).with_follower(self).map(&:circle) | ||
212 | + circles_to_add = new_circles - profile_circles | ||
213 | + circles_to_remove = profile_circles - new_circles | ||
214 | + circles_to_add.each do |new_circle| | ||
215 | + ProfileFollower.create(profile: profile, circle: new_circle) | ||
216 | + end | ||
217 | + | ||
218 | + ProfileFollower.where('circle_id IN (?) AND profile_id = ?', | ||
219 | + circles_to_remove.map(&:id), profile.id).destroy_all | ||
220 | + end | ||
221 | + | ||
222 | + def unfollow(profile) | ||
223 | + ProfileFollower.with_follower(self).with_profile(profile).destroy_all | ||
224 | + end | ||
225 | + | ||
226 | + def remove_profile_from_circle(profile, circle) | ||
227 | + ProfileFollower.with_profile(profile).with_circle(circle).destroy_all | ||
228 | + end | ||
229 | + | ||
203 | def already_request_friendship?(person) | 230 | def already_request_friendship?(person) |
204 | person.tasks.where(requestor_id: self.id, type: 'AddFriend', status: Task::Status::ACTIVE).first | 231 | person.tasks.where(requestor_id: self.id, type: 'AddFriend', status: Task::Status::ACTIVE).first |
205 | end | 232 | end |
@@ -580,9 +607,12 @@ class Person < Profile | @@ -580,9 +607,12 @@ class Person < Profile | ||
580 | person.has_permission?(:manage_friends, self) | 607 | person.has_permission?(:manage_friends, self) |
581 | end | 608 | end |
582 | 609 | ||
583 | - protected | 610 | + def followed_profiles |
611 | + Profile.followed_by self | ||
612 | + end | ||
584 | 613 | ||
585 | - def followed_by?(profile) | ||
586 | - self == profile || self.is_a_friend?(profile) | 614 | + def in_social_circle?(person) |
615 | + self.is_a_friend?(person) || super | ||
587 | end | 616 | end |
617 | + | ||
588 | end | 618 | end |
app/models/profile.rb
@@ -5,7 +5,7 @@ class Profile < ApplicationRecord | @@ -5,7 +5,7 @@ class Profile < ApplicationRecord | ||
5 | 5 | ||
6 | attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, | 6 | attr_accessible :name, :identifier, :public_profile, :nickname, :custom_footer, :custom_header, :address, :zip_code, :contact_phone, :image_builder, :description, :closed, :template_id, :environment, :lat, :lng, :is_template, :fields_privacy, :preferred_domain_id, :category_ids, :country, :city, :state, :national_region_code, :email, :contact_email, :redirect_l10n, :notification_time, |
7 | :redirection_after_login, :custom_url_redirection, | 7 | :redirection_after_login, :custom_url_redirection, |
8 | - :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :profile_admin_mail_notification | 8 | + :email_suggestions, :allow_members_to_invite, :invite_friends_only, :secret, :profile_admin_mail_notification, :allow_followers |
9 | 9 | ||
10 | # use for internationalizable human type names in search facets | 10 | # use for internationalizable human type names in search facets |
11 | # reimplement on subclasses | 11 | # reimplement on subclasses |
@@ -52,6 +52,9 @@ class Profile < ApplicationRecord | @@ -52,6 +52,9 @@ class Profile < ApplicationRecord | ||
52 | def self.organization_custom_roles(env_id, profile_id) | 52 | def self.organization_custom_roles(env_id, profile_id) |
53 | all_roles(env_id).where('profile_id = ?', profile_id) | 53 | all_roles(env_id).where('profile_id = ?', profile_id) |
54 | end | 54 | end |
55 | + def self.organization_roles(env_id, profile_id) | ||
56 | + all_roles(env_id).where("profile_id = ? or key like 'profile_%'", profile_id) | ||
57 | + end | ||
55 | def self.all_roles(env_id) | 58 | def self.all_roles(env_id) |
56 | Role.where(environment_id: env_id) | 59 | Role.where(environment_id: env_id) |
57 | end | 60 | end |
@@ -88,6 +91,8 @@ class Profile < ApplicationRecord | @@ -88,6 +91,8 @@ class Profile < ApplicationRecord | ||
88 | } | 91 | } |
89 | 92 | ||
90 | acts_as_accessible | 93 | acts_as_accessible |
94 | + | ||
95 | + include Customizable | ||
91 | acts_as_customizable | 96 | acts_as_customizable |
92 | 97 | ||
93 | include Noosfero::Plugin::HotSpot | 98 | include Noosfero::Plugin::HotSpot |
@@ -185,6 +190,21 @@ class Profile < ApplicationRecord | @@ -185,6 +190,21 @@ class Profile < ApplicationRecord | ||
185 | Person.members_of(self).by_role(roles) | 190 | Person.members_of(self).by_role(roles) |
186 | end | 191 | end |
187 | 192 | ||
193 | + extend ActsAsHavingSettings::ClassMethods | ||
194 | + acts_as_having_settings field: :data | ||
195 | + | ||
196 | + def settings | ||
197 | + data | ||
198 | + end | ||
199 | + | ||
200 | + settings_items :redirect_l10n, :type => :boolean, :default => false | ||
201 | + settings_items :public_content, :type => :boolean, :default => true | ||
202 | + settings_items :description | ||
203 | + settings_items :fields_privacy, :type => :hash, :default => {} | ||
204 | + settings_items :email_suggestions, :type => :boolean, :default => false | ||
205 | + settings_items :profile_admin_mail_notification, :type => :boolean, :default => true | ||
206 | + | ||
207 | + extend ActsAsHavingBoxes::ClassMethods | ||
188 | acts_as_having_boxes | 208 | acts_as_having_boxes |
189 | 209 | ||
190 | acts_as_taggable | 210 | acts_as_taggable |
@@ -203,6 +223,23 @@ class Profile < ApplicationRecord | @@ -203,6 +223,23 @@ class Profile < ApplicationRecord | ||
203 | scope :more_active, -> { order 'activities_count DESC' } | 223 | scope :more_active, -> { order 'activities_count DESC' } |
204 | scope :more_recent, -> { order "created_at DESC" } | 224 | scope :more_recent, -> { order "created_at DESC" } |
205 | 225 | ||
226 | + scope :followed_by, -> person{ | ||
227 | + distinct.select('profiles.*'). | ||
228 | + joins('left join profiles_circles ON profiles_circles.profile_id = profiles.id'). | ||
229 | + joins('left join circles ON circles.id = profiles_circles.circle_id'). | ||
230 | + where('circles.person_id = ?', person.id) | ||
231 | + } | ||
232 | + | ||
233 | + scope :in_circle, -> circle{ | ||
234 | + distinct.select('profiles.*'). | ||
235 | + joins('left join profiles_circles ON profiles_circles.profile_id = profiles.id'). | ||
236 | + joins('left join circles ON circles.id = profiles_circles.circle_id'). | ||
237 | + where('circles.id = ?', circle.id) | ||
238 | + } | ||
239 | + | ||
240 | + settings_items :allow_followers, :type => :boolean, :default => true | ||
241 | + alias_method :allow_followers?, :allow_followers | ||
242 | + | ||
206 | acts_as_trackable :dependent => :destroy | 243 | acts_as_trackable :dependent => :destroy |
207 | 244 | ||
208 | has_many :profile_activities | 245 | has_many :profile_activities |
@@ -215,6 +252,9 @@ class Profile < ApplicationRecord | @@ -215,6 +252,9 @@ class Profile < ApplicationRecord | ||
215 | 252 | ||
216 | has_many :email_templates, :foreign_key => :owner_id | 253 | has_many :email_templates, :foreign_key => :owner_id |
217 | 254 | ||
255 | + has_many :profile_followers | ||
256 | + has_many :followers, -> { uniq }, :class_name => 'Person', :through => :profile_followers, :source => :person | ||
257 | + | ||
218 | # Although this should be a has_one relation, there are no non-silly names for | 258 | # Although this should be a has_one relation, there are no non-silly names for |
219 | # a foreign key on article to reference the template to which it is | 259 | # a foreign key on article to reference the template to which it is |
220 | # welcome_page... =P | 260 | # welcome_page... =P |
@@ -231,19 +271,6 @@ class Profile < ApplicationRecord | @@ -231,19 +271,6 @@ class Profile < ApplicationRecord | ||
231 | scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap) | 271 | scrap.nil? ? Scrap.all_scraps(self) : Scrap.all_scraps(self).find(scrap) |
232 | end | 272 | end |
233 | 273 | ||
234 | - acts_as_having_settings :field => :data | ||
235 | - | ||
236 | - def settings | ||
237 | - data | ||
238 | - end | ||
239 | - | ||
240 | - settings_items :redirect_l10n, :type => :boolean, :default => false | ||
241 | - settings_items :public_content, :type => :boolean, :default => true | ||
242 | - settings_items :description | ||
243 | - settings_items :fields_privacy, :type => :hash, :default => {} | ||
244 | - settings_items :email_suggestions, :type => :boolean, :default => false | ||
245 | - settings_items :profile_admin_mail_notification, :type => :boolean, :default => true | ||
246 | - | ||
247 | validates_length_of :description, :maximum => 550, :allow_nil => true | 274 | validates_length_of :description, :maximum => 550, :allow_nil => true |
248 | 275 | ||
249 | # Valid identifiers must match this format. | 276 | # Valid identifiers must match this format. |
@@ -285,6 +312,7 @@ class Profile < ApplicationRecord | @@ -285,6 +312,7 @@ class Profile < ApplicationRecord | ||
285 | 312 | ||
286 | has_many :files, :class_name => 'UploadedFile' | 313 | has_many :files, :class_name => 'UploadedFile' |
287 | 314 | ||
315 | + extend ActsAsHavingImage::ClassMethods | ||
288 | acts_as_having_image | 316 | acts_as_having_image |
289 | 317 | ||
290 | has_many :tasks, :dependent => :destroy, :as => 'target' | 318 | has_many :tasks, :dependent => :destroy, :as => 'target' |
@@ -758,12 +786,13 @@ private :generate_url, :url_options | @@ -758,12 +786,13 @@ private :generate_url, :url_options | ||
758 | 786 | ||
759 | # Adds a person as member of this Profile. | 787 | # Adds a person as member of this Profile. |
760 | def add_member(person, attributes={}) | 788 | def add_member(person, attributes={}) |
761 | - if self.has_members? | 789 | + if self.has_members? && !self.secret |
762 | if self.closed? && members.count > 0 | 790 | if self.closed? && members.count > 0 |
763 | AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person) | 791 | AddMember.create!(:person => person, :organization => self) unless self.already_request_membership?(person) |
764 | else | 792 | else |
765 | self.affiliate(person, Profile::Roles.admin(environment.id), attributes) if members.count == 0 | 793 | self.affiliate(person, Profile::Roles.admin(environment.id), attributes) if members.count == 0 |
766 | self.affiliate(person, Profile::Roles.member(environment.id), attributes) | 794 | self.affiliate(person, Profile::Roles.member(environment.id), attributes) |
795 | + person.follow(self, Circle.find_or_create_by(:person => person, :name =>_('memberships'), :profile_type => 'Community')) | ||
767 | end | 796 | end |
768 | person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } | 797 | person.tasks.pending.of("InviteMember").select { |t| t.data[:community_id] == self.id }.each { |invite| invite.cancel } |
769 | remove_from_suggestion_list person | 798 | remove_from_suggestion_list person |
@@ -1107,7 +1136,11 @@ private :generate_url, :url_options | @@ -1107,7 +1136,11 @@ private :generate_url, :url_options | ||
1107 | end | 1136 | end |
1108 | 1137 | ||
1109 | def followed_by?(person) | 1138 | def followed_by?(person) |
1110 | - person.is_member_of?(self) | 1139 | + (person == self) || (person.in? self.followers) |
1140 | + end | ||
1141 | + | ||
1142 | + def in_social_circle?(person) | ||
1143 | + (person == self) || (person.is_member_of?(self)) | ||
1111 | end | 1144 | end |
1112 | 1145 | ||
1113 | def display_private_info_to?(user) | 1146 | def display_private_info_to?(user) |
@@ -1148,4 +1181,8 @@ private :generate_url, :url_options | @@ -1148,4 +1181,8 @@ private :generate_url, :url_options | ||
1148 | def allow_destroy?(person = nil) | 1181 | def allow_destroy?(person = nil) |
1149 | person.kind_of?(Profile) && person.has_permission?('destroy_profile', self) | 1182 | person.kind_of?(Profile) && person.has_permission?('destroy_profile', self) |
1150 | end | 1183 | end |
1184 | + | ||
1185 | + def in_circle?(circle, follower) | ||
1186 | + ProfileFollower.with_follower(follower).with_circle(circle).with_profile(self).present? | ||
1187 | + end | ||
1151 | end | 1188 | end |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +class ProfileFollower < ApplicationRecord | ||
2 | + self.table_name = :profiles_circles | ||
3 | + track_actions :new_follower, :after_create, :keep_params => ["follower.name", "follower.url", "follower.profile_custom_icon"], :custom_user => :profile | ||
4 | + | ||
5 | + attr_accessible :profile, :circle | ||
6 | + | ||
7 | + belongs_to :profile | ||
8 | + belongs_to :circle | ||
9 | + | ||
10 | + has_one :person, through: :circle | ||
11 | + alias follower person | ||
12 | + | ||
13 | + validates_presence_of :profile_id, :circle_id | ||
14 | + validates :profile_id, :uniqueness => {:scope => :circle_id, :message => "can't put a profile in the same circle twice"} | ||
15 | + | ||
16 | + scope :with_follower, -> person{ | ||
17 | + joins(:circle).where('circles.person_id = ?', person.id) | ||
18 | + } | ||
19 | + | ||
20 | + scope :with_profile, -> profile{ | ||
21 | + where(:profile => profile) | ||
22 | + } | ||
23 | + | ||
24 | + scope :with_circle, -> circle{ | ||
25 | + where(:circle => circle) | ||
26 | + } | ||
27 | + | ||
28 | +end |
app/models/profile_suggestion.rb
@@ -17,7 +17,8 @@ class ProfileSuggestion < ApplicationRecord | @@ -17,7 +17,8 @@ class ProfileSuggestion < ApplicationRecord | ||
17 | self.class.generate_profile_suggestions(profile_suggestion.person) | 17 | self.class.generate_profile_suggestions(profile_suggestion.person) |
18 | end | 18 | end |
19 | 19 | ||
20 | - acts_as_having_settings :field => :categories | 20 | + extend ActsAsHavingSettings::ClassMethods |
21 | + acts_as_having_settings field: :categories | ||
21 | 22 | ||
22 | validate :must_be_a_valid_category, :on => :create | 23 | validate :must_be_a_valid_category, :on => :create |
23 | def must_be_a_valid_category | 24 | def must_be_a_valid_category |
app/models/task.rb
@@ -11,7 +11,8 @@ | @@ -11,7 +11,8 @@ | ||
11 | # will need to declare <ttserialize</tt> itself). | 11 | # will need to declare <ttserialize</tt> itself). |
12 | class Task < ApplicationRecord | 12 | class Task < ApplicationRecord |
13 | 13 | ||
14 | - acts_as_having_settings :field => :data | 14 | + extend ActsAsHavingSettings::ClassMethods |
15 | + acts_as_having_settings field: :data | ||
15 | 16 | ||
16 | module Status | 17 | module Status |
17 | # the status of tasks just created | 18 | # the status of tasks just created |
@@ -313,7 +314,7 @@ class Task < ApplicationRecord | @@ -313,7 +314,7 @@ class Task < ApplicationRecord | ||
313 | where "LOWER(#{field}) LIKE ?", "%#{value.downcase}%" | 314 | where "LOWER(#{field}) LIKE ?", "%#{value.downcase}%" |
314 | end | 315 | end |
315 | } | 316 | } |
316 | - scope :pending_all, -> profile, filter_type, filter_text { | 317 | + scope :pending_all_by_filter, -> profile, filter_type, filter_text { |
317 | self.to(profile).without_spam.pending.of(filter_type).like('data', filter_text) | 318 | self.to(profile).without_spam.pending.of(filter_type).like('data', filter_text) |
318 | } | 319 | } |
319 | 320 | ||
@@ -322,10 +323,17 @@ class Task < ApplicationRecord | @@ -322,10 +323,17 @@ class Task < ApplicationRecord | ||
322 | if profile.person? | 323 | if profile.person? |
323 | envs_ids = Environment.all.select{ |env| profile.is_admin?(env) }.map{ |env| "target_id = #{env.id}"}.join(' OR ') | 324 | envs_ids = Environment.all.select{ |env| profile.is_admin?(env) }.map{ |env| "target_id = #{env.id}"}.join(' OR ') |
324 | environment_condition = envs_ids.blank? ? nil : "(target_type = 'Environment' AND (#{envs_ids}))" | 325 | environment_condition = envs_ids.blank? ? nil : "(target_type = 'Environment' AND (#{envs_ids}))" |
326 | + | ||
327 | + organizations = profile.memberships.all.select do |organization| | ||
328 | + profile.has_permission?(:perform_task, organization) | ||
329 | + end | ||
330 | + organization_ids = organizations.map{ |organization| "target_id = #{organization.id}"}.join(' OR ') | ||
331 | + | ||
332 | + organization_conditions = organization_ids.blank? ? nil : "(target_type = 'Profile' AND (#{organization_ids}))" | ||
325 | end | 333 | end |
326 | profile_condition = "(target_type = 'Profile' AND target_id = #{profile.id})" | 334 | profile_condition = "(target_type = 'Profile' AND target_id = #{profile.id})" |
327 | 335 | ||
328 | - where [environment_condition, profile_condition].compact.join(' OR ') | 336 | + where [environment_condition, organization_conditions, profile_condition].compact.join(' OR ') |
329 | } | 337 | } |
330 | 338 | ||
331 | scope :from_closed_date, -> closed_from { | 339 | scope :from_closed_date, -> closed_from { |
app/models/text_article.rb
1 | -require 'noosfero/translatable_content' | ||
2 | - | ||
3 | # a base class for all text article types. | 1 | # a base class for all text article types. |
4 | class TextArticle < Article | 2 | class TextArticle < Article |
5 | 3 | ||
@@ -9,7 +7,7 @@ class TextArticle < Article | @@ -9,7 +7,7 @@ class TextArticle < Article | ||
9 | _('Article') | 7 | _('Article') |
10 | end | 8 | end |
11 | 9 | ||
12 | - include Noosfero::TranslatableContent | 10 | + include TranslatableContent |
13 | 11 | ||
14 | def self.icon_name(article = nil) | 12 | def self.icon_name(article = nil) |
15 | if article && !article.parent.nil? && article.parent.kind_of?(Blog) | 13 | if article && !article.parent.nil? && article.parent.kind_of?(Blog) |
app/models/tiny_mce_article.rb
app/models/uploaded_file.rb
@@ -84,6 +84,7 @@ class UploadedFile < Article | @@ -84,6 +84,7 @@ class UploadedFile < Article | ||
84 | 84 | ||
85 | validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n | 85 | validates_attachment :size => N_("{fn} of uploaded file was larger than the maximum size of %{size}").sub('%{size}', self.max_size.to_humanreadable).fix_i18n |
86 | 86 | ||
87 | + extend DelayedAttachmentFu::ClassMethods | ||
87 | delay_attachment_fu_thumbnails | 88 | delay_attachment_fu_thumbnails |
88 | 89 | ||
89 | postgresql_attachment_fu | 90 | postgresql_attachment_fu |
app/views/account/activation_question.html.erb
@@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
3 | var answer = parseInt(form.answer.value); | 3 | var answer = parseInt(form.answer.value); |
4 | var val = form.answer.value; | 4 | var val = form.answer.value; |
5 | if (!answer || (val.length != 4) || val > <%= Time.now.year %> || val < 1900) { | 5 | if (!answer || (val.length != 4) || val > <%= Time.now.year %> || val < 1900) { |
6 | - alert(<%= (_('The year must be between %d and %d') % [1900, Time.now.year]).inspect %>); | 6 | + alert(<%= (_('The year must be between %d and %d').html_safe % [1900, Time.now.year]).inspect %>); |
7 | return false; | 7 | return false; |
8 | } else { | 8 | } else { |
9 | return true; | 9 | return true; |
@@ -28,9 +28,9 @@ | @@ -28,9 +28,9 @@ | ||
28 | 28 | ||
29 | <p> <strong><%= _('Pay atention! You have only one chance!') %></strong> </p> | 29 | <p> <strong><%= _('Pay atention! You have only one chance!') %></strong> </p> |
30 | 30 | ||
31 | - <p><%= _("This is a question to know if you really are part of this enterprise. Pay atention because you have only one chance to answer right and activate your enterprise. If you answer wrong you will not be able to activate the enterprise automaticaly and must get in touch with the admins of %s by email or phone.") % environment.name %> </p> | 31 | + <p><%= _("This is a question to know if you really are part of this enterprise. Pay atention because you have only one chance to answer right and activate your enterprise. If you answer wrong you will not be able to activate the enterprise automaticaly and must get in touch with the admins of %s by email or phone.").html_safe % environment.name %> </p> |
32 | 32 | ||
33 | - <%= ApplicationHelper::NoosferoFormBuilder::output_field(@question == :foundation_year ? (_("What year your enterprise was founded? It must have 4 digits, eg 1990. %s") % environment.tip_message_enterprise_activation_question) : _('What is the CNPJ of your enterprise?'), text_field_tag(:answer, nil, :id => 'enterprise-activation-answer')) %> | 33 | + <%= ApplicationHelper::NoosferoFormBuilder::output_field(@question == :foundation_year ? (_("What year your enterprise was founded? It must have 4 digits, eg 1990. %s").html_safe % environment.tip_message_enterprise_activation_question) : _('What is the CNPJ of your enterprise?'), text_field_tag(:answer, nil, :id => 'enterprise-activation-answer')) %> |
34 | 34 | ||
35 | <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %> | 35 | <%= hidden_field_tag :enterprise_code, params[:enterprise_code] %> |
36 | 36 |
app/views/admin_panel/_signup_welcome_text.html.erb
1 | <div class='description'> | 1 | <div class='description'> |
2 | <%= _('This text will be sent to new users if the feature "Send welcome e-mail to new users" is enabled on environment.') %><br/><br/> | 2 | <%= _('This text will be sent to new users if the feature "Send welcome e-mail to new users" is enabled on environment.') %><br/><br/> |
3 | - <%= _('Including %s on body, it will be replaced by the real name of the e-mail recipient.') % content_tag('code', '{user_name}') %> | 3 | + <%= _('Including %s on body, it will be replaced by the real name of the e-mail recipient.').html_safe % content_tag('code', '{user_name}') %> |
4 | </div> | 4 | </div> |
5 | 5 | ||
6 | <%= labelled_form_field(_('Subject'), text_field(:environment, :signup_welcome_text_subject, :style => 'width:100%')) %> | 6 | <%= labelled_form_field(_('Subject'), text_field(:environment, :signup_welcome_text_subject, :style => 'width:100%')) %> |
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +<div class="circles" id='circles-list'> | ||
2 | + | ||
3 | + <%= form_for :circles, :url => {:controller => 'profile', :action => 'follow'}, :html => {:id => "follow-circles-form"} do |f|%> | ||
4 | + <%= render partial: "blocks/profile_info_actions/select_circles", :locals => {:circles => circles, :followed_profile => profile, :follower => current_person } %> | ||
5 | + | ||
6 | + <div id="circle-actions"> | ||
7 | + <%= submit_button :ok, _("Follow") %> | ||
8 | + <input type="button" value="<%= _("Cancel") %>" id="cancel-set-circle" class="button with-text icon-cancel"/> | ||
9 | + </div> | ||
10 | + <% end %> | ||
11 | +</div> |
app/views/blocks/profile_info_actions/_common.html.erb
1 | <li><%= report_abuse(profile, :button) %></li> | 1 | <li><%= report_abuse(profile, :button) %></li> |
2 | +<% if logged_in? && (user != profile) && profile.allow_followers? %> | ||
3 | + <li> | ||
4 | + <% follow = user.follows?(profile) %> | ||
5 | + <%= button(:unfollow, content_tag('span', _('Unfollow')), {:profile => profile.identifier, :controller => 'profile', :action => 'unfollow'}, :method => :post, :id => 'action-unfollow', :title => _("Unfollow"), :style => follow ? "" : "display: none;") %> | ||
6 | + <%= button(:ok, content_tag('span', _('Follow')), {:profile => profile.identifier, :controller => 'profile', :action => 'find_profile_circles'}, :id => 'action-follow', :title => _("Follow"), :style => follow ? "display: none;" : "") %> | ||
7 | + <div id="circles-container" style="display: none;"> | ||
8 | + </div> | ||
9 | + </li> | ||
10 | +<% end %> | ||
2 | <%= render_environment_features(:profile_actions) %> | 11 | <%= render_environment_features(:profile_actions) %> |
app/views/blocks/profile_info_actions/_select_circles.html.erb
0 → 100644
@@ -0,0 +1,22 @@ | @@ -0,0 +1,22 @@ | ||
1 | +<div class="circles" id='circles-list'> | ||
2 | + <p><%= _("Select the circles for %s") % followed_profile.name %></p> | ||
3 | + <div id="circles-checkboxes"> | ||
4 | + <% circles.each do |circle| %> | ||
5 | + <div class="circle"> | ||
6 | + <%= labelled_check_box circle.name, "circles[#{circle.name}]", circle.id, followed_profile.in_circle?(circle, follower) %> | ||
7 | + </div> | ||
8 | + <% end %> | ||
9 | + </div> | ||
10 | + | ||
11 | + <%= button(:add, _('New Circle'), '#', :id => "new-circle") %> | ||
12 | + | ||
13 | + <div id="new-circle-form" style="display: none;"> | ||
14 | + <%= labelled_text_field _('Circle name') , 'circle[name]', "",:id => 'text-field-name-new-circle'%> | ||
15 | + <%= hidden_field_tag('circle[profile_type]', followed_profile.class.name) %> | ||
16 | + | ||
17 | + <%= button_bar do %> | ||
18 | + <%= button(:save, _('Create'), {:profile => follower.identifier, :controller => 'circles', :action => 'xhr_create'}, :id => "new-circle-submit") %> | ||
19 | + <%= button(:cancel, _('Cancel'), '#', :id => "new-circle-cancel") %> | ||
20 | + <% end %> | ||
21 | + </div> | ||
22 | +</div> |
app/views/box_organizer/show_block_type_info.html.erb
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | <div id="block-info-description"> | 15 | <div id="block-info-description"> |
16 | <h2><%= _('Description') %></h2> | 16 | <h2><%= _('Description') %></h2> |
17 | <p><%= @block.class.description %></p> | 17 | <p><%= @block.class.description %></p> |
18 | - <p><%= @block.help if @block.class.method_defined?(:help) %></p> | 18 | + <p><%= @block.help.html_safe if @block.class.method_defined?(:help) %></p> |
19 | </div> | 19 | </div> |
20 | 20 | ||
21 | </div> | 21 | </div> |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +<%= error_messages_for :circle %> | ||
2 | + | ||
3 | +<%= labelled_form_for :circle, :url => (mode == :edit) ? {:action => 'update', :id => circle} : {:action => 'create'} do |f| %> | ||
4 | + | ||
5 | + <%= required_fields_message %> | ||
6 | + | ||
7 | + <%= required f.text_field(:name) %> | ||
8 | + | ||
9 | + <%= required labelled_form_field _("Profile type"), f.select(:profile_type, Circle.profile_types.to_a) %> | ||
10 | + | ||
11 | + <%= button_bar do %> | ||
12 | + <%= submit_button('save', (mode == :edit) ? _('Save changes') : _('Create circle'), :cancel => {:action => 'index'} ) %> | ||
13 | + <% end %> | ||
14 | +<% end %> |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +<h1><%= _('Manage circles') %></h1> | ||
2 | + | ||
3 | +<table> | ||
4 | + <tr> | ||
5 | + <th><%= _('Circle name') %></th> | ||
6 | + <th><%= _('Profile type') %></th> | ||
7 | + <th><%= _('Actions') %></th> | ||
8 | + </tr> | ||
9 | + <% @circles.each do |circle| %> | ||
10 | + <tr> | ||
11 | + <td> | ||
12 | + <%= circle.name %> | ||
13 | + </td> | ||
14 | + <td> | ||
15 | + <%= _(circle.profile_type) %> | ||
16 | + </td> | ||
17 | + <td> | ||
18 | + <div style="text-align: center;"> | ||
19 | + <%= button_without_text :edit, _('Edit'), :action => 'edit', :id => circle %> | ||
20 | + <%= button_without_text :delete, _('Delete'), { :action => 'destroy', :id => circle }, { "data-method" => "POST" } %> | ||
21 | + </div> | ||
22 | + </td> | ||
23 | + </tr> | ||
24 | + <% end %> | ||
25 | +</table> | ||
26 | + | ||
27 | +<%= button_bar do %> | ||
28 | + <%= button :add, _('Create a new circle'), :action => 'new' %> | ||
29 | + <%= button :back, _('Back to control panel'), :controller => 'profile_editor' %> | ||
30 | +<% end %> |
app/views/cms/_blog.html.erb
@@ -58,7 +58,7 @@ | @@ -58,7 +58,7 @@ | ||
58 | <div id="blog-image-builder"> | 58 | <div id="blog-image-builder"> |
59 | <%= f.fields_for :image_builder, @article.image do |i| %> | 59 | <%= f.fields_for :image_builder, @article.image do |i| %> |
60 | <%= file_field_or_thumbnail(_('Cover image:'), @article.image, i)%> | 60 | <%= file_field_or_thumbnail(_('Cover image:'), @article.image, i)%> |
61 | - <%= _("Max size: %s (.jpg, .gif, .png)")% Image.max_size.to_humanreadable %> | 61 | + <%= _("Max size: %s (.jpg, .gif, .png)").html_safe % Image.max_size.to_humanreadable %> |
62 | <% end %> | 62 | <% end %> |
63 | </div> | 63 | </div> |
64 | 64 |
app/views/enterprise_validation/view_processed.html.erb
1 | -<h2><%= _('Processed validation request for %s ') % @processed.name %> (<%= status(@processed) %>)</h2> | 1 | +<h2><%= _('Processed validation request for %s ').html_safe % @processed.name %> (<%= status(@processed) %>)</h2> |
2 | 2 | ||
3 | <%= link_to _('Back'), :action => 'index' %> | 3 | <%= link_to _('Back'), :action => 'index' %> |
4 | 4 |
app/views/favorite_enterprises/add.html.erb
1 | -<h1><%= _('Adding %s as a favorite enterprise') % @favorite_enterprise.name %></h1> | 1 | +<h1><%= _('Adding %s as a favorite enterprise').html_safe % @favorite_enterprise.name %></h1> |
2 | 2 | ||
3 | <p> | 3 | <p> |
4 | -<%= _('Are you sure you want to add %s as your favorite enterprise?') % @favorite_enterprise.name %> | 4 | +<%= _('Are you sure you want to add %s as your favorite enterprise?').html_safe % @favorite_enterprise.name %> |
5 | </p> | 5 | </p> |
6 | 6 | ||
7 | <%= form_tag do %> | 7 | <%= form_tag do %> |
8 | <%= hidden_field_tag(:confirmation, 1) %> | 8 | <%= hidden_field_tag(:confirmation, 1) %> |
9 | 9 | ||
10 | - <%= submit_button(:ok, _("Yes, I am sure"), :title => _("I want to add %s as a favorite enterprise") % @favorite_enterprise.name) %> | 10 | + <%= submit_button(:ok, _("Yes, I am sure"), :title => _("I want to add %s as a favorite enterprise").html_safe % @favorite_enterprise.name) %> |
11 | <%= button(:cancel, _("No, I don't want"), :action => 'index') %> | 11 | <%= button(:cancel, _("No, I don't want"), :action => 'index') %> |
12 | <% end %> | 12 | <% end %> |
app/views/file_presenter/_image.html.erb
@@ -4,15 +4,15 @@ | @@ -4,15 +4,15 @@ | ||
4 | current_index = images.index(image.encapsulated_file) | 4 | current_index = images.index(image.encapsulated_file) |
5 | total_of_images = images.count | 5 | total_of_images = images.count |
6 | link_to_previous = if current_index >= 1 | 6 | link_to_previous = if current_index >= 1 |
7 | - link_to(_('« Previous'), images[current_index - 1].view_url, :class => 'previous') | 7 | + link_to(_('« Previous').html_safe, images[current_index - 1].view_url, :class => 'previous') |
8 | else | 8 | else |
9 | - content_tag('span', _('« Previous'), :class => 'previous') | 9 | + content_tag('span', _('« Previous').html_safe, :class => 'previous') |
10 | end | 10 | end |
11 | 11 | ||
12 | link_to_next = if current_index < total_of_images - 1 | 12 | link_to_next = if current_index < total_of_images - 1 |
13 | - link_to(_('Next »'), images[current_index + 1].view_url, :class => 'next') | 13 | + link_to(_('Next »').html_safe, images[current_index + 1].view_url, :class => 'next') |
14 | else | 14 | else |
15 | - content_tag('span', _('Next »'), :class => 'next') | 15 | + content_tag('span', _('Next »').html_safe, :class => 'next') |
16 | end | 16 | end |
17 | %> | 17 | %> |
18 | 18 |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +<div class="circles" id='circles-list'> | ||
2 | + <%= form_for :circles, :url => {:controller => 'followers', :action => 'update_category'}, :html => {:id => "follow-circles-form"} do |f|%> | ||
3 | + <%= render partial: "blocks/profile_info_actions/select_circles", :locals => {:circles => circles, :followed_profile => followed_profile, :follower => profile } %> | ||
4 | + | ||
5 | + <%= hidden_field_tag('followed_profile_id', followed_profile.id) %> | ||
6 | + | ||
7 | + <div id="circle-actions"> | ||
8 | + <div id="actions-container"> | ||
9 | + <%= submit_button('save', _('Save')) %> | ||
10 | + <%= modal_close_button _("Cancel") %> | ||
11 | + </div> | ||
12 | + </div> | ||
13 | + <% end %> | ||
14 | +</div> |
@@ -0,0 +1,17 @@ | @@ -0,0 +1,17 @@ | ||
1 | +<ul class="profile-list"> | ||
2 | + <% profiles.each do |followed_profile| %> | ||
3 | + <li> | ||
4 | + <%= link_to_profile profile_image(followed_profile) + tag('br') + followed_profile.short_name, | ||
5 | + followed_profile.identifier, :class => 'profile-link' %> | ||
6 | + <div class="controll"> | ||
7 | + <%= button_without_text :remove, content_tag('span',_('unfollow')), | ||
8 | + { :controller => "profile", :profile => followed_profile.identifier, :follower_id => profile.id, | ||
9 | + :action => 'unfollow', :redirect_to => url_for({:controller => "followers", :profile => profile.identifier}) }, | ||
10 | + :method => :post, :title => _('remove') %> | ||
11 | + <%= modal_icon_button :edit, _('change category'), | ||
12 | + url_for(:controller => 'followers', :action => 'set_category_modal', | ||
13 | + :followed_profile_id => followed_profile.id) %> | ||
14 | + </div><!-- end class="controll" --> | ||
15 | + </li> | ||
16 | + <% end %> | ||
17 | +</ul> |
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +<div id="manage_followed people"> | ||
2 | + | ||
3 | +<h1><%= _("%s is following") % profile.name %></h1> | ||
4 | + | ||
5 | +<% cache_timeout(profile.manage_friends_cache_key(params), 4.hours) do %> | ||
6 | + <% if @followed_people.empty? %> | ||
7 | + <p> | ||
8 | + <em> | ||
9 | + <%= _("You don't follow anybody yet.") %> | ||
10 | + </em> | ||
11 | + </p> | ||
12 | + <% end %> | ||
13 | + | ||
14 | + <%= button_bar do %> | ||
15 | + <%= button(:back, _('Back to control panel'), :controller => 'profile_editor') %> | ||
16 | + <%= button(:search, _('Find people'), :controller => 'search', :action => 'assets', :asset => 'people') %> | ||
17 | + <% end %> | ||
18 | + | ||
19 | + <%= labelled_select(_('Profile type')+': ', :filter_profile_type, :last, :first, @active_filter, @profile_types, :id => "profile-type-filter") %> | ||
20 | + | ||
21 | + <%= render :partial => 'profile_list', :locals => { :profiles => @followed_people } %> | ||
22 | + | ||
23 | + <br style="clear:both" /> | ||
24 | + <%= pagination_links @followed_people, :param_name => 'npage' %> | ||
25 | +<% end %> | ||
26 | + | ||
27 | +</div> |
app/views/friends/remove.html.erb
1 | <div id="remove_friend"> | 1 | <div id="remove_friend"> |
2 | 2 | ||
3 | -<h1><%= _('Removing friend: %s') % @friend.name %></h1> | 3 | +<h1><%= _('Removing friend: %s').html_safe % @friend.name %></h1> |
4 | 4 | ||
5 | <%= profile_image @friend, :thumb, :class => 'friend_picture' %> | 5 | <%= profile_image @friend, :thumb, :class => 'friend_picture' %> |
6 | 6 | ||
7 | <p> | 7 | <p> |
8 | -<%= _('Are you sure you want to remove %s from your friends list?') % @friend.name %> | 8 | +<%= _('Are you sure you want to remove %s from your friends list?').html_safe % @friend.name %> |
9 | </p> | 9 | </p> |
10 | 10 | ||
11 | <p> | 11 | <p> |
12 | <em> | 12 | <em> |
13 | -<%= _('Note that %s will still have you as a friend, unless he/she also wants to remove you from his/her friend list.') % @friend.name %> | 13 | +<%= _('Note that %s will still have you as a friend, unless he/she also wants to remove you from his/her friend list.').html_safe % @friend.name %> |
14 | </em> | 14 | </em> |
15 | </p> | 15 | </p> |
16 | 16 |
app/views/home/welcome.html.erb
1 | <% default_message = defined?(default_message) ? default_message : false %> | 1 | <% default_message = defined?(default_message) ? default_message : false %> |
2 | 2 | ||
3 | <div id='thanks-for-signing'> | 3 | <div id='thanks-for-signing'> |
4 | - <h1><%= _("Welcome to %s!") % environment.name %></h1> | 4 | + <h1><%= _("Welcome to %s!").html_safe % environment.name %></h1> |
5 | <% if environment.has_custom_welcome_screen? && !default_message %> | 5 | <% if environment.has_custom_welcome_screen? && !default_message %> |
6 | <%= environment.settings[:signup_welcome_screen_body].html_safe %> | 6 | <%= environment.settings[:signup_welcome_screen_body].html_safe %> |
7 | <% else %> | 7 | <% else %> |
@@ -10,21 +10,21 @@ | @@ -10,21 +10,21 @@ | ||
10 | <p><%= _("Firstly, some tips for getting started:") %></p> | 10 | <p><%= _("Firstly, some tips for getting started:") %></p> |
11 | <h4><%= _("Confirm your account!") %></h4> | 11 | <h4><%= _("Confirm your account!") %></h4> |
12 | <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p> | 12 | <p><%= _("You should receive a welcome email from us shortly. Please take a second to follow the link within to confirm your account.") %></p> |
13 | - <p><%= _("You won't appear as %s until your account is confirmed.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | 13 | + <p><%= _("You won't appear as %s until your account is confirmed.").html_safe % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> |
14 | <% else %> | 14 | <% else %> |
15 | <h4><%= _("Wait for admin approvement!") %></h4> | 15 | <h4><%= _("Wait for admin approvement!") %></h4> |
16 | <p><%= _("The administrators will evaluate your signup request for approvement.") %></p> | 16 | <p><%= _("The administrators will evaluate your signup request for approvement.") %></p> |
17 | - <p><%= _("You won't appear as %s until your account is approved.") % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> | 17 | + <p><%= _("You won't appear as %s until your account is approved.").html_safe % link_to(_('user'), {:controller => :search, :action => :people, :filter => 'more_recent'}, :target => '_blank') %></p> |
18 | <% end %> | 18 | <% end %> |
19 | <h4><%= _("What to do next?") %></h4> | 19 | <h4><%= _("What to do next?") %></h4> |
20 | - <p><%= _("Access your %s and see your face on the network!") % | 20 | + <p><%= _("Access your %s and see your face on the network!").html_safe % |
21 | (user.present? ? link_to(_('Profile'), {:controller => 'profile', :profile => user.identifier}, :target => '_blank') : 'Profile') %> | 21 | (user.present? ? link_to(_('Profile'), {:controller => 'profile', :profile => user.identifier}, :target => '_blank') : 'Profile') %> |
22 | - <%= _("You can also explore your %s to customize your profile. Here are some %s on what you can do there.") % | 22 | + <%= _("You can also explore your %s to customize your profile. Here are some %s on what you can do there.").html_safe % |
23 | [user.present? ? link_to(_('Control Panel'), {:controller => 'profile_editor', :profile => user.identifier}, :target => '_blank') : 'Control Panel', | 23 | [user.present? ? link_to(_('Control Panel'), {:controller => 'profile_editor', :profile => user.identifier}, :target => '_blank') : 'Control Panel', |
24 | link_to(_('tips'), {:controller => 'doc', :action => 'topic', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank')] %></p> | 24 | link_to(_('tips'), {:controller => 'doc', :action => 'topic', :section => 'user', :topic => 'editing-person-info'}, :target => '_blank')] %></p> |
25 | - <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!") % link_to(_('Invite and find'), {:controller => 'doc', :action => 'topic', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p> | ||
26 | - <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!") % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p> | 25 | + <p><%= _("%s your Gmail, Yahoo and Hotmail contacts!").html_safe % link_to(_('Invite and find'), {:controller => 'doc', :action => 'topic', :section => 'user', :topic => 'invite-contacts'}, :target => '_blank') %></p> |
26 | + <p><%= _("Learn the guidelines. Read the %s for more details on how to use this social network!").html_safe % link_to(_('Documentation'), {:controller => 'doc'}, :target => '_blank') %></p> | ||
27 | <p><%= _("Start exploring and have fun!") %></p> | 27 | <p><%= _("Start exploring and have fun!") %></p> |
28 | <% end %> | 28 | <% end %> |
29 | - <%= render :partial => 'shared/template_welcome_page', :locals => {:template => @person_template, :header => _("What can I do as a %s?")} %> | 29 | + <%= render :partial => 'shared/template_welcome_page', :locals => {:template => @person_template, :header => _("What can I do as a %s?").html_safe} %> |
30 | </div> | 30 | </div> |
app/views/person_notifier/mailer/_create_article.html.erb
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | <td> | 5 | <td> |
6 | <p> | 6 | <p> |
7 | <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span> | 7 | <span style="font-size: 14px;"><%= link_to activity.user.short_name(20), activity.user.url %></span> |
8 | - <span style="font-size: 14px;"><%= _("has published on community %s") % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span> | 8 | + <span style="font-size: 14px;"><%= _("has published on community %s").html_safe % link_to(activity.target.profile.short_name(20), activity.target.profile.url, :style => "color: #333; font-weight: bold; text-decoration: none;") if activity.target.profile.is_a?(Community) %></span> |
9 | <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span> | 9 | <span style="font-size: 10px; color: #929292; float:right;"><%= time_ago_in_words(activity.created_at) %></span> |
10 | </p> | 10 | </p> |
11 | <p> | 11 | <p> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<%= render :partial => 'default_activity', :locals => { :activity => activity } %> |
app/views/person_notifier/mailer/_profile_comments.html.erb
1 | <% if activity.comments_count > 2 %> | 1 | <% if activity.comments_count > 2 %> |
2 | <div style="font-size: 10px;"> | 2 | <div style="font-size: 10px;"> |
3 | <% if activity.params['url'].blank? %> | 3 | <% if activity.params['url'].blank? %> |
4 | - <%= _("%s comments") % activity.comments_count %> | 4 | + <%= _("%s comments").html_safe % activity.comments_count %> |
5 | <% else %> | 5 | <% else %> |
6 | - <%= link_to(_("View all %s comments") % activity.comments_count, activity.params['url']) %> | 6 | + <%= link_to(_("View all %s comments").html_safe % activity.comments_count, activity.params['url']) %> |
7 | <% end %> | 7 | <% end %> |
8 | </div> | 8 | </div> |
9 | <% else %> | 9 | <% else %> |
app/views/person_notifier/mailer/content_summary.html.erb
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | <%= link_to @url, :style => "text-decoration: none;" do %> | 5 | <%= link_to @url, :style => "text-decoration: none;" do %> |
6 | <span style="font-weight:bold;font-size: 28px;margin: 0;color: white;background-color: #AAAAAA;padding: 5px;"><%= @environment.name %></span> | 6 | <span style="font-weight:bold;font-size: 28px;margin: 0;color: white;background-color: #AAAAAA;padding: 5px;"><%= @environment.name %></span> |
7 | <% end %> | 7 | <% end %> |
8 | - <span style="font-weight:bold;color: #333;font-size:19px;margin-left: 8px;"><%= _("%s's Notifications") % @profile.name %></h3> | 8 | + <span style="font-weight:bold;color: #333;font-size:19px;margin-left: 8px;"><%= _("%s's Notifications").html_safe % @profile.name %></h3> |
9 | </div> | 9 | </div> |
10 | <div style="margin: 0 20px 20px 20px;border-top:1px solid #e2e2e2;"> | 10 | <div style="margin: 0 20px 20px 20px;border-top:1px solid #e2e2e2;"> |
11 | <% if @tasks.present? %> | 11 | <% if @tasks.present? %> |
@@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
34 | 34 | ||
35 | <div style="color:#444444;font-size:11px;margin-bottom: 20px;"> | 35 | <div style="color:#444444;font-size:11px;margin-bottom: 20px;"> |
36 | <p style="margin:0"><%= _("Greetings,") %></p> | 36 | <p style="margin:0"><%= _("Greetings,") %></p> |
37 | - <p style="margin:0"><%= _('%s team.') % @environment.name %></p> | 37 | + <p style="margin:0"><%= _('%s team.').html_safe % @environment.name %></p> |
38 | <p style="margin:0"><%= link_to @url, url_for(@url) %></p> | 38 | <p style="margin:0"><%= link_to @url, url_for(@url) %></p> |
39 | </div> | 39 | </div> |
40 | </div> | 40 | </div> |
@@ -0,0 +1,18 @@ | @@ -0,0 +1,18 @@ | ||
1 | +<% cache_timeout(profile.friends_cache_key(params), 4.hours) do %> | ||
2 | + <ul class='profile-list'> | ||
3 | + <% follow.each do |follower| %> | ||
4 | + <%= profile_image_link(follower) %> | ||
5 | + <% end%> | ||
6 | + </ul> | ||
7 | + | ||
8 | + <div id='pagination-profiles'> | ||
9 | + <%= pagination_links follow, :param_name => 'npage' %> | ||
10 | + </div> | ||
11 | +<% end %> | ||
12 | + | ||
13 | +<%= button_bar do %> | ||
14 | + <%= button :back, _('Go back'), { :controller => 'profile' } %> | ||
15 | + <% if user == profile %> | ||
16 | + <%= button :edit, _('Manage followed people'), :controller => 'friends', :action => 'index', :profile => profile.identifier %> | ||
17 | + <% end %> | ||
18 | +<% end %> |
@@ -0,0 +1 @@ | @@ -0,0 +1 @@ | ||
1 | +<%= render :partial => 'default_activity', :locals => { :activity => activity, :tab_action => tab_action } %> |
app/views/profile/_private_profile.html.erb
@@ -13,5 +13,5 @@ | @@ -13,5 +13,5 @@ | ||
13 | <%= button(:add, content_tag('span', _('Add friend')), profile.add_url, :class => 'add-friend', :title => _("Add friend"), :style => 'position: relative;') %> | 13 | <%= button(:add, content_tag('span', _('Add friend')), profile.add_url, :class => 'add-friend', :title => _("Add friend"), :style => 'position: relative;') %> |
14 | <% end %> | 14 | <% end %> |
15 | <%= button :back, _('Go back'), :back %> | 15 | <%= button :back, _('Go back'), :back %> |
16 | - <%= button :home, _("Go to %s home page") % environment.name, :controller => 'home' %> | 16 | + <%= button :home, _("Go to %s home page").html_safe % environment.name, :controller => 'home' %> |
17 | <% end %> | 17 | <% end %> |
app/views/profile/_profile_comments.html.erb
@@ -5,7 +5,7 @@ | @@ -5,7 +5,7 @@ | ||
5 | <% if activity.comments_count > 0 %> | 5 | <% if activity.comments_count > 0 %> |
6 | <div id="profile-wall-activities-comments-more-<%= activity.id %>" class="profile-wall-activities-comments" > | 6 | <div id="profile-wall-activities-comments-more-<%= activity.id %>" class="profile-wall-activities-comments" > |
7 | <div class='view-all-comments icon-chat'> | 7 | <div class='view-all-comments icon-chat'> |
8 | - <%= link_to(n_('View comment', "View all %s comments", activity.comments_count) % activity.comments_count, :profile => profile.identifier, :controller => 'profile', :action => 'more_comments', :activity => activity, :comment_page => (1)) %> | 8 | + <%= link_to(n_('View comment', "View all %s comments".html_safe, activity.comments_count) % activity.comments_count, :profile => profile.identifier, :controller => 'profile', :action => 'more_comments', :activity => activity, :comment_page => (1)) %> |
9 | </div> | 9 | </div> |
10 | </div> | 10 | </div> |
11 | <% end %> | 11 | <% end %> |
app/views/profile/_profile_scraps.html.erb
@@ -23,7 +23,7 @@ | @@ -23,7 +23,7 @@ | ||
23 | <% if scrap.replies.count > 0 %> | 23 | <% if scrap.replies.count > 0 %> |
24 | <div id="profile-wall-activities-comments-more-<%= activity.id %>" class="profile-wall-activities-comments"> | 24 | <div id="profile-wall-activities-comments-more-<%= activity.id %>" class="profile-wall-activities-comments"> |
25 | <div class='view-all-comments icon-chat'> | 25 | <div class='view-all-comments icon-chat'> |
26 | - <%= link_to(n_('View comment', "View all %s comments", scrap.replies.count) % scrap.replies.count, :profile => profile.identifier, :controller => 'profile', :action => 'more_replies', :activity => activity, :comment_page => (1)) %> | 26 | + <%= link_to(n_('View comment', "View all %s comments".html_safe, scrap.replies.count) % scrap.replies.count, :profile => profile.identifier, :controller => 'profile', :action => 'more_replies', :activity => activity, :comment_page => (1)) %> |
27 | </div> | 27 | </div> |
28 | </div> | 28 | </div> |
29 | <% end %> | 29 | <% end %> |