Compare View
Commits (289)
- other 89 commits hidden to prevent performance issues.
Showing
1159 changed files
Show diff stats
Too many changes.
To preserve performance only 100 of 1159 files displayed.
.gitlab-ci.yml
@@ -30,14 +30,47 @@ integration: | @@ -30,14 +30,47 @@ integration: | ||
30 | script: bundle exec rake test:integration | 30 | script: bundle exec rake test:integration |
31 | stage: all-tests | 31 | stage: all-tests |
32 | 32 | ||
33 | -cucumber: | ||
34 | - script: bundle exec rake cucumber | 33 | +cucumber-1: |
34 | + script: SLICE=1/2 bundle exec rake cucumber | ||
35 | + stage: all-tests | ||
36 | +cucumber-2: | ||
37 | + script: SLICE=2/2 bundle exec rake cucumber | ||
35 | stage: all-tests | 38 | stage: all-tests |
36 | 39 | ||
37 | -selenium: | ||
38 | - script: bundle exec rake selenium | 40 | +selenium-1: |
41 | + script: SLICE=1/6 bundle exec rake selenium | ||
42 | + stage: all-tests | ||
43 | +selenium-2: | ||
44 | + script: SLICE=2/6 bundle exec rake selenium | ||
45 | + stage: all-tests | ||
46 | +selenium-3: | ||
47 | + script: SLICE=3/6 bundle exec rake selenium | ||
48 | + stage: all-tests | ||
49 | +selenium-4: | ||
50 | + script: SLICE=4/6 bundle exec rake selenium | ||
51 | + stage: all-tests | ||
52 | +selenium-5: | ||
53 | + script: SLICE=5/6 bundle exec rake selenium | ||
54 | + stage: all-tests | ||
55 | +selenium-6: | ||
56 | + script: SLICE=6/6 bundle exec rake selenium | ||
39 | stage: all-tests | 57 | stage: all-tests |
40 | 58 | ||
41 | -plugins: | ||
42 | - script: bundle exec rake test:noosfero_plugins | 59 | +# NOOSFERO_BUNDLE_OPTS=install makes migrations fails |
60 | +# probably because of rubygems-integration | ||
61 | +plugins-1: | ||
62 | + script: SLICE=1/5 bundle exec rake test:noosfero_plugins | ||
43 | stage: all-tests | 63 | stage: all-tests |
64 | +plugins-2: | ||
65 | + script: SLICE=2/5 bundle exec rake test:noosfero_plugins | ||
66 | + stage: all-tests | ||
67 | +plugins-3: | ||
68 | + script: SLICE=3/5 bundle exec rake test:noosfero_plugins | ||
69 | + stage: all-tests | ||
70 | +plugins-4: | ||
71 | + script: SLICE=4/5 bundle exec rake test:noosfero_plugins | ||
72 | + stage: all-tests | ||
73 | +plugins-5: | ||
74 | + script: SLICE=5/5 bundle exec rake test:noosfero_plugins | ||
75 | + stage: all-tests | ||
76 | + |
.travis.yml
@@ -6,15 +6,19 @@ notifications: | @@ -6,15 +6,19 @@ notifications: | ||
6 | template: | 6 | template: |
7 | - "%{repository_slug} %{branch} %{commit} %{commit_subject} - %{result} %{build_url}" | 7 | - "%{repository_slug} %{branch} %{commit} %{commit_subject} - %{result} %{build_url}" |
8 | 8 | ||
9 | -# trusty constainers take more time to start | ||
10 | -#dist: trusty | 9 | +# Ensure Container-based environment, as others can have some random failures |
10 | +# specially with different Firefox versions and selenium tests. | ||
11 | +# E.g. https://travis-ci.org/noosfero/noosfero/jobs/122918772#L1308 | ||
12 | +# | ||
13 | +# Also container-based environments have the fatest boot times and | ||
14 | +# are the only one with cache available for public projects. | ||
15 | +# See https://docs.travis-ci.com/user/ci-environment/#Virtualization-environments | ||
16 | +sudo: false | ||
17 | +cache: bundler | ||
11 | 18 | ||
12 | language: ruby | 19 | language: ruby |
13 | rvm: | 20 | rvm: |
14 | - - 2.2 | ||
15 | - # ruby 2.3 works but isn't stable on travis | ||
16 | - | ||
17 | -cache: bundler | 21 | + - 2.3.1 |
18 | 22 | ||
19 | addons: | 23 | addons: |
20 | apt: | 24 | apt: |
@@ -25,11 +29,6 @@ addons: | @@ -25,11 +29,6 @@ addons: | ||
25 | paths: | 29 | paths: |
26 | - $(ls tmp/artifact* | tr "\n" ":") | 30 | - $(ls tmp/artifact* | tr "\n" ":") |
27 | 31 | ||
28 | -# workaround for https://github.com/travis-ci/travis-ci/issues/4536 | ||
29 | -before_install: | ||
30 | - - export GEM_HOME=$PWD/vendor/bundle/ruby/2.2.0 | ||
31 | - - gem install bundler | ||
32 | - | ||
33 | before_script: | 32 | before_script: |
34 | - mkdir -p tmp/{pids,cache} log cache | 33 | - mkdir -p tmp/{pids,cache} log cache |
35 | - script/noosfero-plugins disableall | 34 | - script/noosfero-plugins disableall |
@@ -41,21 +40,36 @@ before_script: | @@ -41,21 +40,36 @@ before_script: | ||
41 | - bundle exec rake db:migrate &>/dev/null | 40 | - bundle exec rake db:migrate &>/dev/null |
42 | 41 | ||
43 | env: | 42 | env: |
44 | - - TASK=test:api | ||
45 | - - TASK=test:units | ||
46 | - - TASK=test:functionals | ||
47 | - - TASK=test:integration | ||
48 | - - SLICE=1/2 TASK=cucumber LANG=en | ||
49 | - - SLICE=2/2 TASK=cucumber LANG=en | ||
50 | - - SLICE=1/4 TASK=selenium | ||
51 | - - SLICE=2/4 TASK=selenium | ||
52 | - - SLICE=3/4 TASK=selenium | ||
53 | - - SLICE=4/4 TASK=selenium | ||
54 | - - SLICE=1/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install | ||
55 | - - SLICE=2/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install | ||
56 | - - SLICE=3/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install | ||
57 | - - SLICE=4/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install | ||
58 | - - SLICE=5/5 TASK=test:noosfero_plugins BUNDLE_OPTS=install | 43 | + global: |
44 | + - LANG=en | ||
45 | + matrix: | ||
46 | + - TASK=test:api | ||
47 | + - TASK=test:units | ||
48 | + - TASK=test:functionals | ||
49 | + - TASK=test:integration | ||
50 | + - SLICE=1/2 TASK=cucumber | ||
51 | + - SLICE=2/2 TASK=cucumber | ||
52 | + - SLICE=1/4 TASK=selenium | ||
53 | + - SLICE=2/4 TASK=selenium | ||
54 | + - SLICE=3/4 TASK=selenium | ||
55 | + - SLICE=4/4 TASK=selenium | ||
56 | + - SLICE=1/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | ||
57 | + - SLICE=2/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | ||
58 | + - SLICE=3/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | ||
59 | + - SLICE=4/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | ||
60 | + - SLICE=5/5 TASK=test:noosfero_plugins NOOSFERO_BUNDLE_OPTS=install | ||
61 | + # chrome hanging on travis | ||
62 | + #- SLICE=1/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
63 | + #- SLICE=2/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
64 | + #- SLICE=3/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
65 | + #- SLICE=4/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
66 | + | ||
67 | +matrix: | ||
68 | + allow_failures: | ||
69 | + - env: SLICE=1/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
70 | + - env: SLICE=2/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
71 | + - env: SLICE=3/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
72 | + - env: SLICE=4/4 TASK=selenium SELENIUM_DRIVER=chrome | ||
59 | 73 | ||
60 | script: | 74 | script: |
61 | - bundle exec rake $TASK | 75 | - bundle exec rake $TASK |
Gemfile
@@ -77,6 +77,7 @@ group :cucumber do | @@ -77,6 +77,7 @@ group :cucumber do | ||
77 | gem 'cucumber-rails', '~> 1.4.2', :require => false | 77 | gem 'cucumber-rails', '~> 1.4.2', :require => false |
78 | gem 'database_cleaner', '~> 1.3' | 78 | gem 'database_cleaner', '~> 1.3' |
79 | gem 'selenium-webdriver', '>= 2.50' | 79 | gem 'selenium-webdriver', '>= 2.50' |
80 | + gem 'chromedriver-helper' if ENV['SELENIUM_DRIVER'] == 'chrome' | ||
80 | end | 81 | end |
81 | 82 | ||
82 | # Requires custom dependencies | 83 | # Requires custom dependencies |
INSTALL.varnish.md
@@ -19,7 +19,6 @@ Install the RPAF apache module (or skip this step if not using apache): | @@ -19,7 +19,6 @@ Install the RPAF apache module (or skip this step if not using apache): | ||
19 | 19 | ||
20 | 3a) Edit `/etc/apache2/ports.conf`, and: | 20 | 3a) Edit `/etc/apache2/ports.conf`, and: |
21 | 21 | ||
22 | - * change `NameVirtualHost *:80` to `NameVirtualHost *:8080` | ||
23 | * change `Listen 80` to `Listen 127.0.0.1:8080` | 22 | * change `Listen 80` to `Listen 127.0.0.1:8080` |
24 | 23 | ||
25 | 3b) Edit `/etc/apache2/sites-enabled/*`, and change `<VirtualHost *:80>` to `<VirtualHost *:8080>` | 24 | 3b) Edit `/etc/apache2/sites-enabled/*`, and change `<VirtualHost *:80>` to `<VirtualHost *:8080>` |
@@ -30,6 +29,7 @@ Install the RPAF apache module (or skip this step if not using apache): | @@ -30,6 +29,7 @@ Install the RPAF apache module (or skip this step if not using apache): | ||
30 | 29 | ||
31 | * change the line that says `START=no` to say `START=yes` | 30 | * change the line that says `START=no` to say `START=yes` |
32 | * change `-a :6081` to `-a :80` | 31 | * change `-a :6081` to `-a :80` |
32 | + * add parameter `-p vcc_allow_inline_c=on` on `DAEMON_OPTS` | ||
33 | 33 | ||
34 | 4b) Edit `/etc/varnish/default.vcl` and add the following lines at the end: | 34 | 4b) Edit `/etc/varnish/default.vcl` and add the following lines at the end: |
35 | 35 |
README.rails.md
@@ -99,7 +99,7 @@ Description of contents | @@ -99,7 +99,7 @@ Description of contents | ||
99 | Holds controllers that should be named like weblog_controller.rb for automated URL mapping. All controllers should descend from `ActionController::Base`. | 99 | Holds controllers that should be named like weblog_controller.rb for automated URL mapping. All controllers should descend from `ActionController::Base`. |
100 | 100 | ||
101 | * `app/models` | 101 | * `app/models` |
102 | - Holds models that should be named like post.rb. Most models will descend from `ActiveRecord::Base`. | 102 | + Holds models that should be named like post.rb. Most models will descend from `ApplicationRecord`. |
103 | 103 | ||
104 | * `app/views` | 104 | * `app/views` |
105 | Holds the template files for the view that should be named like `weblog/index.rhtml` for the `WeblogController#index` action. All views use eRuby syntax. This directory can also be used to keep stylesheets, images, and so on that can be symlinked to public. | 105 | Holds the template files for the view that should be named like `weblog/index.rhtml` for the `WeblogController#index` action. All views use eRuby syntax. This directory can also be used to keep stylesheets, images, and so on that can be symlinked to public. |
@@ -0,0 +1,89 @@ | @@ -0,0 +1,89 @@ | ||
1 | +require_dependency 'api/helpers' | ||
2 | + | ||
3 | +module Api | ||
4 | + class App < Grape::API | ||
5 | + use Rack::JSONP | ||
6 | + | ||
7 | + logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log")) | ||
8 | + logger.formatter = GrapeLogging::Formatters::Default.new | ||
9 | + #use GrapeLogging::Middleware::RequestLogger, { logger: logger } | ||
10 | + | ||
11 | + rescue_from :all do |e| | ||
12 | + logger.error e | ||
13 | + error! e.message, 500 | ||
14 | + end unless Rails.env.test? | ||
15 | + | ||
16 | + @@NOOSFERO_CONF = nil | ||
17 | + def self.NOOSFERO_CONF | ||
18 | + if @@NOOSFERO_CONF | ||
19 | + @@NOOSFERO_CONF | ||
20 | + else | ||
21 | + file = Rails.root.join('config', 'noosfero.yml') | ||
22 | + @@NOOSFERO_CONF = File.exists?(file) ? YAML.load_file(file)[Rails.env] || {} : {} | ||
23 | + end | ||
24 | + end | ||
25 | + | ||
26 | + before { set_locale } | ||
27 | + before { setup_multitenancy } | ||
28 | + before { detect_stuff_by_domain } | ||
29 | + before { filter_disabled_plugins_endpoints } | ||
30 | + before { init_noosfero_plugins } | ||
31 | + after { set_session_cookie } | ||
32 | + | ||
33 | + version 'v1' | ||
34 | + prefix [ENV['RAILS_RELATIVE_URL_ROOT'], "api"].compact.join('/') | ||
35 | + format :json | ||
36 | + content_type :txt, "text/plain" | ||
37 | + | ||
38 | + helpers Helpers | ||
39 | + | ||
40 | + mount V1::Session | ||
41 | + mount V1::Articles | ||
42 | + mount V1::Comments | ||
43 | + mount V1::Users | ||
44 | + mount V1::Communities | ||
45 | + mount V1::People | ||
46 | + mount V1::Enterprises | ||
47 | + mount V1::Categories | ||
48 | + mount V1::Tasks | ||
49 | + mount V1::Tags | ||
50 | + mount V1::Environments | ||
51 | + mount V1::Search | ||
52 | + mount V1::Contacts | ||
53 | + mount V1::Boxes | ||
54 | + mount V1::Blocks | ||
55 | + mount V1::Profiles | ||
56 | + mount V1::Activities | ||
57 | + | ||
58 | + # 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 | + @plugins = Noosfero::Plugin.all.map { |p| p.constantize } | ||
61 | + @plugins.each do |klass| | ||
62 | + if klass.public_methods.include? :api_mount_points | ||
63 | + klass.api_mount_points.each do |mount_class| | ||
64 | + mount mount_class if mount_class && ( mount_class < Grape::API ) | ||
65 | + end | ||
66 | + end | ||
67 | + end | ||
68 | + | ||
69 | + def self.endpoint_unavailable?(endpoint, environment) | ||
70 | + api_class = endpoint.options[:app] || endpoint.options[:for] | ||
71 | + if api_class.present? | ||
72 | + klass = api_class.name.deconstantize.constantize | ||
73 | + return klass < Noosfero::Plugin && !environment.plugin_enabled?(klass) | ||
74 | + end | ||
75 | + end | ||
76 | + | ||
77 | + class << self | ||
78 | + def endpoints_with_plugins(environment = nil) | ||
79 | + if environment.present? | ||
80 | + cloned_endpoints = endpoints_without_plugins.dup | ||
81 | + cloned_endpoints.delete_if { |endpoint| endpoint_unavailable?(endpoint, environment) } | ||
82 | + else | ||
83 | + endpoints_without_plugins | ||
84 | + end | ||
85 | + end | ||
86 | + alias_method_chain :endpoints, :plugins | ||
87 | + end | ||
88 | + end | ||
89 | +end |
@@ -0,0 +1,269 @@ | @@ -0,0 +1,269 @@ | ||
1 | +module Api | ||
2 | + module Entities | ||
3 | + | ||
4 | + Entity.format_with :timestamp do |date| | ||
5 | + date.strftime('%Y/%m/%d %H:%M:%S') if date | ||
6 | + end | ||
7 | + | ||
8 | + PERMISSIONS = { | ||
9 | + :admin => 0, | ||
10 | + :self => 10, | ||
11 | + :private_content => 20, | ||
12 | + :logged_user => 30, | ||
13 | + :anonymous => 40 | ||
14 | + } | ||
15 | + | ||
16 | + def self.can_display_profile_field? profile, options, permission_options={} | ||
17 | + permissions={:field => "", :permission => :private_content} | ||
18 | + permissions.merge!(permission_options) | ||
19 | + field = permissions[:field] | ||
20 | + permission = permissions[:permission] | ||
21 | + return true if profile.public? && profile.public_fields.map{|f| f.to_sym}.include?(field.to_sym) | ||
22 | + | ||
23 | + current_person = options[:current_person] | ||
24 | + | ||
25 | + current_permission = if current_person.present? | ||
26 | + if current_person.is_admin? | ||
27 | + :admin | ||
28 | + elsif current_person == profile | ||
29 | + :self | ||
30 | + elsif profile.display_private_info_to?(current_person) | ||
31 | + :private_content | ||
32 | + else | ||
33 | + :logged_user | ||
34 | + end | ||
35 | + else | ||
36 | + :anonymous | ||
37 | + end | ||
38 | + PERMISSIONS[current_permission] <= PERMISSIONS[permission] | ||
39 | + end | ||
40 | + | ||
41 | + class Image < Entity | ||
42 | + root 'images', 'image' | ||
43 | + | ||
44 | + expose :url do |image, options| | ||
45 | + image.public_filename | ||
46 | + end | ||
47 | + | ||
48 | + expose :icon_url do |image, options| | ||
49 | + image.public_filename(:icon) | ||
50 | + end | ||
51 | + | ||
52 | + expose :minor_url do |image, options| | ||
53 | + image.public_filename(:minor) | ||
54 | + end | ||
55 | + | ||
56 | + expose :portrait_url do |image, options| | ||
57 | + image.public_filename(:portrait) | ||
58 | + end | ||
59 | + | ||
60 | + expose :thumb_url do |image, options| | ||
61 | + image.public_filename(:thumb) | ||
62 | + end | ||
63 | + end | ||
64 | + | ||
65 | + class CategoryBase < Entity | ||
66 | + root 'categories', 'category' | ||
67 | + expose :name, :id, :slug | ||
68 | + end | ||
69 | + | ||
70 | + class Category < CategoryBase | ||
71 | + root 'categories', 'category' | ||
72 | + expose :full_name do |category, options| | ||
73 | + category.full_name | ||
74 | + end | ||
75 | + expose :parent, :using => CategoryBase, if: { parent: true } | ||
76 | + expose :children, :using => CategoryBase, if: { children: true } | ||
77 | + expose :image, :using => Image | ||
78 | + expose :display_color | ||
79 | + end | ||
80 | + | ||
81 | + class Region < Category | ||
82 | + root 'regions', 'region' | ||
83 | + expose :parent_id | ||
84 | + end | ||
85 | + | ||
86 | + class Block < Entity | ||
87 | + root 'blocks', 'block' | ||
88 | + expose :id, :type, :settings, :position, :enabled | ||
89 | + expose :mirror, :mirror_block_id, :title | ||
90 | + expose :api_content, if: lambda { |object, options| options[:display_api_content] || object.display_api_content_by_default? } | ||
91 | + end | ||
92 | + | ||
93 | + class Box < Entity | ||
94 | + root 'boxes', 'box' | ||
95 | + expose :id, :position | ||
96 | + expose :blocks, :using => Block do |box, options| | ||
97 | + box.blocks.select {|block| block.visible_to_user?(options[:current_person]) } | ||
98 | + end | ||
99 | + end | ||
100 | + | ||
101 | + class Profile < Entity | ||
102 | + expose :identifier, :name, :id | ||
103 | + expose :created_at, :format_with => :timestamp | ||
104 | + expose :updated_at, :format_with => :timestamp | ||
105 | + expose :additional_data do |profile, options| | ||
106 | + hash ={} | ||
107 | + profile.public_values.each do |value| | ||
108 | + hash[value.custom_field.name]=value.value | ||
109 | + end | ||
110 | + | ||
111 | + private_values = profile.custom_field_values - profile.public_values | ||
112 | + private_values.each do |value| | ||
113 | + if Entities.can_display_profile_field?(profile,options) | ||
114 | + hash[value.custom_field.name]=value.value | ||
115 | + end | ||
116 | + end | ||
117 | + hash | ||
118 | + end | ||
119 | + expose :image, :using => Image | ||
120 | + expose :region, :using => Region | ||
121 | + expose :type | ||
122 | + expose :custom_header | ||
123 | + expose :custom_footer | ||
124 | + end | ||
125 | + | ||
126 | + class UserBasic < Entity | ||
127 | + expose :id | ||
128 | + expose :login | ||
129 | + end | ||
130 | + | ||
131 | + class Person < Profile | ||
132 | + root 'people', 'person' | ||
133 | + expose :user, :using => UserBasic, documentation: {type: 'User', desc: 'The user data of a person' } | ||
134 | + expose :vote_count | ||
135 | + expose :comments_count do |person, options| | ||
136 | + person.comments.count | ||
137 | + end | ||
138 | + expose :following_articles_count do |person, options| | ||
139 | + person.following_articles.count | ||
140 | + end | ||
141 | + expose :articles_count do |person, options| | ||
142 | + person.articles.count | ||
143 | + end | ||
144 | + end | ||
145 | + | ||
146 | + class Enterprise < Profile | ||
147 | + root 'enterprises', 'enterprise' | ||
148 | + end | ||
149 | + | ||
150 | + class Community < Profile | ||
151 | + root 'communities', 'community' | ||
152 | + expose :description | ||
153 | + expose :admins, :if => lambda { |community, options| community.display_info_to? options[:current_person]} do |community, options| | ||
154 | + community.admins.map{|admin| {"name"=>admin.name, "id"=>admin.id, "username" => admin.identifier}} | ||
155 | + end | ||
156 | + expose :categories, :using => Category | ||
157 | + expose :members, :using => Person , :if => lambda{ |community, options| community.display_info_to? options[:current_person] } | ||
158 | + end | ||
159 | + | ||
160 | + class CommentBase < Entity | ||
161 | + expose :body, :title, :id | ||
162 | + expose :created_at, :format_with => :timestamp | ||
163 | + expose :author, :using => Profile | ||
164 | + expose :reply_of, :using => CommentBase | ||
165 | + end | ||
166 | + | ||
167 | + class Comment < CommentBase | ||
168 | + root 'comments', 'comment' | ||
169 | + expose :children, as: :replies, :using => Comment | ||
170 | + end | ||
171 | + | ||
172 | + class ArticleBase < Entity | ||
173 | + root 'articles', 'article' | ||
174 | + expose :id | ||
175 | + expose :body | ||
176 | + expose :abstract, documentation: {type: 'String', desc: 'Teaser of the body'} | ||
177 | + expose :created_at, :format_with => :timestamp | ||
178 | + expose :updated_at, :format_with => :timestamp | ||
179 | + expose :title, :documentation => {:type => "String", :desc => "Title of the article"} | ||
180 | + expose :created_by, :as => :author, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile author that create the article'} | ||
181 | + expose :profile, :using => Profile, :documentation => {type: 'Profile', desc: 'The profile associated with the article'} | ||
182 | + expose :categories, :using => Category | ||
183 | + expose :image, :using => Image | ||
184 | + expose :votes_for | ||
185 | + expose :votes_against | ||
186 | + expose :setting | ||
187 | + expose :position | ||
188 | + expose :hits | ||
189 | + expose :start_date | ||
190 | + expose :end_date, :documentation => {type: 'DateTime', desc: 'The date of finish of the article'} | ||
191 | + expose :tag_list | ||
192 | + expose :children_count | ||
193 | + expose :slug, :documentation => {:type => "String", :desc => "Trimmed and parsed name of a article"} | ||
194 | + expose :path | ||
195 | + expose :followers_count | ||
196 | + expose :votes_count | ||
197 | + expose :comments_count | ||
198 | + expose :archived, :documentation => {:type => "Boolean", :desc => "Defines if a article is readonly"} | ||
199 | + expose :type | ||
200 | + expose :comments, using: CommentBase, :if => lambda{|obj,opt| opt[:params] && ['1','true',true].include?(opt[:params][:show_comments])} | ||
201 | + expose :published | ||
202 | + expose :accept_comments?, as: :accept_comments | ||
203 | + end | ||
204 | + | ||
205 | + class Article < ArticleBase | ||
206 | + root 'articles', 'article' | ||
207 | + expose :parent, :using => ArticleBase | ||
208 | + expose :children, :using => ArticleBase do |article, options| | ||
209 | + article.children.published.limit(V1::Articles::MAX_PER_PAGE) | ||
210 | + end | ||
211 | + end | ||
212 | + | ||
213 | + class User < Entity | ||
214 | + root 'users', 'user' | ||
215 | + | ||
216 | + attrs = [:id,:login,:email,:activated?] | ||
217 | + aliases = {:activated? => :activated} | ||
218 | + | ||
219 | + attrs.each do |attribute| | ||
220 | + name = aliases.has_key?(attribute) ? aliases[attribute] : attribute | ||
221 | + expose attribute, :as => name, :if => lambda{|user,options| Entities.can_display_profile_field?(user.person, options, {:field => attribute})} | ||
222 | + end | ||
223 | + | ||
224 | + expose :person, :using => Person, :if => lambda{|user,options| user.person.display_info_to? options[:current_person]} | ||
225 | + expose :permissions, :if => lambda{|user,options| Entities.can_display_profile_field?(user.person, options, {:field => :permissions, :permission => :self})} do |user, options| | ||
226 | + output = {} | ||
227 | + user.person.role_assignments.map do |role_assigment| | ||
228 | + if role_assigment.resource.respond_to?(:identifier) && !role_assigment.role.nil? | ||
229 | + output[role_assigment.resource.identifier] = role_assigment.role.permissions | ||
230 | + end | ||
231 | + end | ||
232 | + output | ||
233 | + end | ||
234 | + end | ||
235 | + | ||
236 | + class UserLogin < User | ||
237 | + root 'users', 'user' | ||
238 | + expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'}, if: lambda {|object, options| object.activated? } | ||
239 | + end | ||
240 | + | ||
241 | + class Task < Entity | ||
242 | + root 'tasks', 'task' | ||
243 | + expose :id | ||
244 | + expose :type | ||
245 | + end | ||
246 | + | ||
247 | + class Environment < Entity | ||
248 | + expose :name | ||
249 | + expose :id | ||
250 | + expose :description | ||
251 | + expose :settings, if: lambda { |instance, options| options[:is_admin] } | ||
252 | + end | ||
253 | + | ||
254 | + class Tag < Entity | ||
255 | + root 'tags', 'tag' | ||
256 | + expose :name | ||
257 | + end | ||
258 | + | ||
259 | + class Activity < Entity | ||
260 | + root 'activities', 'activity' | ||
261 | + expose :id, :params, :verb, :created_at, :updated_at, :comments_count, :visible | ||
262 | + expose :user, :using => Profile | ||
263 | + expose :target do |activity, opts| | ||
264 | + type_map = {Profile => ::Profile, ArticleBase => ::Article}.find {|h| activity.target.kind_of?(h.last)} | ||
265 | + type_map.first.represent(activity.target) unless type_map.nil? | ||
266 | + end | ||
267 | + end | ||
268 | + end | ||
269 | +end |
@@ -0,0 +1,27 @@ | @@ -0,0 +1,27 @@ | ||
1 | +module Api | ||
2 | + class Entity < Grape::Entity | ||
3 | + | ||
4 | + def initialize(object, options = {}) | ||
5 | + object = nil if object.is_a? Exception | ||
6 | + super object, options | ||
7 | + end | ||
8 | + | ||
9 | + def self.represent(objects, options = {}) | ||
10 | + if options[:has_exception] | ||
11 | + data = super objects, options.merge(is_inner_data: true) | ||
12 | + if objects.is_a? Exception | ||
13 | + data.merge ok: false, error: { | ||
14 | + type: objects.class.name, | ||
15 | + message: objects.message | ||
16 | + } | ||
17 | + else | ||
18 | + data = data.serializable_hash if data.is_a? Entity | ||
19 | + data.merge ok: true, error: { type: 'Success', message: '' } | ||
20 | + end | ||
21 | + else | ||
22 | + super objects, options | ||
23 | + end | ||
24 | + end | ||
25 | + | ||
26 | + end | ||
27 | +end |
@@ -0,0 +1,421 @@ | @@ -0,0 +1,421 @@ | ||
1 | +require 'base64' | ||
2 | +require 'tempfile' | ||
3 | + | ||
4 | +module Api | ||
5 | + module Helpers | ||
6 | + PRIVATE_TOKEN_PARAM = :private_token | ||
7 | + DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier, :archived] | ||
8 | + | ||
9 | + include SanitizeParams | ||
10 | + include Noosfero::Plugin::HotSpot | ||
11 | + include ForgotPasswordHelper | ||
12 | + include SearchTermHelper | ||
13 | + | ||
14 | + def set_locale | ||
15 | + I18n.locale = (params[:lang] || request.env['HTTP_ACCEPT_LANGUAGE'] || 'en') | ||
16 | + end | ||
17 | + | ||
18 | + def init_noosfero_plugins | ||
19 | + plugins | ||
20 | + end | ||
21 | + | ||
22 | + def current_user | ||
23 | + private_token = (params[PRIVATE_TOKEN_PARAM] || headers['Private-Token']).to_s | ||
24 | + @current_user ||= User.find_by private_token: private_token | ||
25 | + @current_user ||= plugins.dispatch("api_custom_login", request).first | ||
26 | + @current_user | ||
27 | + end | ||
28 | + | ||
29 | + def current_person | ||
30 | + current_user.person unless current_user.nil? | ||
31 | + end | ||
32 | + | ||
33 | + def is_admin?(environment) | ||
34 | + return false unless current_user | ||
35 | + return current_person.is_admin?(environment) | ||
36 | + end | ||
37 | + | ||
38 | + def logout | ||
39 | + @current_user = nil | ||
40 | + end | ||
41 | + | ||
42 | + def environment | ||
43 | + @environment | ||
44 | + end | ||
45 | + | ||
46 | + def present_partial(model, options) | ||
47 | + if(params[:fields].present?) | ||
48 | + begin | ||
49 | + fields = JSON.parse(params[:fields]) | ||
50 | + if fields.present? | ||
51 | + options.merge!(fields.symbolize_keys.slice(:only, :except)) | ||
52 | + end | ||
53 | + rescue | ||
54 | + fields = params[:fields] | ||
55 | + fields = fields.split(',') if fields.kind_of?(String) | ||
56 | + options[:only] = Array.wrap(fields) | ||
57 | + end | ||
58 | + end | ||
59 | + present model, options | ||
60 | + end | ||
61 | + | ||
62 | + include FindByContents | ||
63 | + | ||
64 | + #################################################################### | ||
65 | + #### SEARCH | ||
66 | + #################################################################### | ||
67 | + def multiple_search?(searches=nil) | ||
68 | + ['index', 'category_index'].include?(params[:action]) || (searches && searches.size > 1) | ||
69 | + end | ||
70 | + #################################################################### | ||
71 | + | ||
72 | + def logger | ||
73 | + logger = Logger.new(File.join(Rails.root, 'log', "#{ENV['RAILS_ENV'] || 'production'}_api.log")) | ||
74 | + logger.formatter = GrapeLogging::Formatters::Default.new | ||
75 | + logger | ||
76 | + end | ||
77 | + | ||
78 | + def limit | ||
79 | + limit = params[:limit].to_i | ||
80 | + limit = default_limit if limit <= 0 | ||
81 | + limit | ||
82 | + end | ||
83 | + | ||
84 | + def period(from_date, until_date) | ||
85 | + return nil if from_date.nil? && until_date.nil? | ||
86 | + | ||
87 | + begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date | ||
88 | + end_period = until_date.nil? ? DateTime.now : until_date | ||
89 | + | ||
90 | + begin_period..end_period | ||
91 | + end | ||
92 | + | ||
93 | + def parse_content_type(content_type) | ||
94 | + return nil if content_type.blank? | ||
95 | + content_type.split(',').map do |content_type| | ||
96 | + content_type.camelcase | ||
97 | + end | ||
98 | + end | ||
99 | + | ||
100 | + def find_article(articles, id) | ||
101 | + article = articles.find(id) | ||
102 | + article.display_to?(current_person) ? article : forbidden! | ||
103 | + end | ||
104 | + | ||
105 | + def post_article(asset, params) | ||
106 | + return forbidden! unless current_person.can_post_content?(asset) | ||
107 | + | ||
108 | + klass_type = params[:content_type] || params[:article].delete(:type) || TinyMceArticle.name | ||
109 | + return forbidden! unless klass_type.constantize <= Article | ||
110 | + | ||
111 | + article = klass_type.constantize.new(params[:article]) | ||
112 | + article.last_changed_by = current_person | ||
113 | + article.created_by= current_person | ||
114 | + article.profile = asset | ||
115 | + | ||
116 | + if !article.save | ||
117 | + render_api_errors!(article.errors.full_messages) | ||
118 | + end | ||
119 | + present_partial article, :with => Entities::Article | ||
120 | + end | ||
121 | + | ||
122 | + def present_article(asset) | ||
123 | + article = find_article(asset.articles, params[:id]) | ||
124 | + present_partial article, :with => Entities::Article, :params => params | ||
125 | + end | ||
126 | + | ||
127 | + def present_articles_for_asset(asset, method = 'articles') | ||
128 | + articles = find_articles(asset, method) | ||
129 | + present_articles(articles) | ||
130 | + end | ||
131 | + | ||
132 | + def present_articles(articles) | ||
133 | + present_partial paginate(articles), :with => Entities::Article, :params => params | ||
134 | + end | ||
135 | + | ||
136 | + def find_articles(asset, method = 'articles') | ||
137 | + articles = select_filtered_collection_of(asset, method, params) | ||
138 | + if current_person.present? | ||
139 | + articles = articles.display_filter(current_person, nil) | ||
140 | + else | ||
141 | + articles = articles.published | ||
142 | + end | ||
143 | + articles | ||
144 | + end | ||
145 | + | ||
146 | + def find_task(asset, id) | ||
147 | + task = asset.tasks.find(id) | ||
148 | + current_person.has_permission?(task.permission, asset) ? task : forbidden! | ||
149 | + end | ||
150 | + | ||
151 | + def post_task(asset, params) | ||
152 | + klass_type= params[:content_type].nil? ? 'Task' : params[:content_type] | ||
153 | + return forbidden! unless klass_type.constantize <= Task | ||
154 | + | ||
155 | + task = klass_type.constantize.new(params[:task]) | ||
156 | + task.requestor_id = current_person.id | ||
157 | + task.target_id = asset.id | ||
158 | + task.target_type = 'Profile' | ||
159 | + | ||
160 | + if !task.save | ||
161 | + render_api_errors!(task.errors.full_messages) | ||
162 | + end | ||
163 | + present_partial task, :with => Entities::Task | ||
164 | + end | ||
165 | + | ||
166 | + def present_task(asset) | ||
167 | + task = find_task(asset, params[:id]) | ||
168 | + present_partial task, :with => Entities::Task | ||
169 | + end | ||
170 | + | ||
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) | ||
175 | + present_partial tasks, :with => Entities::Task | ||
176 | + end | ||
177 | + | ||
178 | + def make_conditions_with_parameter(params = {}) | ||
179 | + parsed_params = parser_params(params) | ||
180 | + conditions = {} | ||
181 | + 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] | ||
183 | + | ||
184 | + conditions[:type] = parse_content_type(parsed_params.delete(:content_type)) unless parsed_params[:content_type].nil? | ||
185 | + | ||
186 | + conditions[:created_at] = period(from_date, until_date) if from_date || until_date | ||
187 | + conditions.merge!(parsed_params) | ||
188 | + | ||
189 | + conditions | ||
190 | + end | ||
191 | + | ||
192 | + # changing make_order_with_parameters to avoid sql injection | ||
193 | + def make_order_with_parameters(object, method, params) | ||
194 | + order = "created_at DESC" | ||
195 | + unless params[:order].blank? | ||
196 | + if params[:order].include? '\'' or params[:order].include? '"' | ||
197 | + order = "created_at DESC" | ||
198 | + elsif ['RANDOM()', 'RANDOM'].include? params[:order].upcase | ||
199 | + order = 'RANDOM()' | ||
200 | + else | ||
201 | + 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 | ||
205 | + if direction.present? and ['ASC','DESC'].include? direction.upcase | ||
206 | + order = "#{field_name} #{direction.upcase}" | ||
207 | + end | ||
208 | + end | ||
209 | + end | ||
210 | + end | ||
211 | + end | ||
212 | + return order | ||
213 | + end | ||
214 | + | ||
215 | + def make_timestamp_with_parameters_and_method(params, method) | ||
216 | + timestamp = nil | ||
217 | + if params[:timestamp] | ||
218 | + datetime = DateTime.parse(params[:timestamp]) | ||
219 | + table_name = method.to_s.singularize.camelize.constantize.table_name | ||
220 | + timestamp = "#{table_name}.updated_at >= '#{datetime}'" | ||
221 | + end | ||
222 | + | ||
223 | + timestamp | ||
224 | + end | ||
225 | + | ||
226 | + def by_reference(scope, params) | ||
227 | + reference_id = params[:reference_id].to_i == 0 ? nil : params[:reference_id].to_i | ||
228 | + if reference_id.nil? | ||
229 | + scope | ||
230 | + else | ||
231 | + created_at = scope.find(reference_id).created_at | ||
232 | + scope.send("#{params.key?(:oldest) ? 'older_than' : 'younger_than'}", created_at) | ||
233 | + end | ||
234 | + end | ||
235 | + | ||
236 | + def by_categories(scope, params) | ||
237 | + category_ids = params[:category_ids] | ||
238 | + if category_ids.nil? | ||
239 | + scope | ||
240 | + else | ||
241 | + scope.joins(:categories).where(:categories => {:id => category_ids}) | ||
242 | + end | ||
243 | + end | ||
244 | + | ||
245 | + def select_filtered_collection_of(object, method, params) | ||
246 | + 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) | ||
249 | + | ||
250 | + objects = object.send(method) | ||
251 | + objects = by_reference(objects, params) | ||
252 | + objects = by_categories(objects, params) | ||
253 | + | ||
254 | + objects = objects.where(conditions).where(timestamp).reorder(order) | ||
255 | + | ||
256 | + params[:page] ||= 1 | ||
257 | + params[:per_page] ||= limit | ||
258 | + paginate(objects) | ||
259 | + end | ||
260 | + | ||
261 | + def authenticate! | ||
262 | + unauthorized! unless current_user | ||
263 | + end | ||
264 | + | ||
265 | + def profiles_for_person(profiles, person) | ||
266 | + if person | ||
267 | + profiles.listed_for_person(person) | ||
268 | + else | ||
269 | + profiles.visible | ||
270 | + end | ||
271 | + end | ||
272 | + | ||
273 | + # Checks the occurrences of uniqueness of attributes, each attribute must be present in the params hash | ||
274 | + # or a Bad Request error is invoked. | ||
275 | + # | ||
276 | + # Parameters: | ||
277 | + # keys (unique) - A hash consisting of keys that must be unique | ||
278 | + def unique_attributes!(obj, keys) | ||
279 | + keys.each do |key| | ||
280 | + cant_be_saved_request!(key) if obj.find_by(key.to_s => params[key]) | ||
281 | + end | ||
282 | + end | ||
283 | + | ||
284 | + def attributes_for_keys(keys) | ||
285 | + attrs = {} | ||
286 | + keys.each do |key| | ||
287 | + attrs[key] = params[key] if params[key].present? or (params.has_key?(key) and params[key] == false) | ||
288 | + end | ||
289 | + attrs | ||
290 | + end | ||
291 | + | ||
292 | + ########################################## | ||
293 | + # error helpers # | ||
294 | + ########################################## | ||
295 | + | ||
296 | + def not_found! | ||
297 | + render_api_error!('404 Not found', 404) | ||
298 | + end | ||
299 | + | ||
300 | + def forbidden! | ||
301 | + render_api_error!('403 Forbidden', 403) | ||
302 | + end | ||
303 | + | ||
304 | + def cant_be_saved_request!(attribute) | ||
305 | + message = _("(Invalid request) %s can't be saved") % attribute | ||
306 | + render_api_error!(message, 400) | ||
307 | + end | ||
308 | + | ||
309 | + def bad_request!(attribute) | ||
310 | + message = _("(Invalid request) %s not given") % attribute | ||
311 | + render_api_error!(message, 400) | ||
312 | + end | ||
313 | + | ||
314 | + def something_wrong! | ||
315 | + message = _("Something wrong happened") | ||
316 | + render_api_error!(message, 400) | ||
317 | + end | ||
318 | + | ||
319 | + def unauthorized! | ||
320 | + render_api_error!(_('Unauthorized'), 401) | ||
321 | + end | ||
322 | + | ||
323 | + def not_allowed! | ||
324 | + render_api_error!(_('Method Not Allowed'), 405) | ||
325 | + end | ||
326 | + | ||
327 | + # javascript_console_message is supposed to be executed as console.log() | ||
328 | + def render_api_error!(user_message, status, log_message = nil, javascript_console_message = nil) | ||
329 | + message_hash = {'message' => user_message, :code => status} | ||
330 | + message_hash[:javascript_console_message] = javascript_console_message if javascript_console_message.present? | ||
331 | + log_msg = "#{status}, User message: #{user_message}" | ||
332 | + log_msg = "#{log_message}, #{log_msg}" if log_message.present? | ||
333 | + log_msg = "#{log_msg}, Javascript Console Message: #{javascript_console_message}" if javascript_console_message.present? | ||
334 | + logger.error log_msg unless Rails.env.test? | ||
335 | + error!(message_hash, status) | ||
336 | + end | ||
337 | + | ||
338 | + def render_api_errors!(messages) | ||
339 | + messages = messages.to_a if messages.class == ActiveModel::Errors | ||
340 | + render_api_error!(messages.join(','), 400) | ||
341 | + end | ||
342 | + | ||
343 | + protected | ||
344 | + | ||
345 | + def set_session_cookie | ||
346 | + cookies['_noosfero_api_session'] = { value: @current_user.private_token, httponly: true } if @current_user.present? | ||
347 | + end | ||
348 | + | ||
349 | + def setup_multitenancy | ||
350 | + Noosfero::MultiTenancy.setup!(request.host) | ||
351 | + end | ||
352 | + | ||
353 | + def detect_stuff_by_domain | ||
354 | + @domain = Domain.by_name(request.host) | ||
355 | + if @domain.nil? | ||
356 | + @environment = Environment.default | ||
357 | + if @environment.nil? && Rails.env.development? | ||
358 | + # This should only happen in development ... | ||
359 | + @environment = Environment.create!(:name => "Noosfero", :is_default => true) | ||
360 | + end | ||
361 | + else | ||
362 | + @environment = @domain.environment | ||
363 | + end | ||
364 | + end | ||
365 | + | ||
366 | + def filter_disabled_plugins_endpoints | ||
367 | + not_found! if Api::App.endpoint_unavailable?(self, @environment) | ||
368 | + end | ||
369 | + | ||
370 | + def asset_with_image params | ||
371 | + if params.has_key? :image_builder | ||
372 | + asset_api_params = params | ||
373 | + asset_api_params[:image_builder] = base64_to_uploadedfile(asset_api_params[:image_builder]) | ||
374 | + return asset_api_params | ||
375 | + end | ||
376 | + params | ||
377 | + end | ||
378 | + | ||
379 | + def base64_to_uploadedfile(base64_image) | ||
380 | + tempfile = base64_to_tempfile base64_image | ||
381 | + converted_image = base64_image | ||
382 | + converted_image[:tempfile] = tempfile | ||
383 | + return {uploaded_data: ActionDispatch::Http::UploadedFile.new(converted_image)} | ||
384 | + end | ||
385 | + | ||
386 | + def base64_to_tempfile base64_image | ||
387 | + base64_img_str = base64_image[:tempfile] | ||
388 | + decoded_base64_str = Base64.decode64(base64_img_str) | ||
389 | + tempfile = Tempfile.new(base64_image[:filename]) | ||
390 | + tempfile.write(decoded_base64_str.encode("ascii-8bit").force_encoding("utf-8")) | ||
391 | + tempfile.rewind | ||
392 | + tempfile | ||
393 | + end | ||
394 | + private | ||
395 | + | ||
396 | + def parser_params(params) | ||
397 | + parsed_params = {} | ||
398 | + params.map do |k,v| | ||
399 | + parsed_params[k.to_sym] = v if DEFAULT_ALLOWED_PARAMETERS.include?(k.to_sym) | ||
400 | + end | ||
401 | + parsed_params | ||
402 | + end | ||
403 | + | ||
404 | + def default_limit | ||
405 | + 20 | ||
406 | + end | ||
407 | + | ||
408 | + def parse_content_type(content_type) | ||
409 | + return nil if content_type.blank? | ||
410 | + content_type.split(',').map do |content_type| | ||
411 | + content_type.camelcase | ||
412 | + end | ||
413 | + end | ||
414 | + | ||
415 | + def period(from_date, until_date) | ||
416 | + begin_period = from_date.nil? ? Time.at(0).to_datetime : from_date | ||
417 | + end_period = until_date.nil? ? DateTime.now : until_date | ||
418 | + begin_period..end_period | ||
419 | + end | ||
420 | + end | ||
421 | +end |
@@ -0,0 +1,20 @@ | @@ -0,0 +1,20 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Activities < Grape::API | ||
4 | + before { authenticate! } | ||
5 | + | ||
6 | + resource :profiles do | ||
7 | + | ||
8 | + get ':id/activities' do | ||
9 | + profile = Profile.find_by id: params[:id] | ||
10 | + | ||
11 | + not_found! if profile.blank? || profile.secret || !profile.visible | ||
12 | + forbidden! if !profile.secret && profile.visible && !profile.display_private_info_to?(current_person) | ||
13 | + | ||
14 | + activities = profile.activities.map(&:activity) | ||
15 | + present activities, :with => Entities::Activity, :current_person => current_person | ||
16 | + end | ||
17 | + end | ||
18 | + end | ||
19 | + end | ||
20 | +end |
@@ -0,0 +1,303 @@ | @@ -0,0 +1,303 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Articles < Grape::API | ||
4 | + | ||
5 | + ARTICLE_TYPES = Article.descendants.map{|a| a.to_s} | ||
6 | + | ||
7 | + MAX_PER_PAGE = 50 | ||
8 | + | ||
9 | + resource :articles do | ||
10 | + | ||
11 | + paginate max_per_page: MAX_PER_PAGE | ||
12 | + # Collect articles | ||
13 | + # | ||
14 | + # Parameters: | ||
15 | + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created | ||
16 | + # oldest - Collect the oldest articles. If nothing is passed the newest articles are collected | ||
17 | + # limit - amount of articles returned. The default value is 20 | ||
18 | + # | ||
19 | + # Example Request: | ||
20 | + # GET host/api/v1/articles?from=2013-04-04-14:41:43&until=2015-04-04-14:41:43&limit=10&private_token=e96fff37c2238fdab074d1dcea8e6317 | ||
21 | + | ||
22 | + desc 'Return all articles of all kinds' do | ||
23 | + detail 'Get all articles filtered by fields in query params' | ||
24 | + params Entities::Article.documentation | ||
25 | + success Entities::Article | ||
26 | + failure [[403, 'Forbidden']] | ||
27 | + named 'ArticlesList' | ||
28 | + headers [ | ||
29 | + 'Per-Page' => { | ||
30 | + description: 'Total number of records', | ||
31 | + required: false | ||
32 | + } | ||
33 | + ] | ||
34 | + end | ||
35 | + get do | ||
36 | + present_articles_for_asset(environment) | ||
37 | + end | ||
38 | + | ||
39 | + desc "Return one article by id" do | ||
40 | + detail 'Get only one article by id. If not found the "forbidden" http error is showed' | ||
41 | + params Entities::Article.documentation | ||
42 | + success Entities::Article | ||
43 | + failure [[403, 'Forbidden']] | ||
44 | + named 'ArticleById' | ||
45 | + end | ||
46 | + get ':id', requirements: {id: /[0-9]+/} do | ||
47 | + present_article(environment) | ||
48 | + end | ||
49 | + | ||
50 | + post ':id' do | ||
51 | + article = environment.articles.find(params[:id]) | ||
52 | + return forbidden! unless article.allow_edit?(current_person) | ||
53 | + article.update_attributes!(asset_with_image(params[:article])) | ||
54 | + present_partial article, :with => Entities::Article | ||
55 | + end | ||
56 | + | ||
57 | + desc 'Report a abuse and/or violent content in a article by id' do | ||
58 | + detail 'Submit a abuse (in general, a content violation) report about a specific article' | ||
59 | + params Entities::Article.documentation | ||
60 | + failure [[400, 'Bad Request']] | ||
61 | + named 'ArticleReportAbuse' | ||
62 | + end | ||
63 | + post ':id/report_abuse' do | ||
64 | + article = find_article(environment.articles, params[:id]) | ||
65 | + profile = article.profile | ||
66 | + begin | ||
67 | + abuse_report = AbuseReport.new(:reason => params[:report_abuse]) | ||
68 | + if !params[:content_type].blank? | ||
69 | + article = params[:content_type].constantize.find(params[:content_id]) | ||
70 | + abuse_report.content = article_reported_version(article) | ||
71 | + end | ||
72 | + | ||
73 | + current_person.register_report(abuse_report, profile) | ||
74 | + | ||
75 | + if !params[:content_type].blank? | ||
76 | + abuse_report = AbuseReport.find_by reporter_id: current_person.id, abuse_complaint_id: profile.opened_abuse_complaint.id | ||
77 | + Delayed::Job.enqueue DownloadReportedImagesJob.new(abuse_report, article) | ||
78 | + end | ||
79 | + | ||
80 | + { | ||
81 | + :success => true, | ||
82 | + :message => _('Your abuse report was registered. The administrators are reviewing your report.'), | ||
83 | + } | ||
84 | + rescue Exception => exception | ||
85 | + #logger.error(exception.to_s) | ||
86 | + render_api_error!(_('Your report couldn\'t be saved due to some problem. Please contact the administrator.'), 400) | ||
87 | + end | ||
88 | + | ||
89 | + end | ||
90 | + | ||
91 | + desc "Returns the articles I voted" do | ||
92 | + detail 'Get the Articles I make a vote' | ||
93 | + failure [[403, 'Forbidden']] | ||
94 | + named 'ArticleFollowers' | ||
95 | + end | ||
96 | + #FIXME refactor this method | ||
97 | + get 'voted_by_me' do | ||
98 | + present_articles(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable)) | ||
99 | + end | ||
100 | + | ||
101 | + desc 'Perform a vote on a article by id' do | ||
102 | + detail 'Vote on a specific article with values: 1 (if you like) or -1 (if not)' | ||
103 | + params Entities::UserLogin.documentation | ||
104 | + failure [[401,'Unauthorized']] | ||
105 | + named 'ArticleVote' | ||
106 | + end | ||
107 | + post ':id/vote' do | ||
108 | + authenticate! | ||
109 | + value = (params[:value] || 1).to_i | ||
110 | + # FIXME verify allowed values | ||
111 | + render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) | ||
112 | + article = find_article(environment.articles, params[:id]) | ||
113 | + begin | ||
114 | + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | ||
115 | + {:vote => vote.save!} | ||
116 | + rescue ActiveRecord::RecordInvalid => e | ||
117 | + render_api_error!(e.message, 400) | ||
118 | + end | ||
119 | + end | ||
120 | + | ||
121 | + desc "Returns the total followers for the article" do | ||
122 | + detail 'Get the followers of a specific article by id' | ||
123 | + failure [[403, 'Forbidden']] | ||
124 | + named 'ArticleFollowers' | ||
125 | + end | ||
126 | + get ':id/followers' do | ||
127 | + article = find_article(environment.articles, params[:id]) | ||
128 | + total = article.person_followers.count | ||
129 | + {:total_followers => total} | ||
130 | + end | ||
131 | + | ||
132 | + desc "Return the articles followed by me" | ||
133 | + get 'followed_by_me' do | ||
134 | + present_articles_for_asset(current_person, 'following_articles') | ||
135 | + end | ||
136 | + | ||
137 | + desc "Add a follower for the article" do | ||
138 | + detail 'Add the current user identified by private token, like a follower of a article' | ||
139 | + params Entities::UserLogin.documentation | ||
140 | + failure [[401, 'Unauthorized']] | ||
141 | + named 'ArticleFollow' | ||
142 | + end | ||
143 | + post ':id/follow' do | ||
144 | + authenticate! | ||
145 | + article = find_article(environment.articles, params[:id]) | ||
146 | + if article.article_followers.exists?(:person_id => current_person.id) | ||
147 | + {:success => false, :already_follow => true} | ||
148 | + else | ||
149 | + article_follower = ArticleFollower.new | ||
150 | + article_follower.article = article | ||
151 | + article_follower.person = current_person | ||
152 | + article_follower.save! | ||
153 | + {:success => true} | ||
154 | + end | ||
155 | + end | ||
156 | + | ||
157 | + desc 'Return the children of a article identified by id' do | ||
158 | + detail 'Get all children articles of a specific article' | ||
159 | + params Entities::Article.documentation | ||
160 | + failure [[403, 'Forbidden']] | ||
161 | + named 'ArticleChildren' | ||
162 | + end | ||
163 | + | ||
164 | + paginate per_page: MAX_PER_PAGE, max_per_page: MAX_PER_PAGE | ||
165 | + get ':id/children' do | ||
166 | + article = find_article(environment.articles, params[:id]) | ||
167 | + | ||
168 | + #TODO make tests for this situation | ||
169 | + votes_order = params.delete(:order) if params[:order]=='votes_score' | ||
170 | + articles = select_filtered_collection_of(article, 'children', params) | ||
171 | + articles = articles.display_filter(current_person, article.profile) | ||
172 | + | ||
173 | + #TODO make tests for this situation | ||
174 | + if votes_order | ||
175 | + articles = articles.joins('left join votes on articles.id=votes.voteable_id').group('articles.id').reorder('sum(coalesce(votes.vote, 0)) DESC') | ||
176 | + end | ||
177 | + Article.hit(articles) | ||
178 | + present_articles(articles) | ||
179 | + end | ||
180 | + | ||
181 | + desc 'Return one child of a article identified by id' do | ||
182 | + detail 'Get a child of a specific article' | ||
183 | + params Entities::Article.documentation | ||
184 | + success Entities::Article | ||
185 | + failure [[403, 'Forbidden']] | ||
186 | + named 'ArticleChild' | ||
187 | + end | ||
188 | + get ':id/children/:child_id' do | ||
189 | + article = find_article(environment.articles, params[:id]) | ||
190 | + child = find_article(article.children, params[:child_id]) | ||
191 | + child.hit | ||
192 | + present_partial child, :with => Entities::Article | ||
193 | + end | ||
194 | + | ||
195 | + desc 'Suggest a article to another profile' do | ||
196 | + detail 'Suggest a article to another profile (person, community...)' | ||
197 | + params Entities::Article.documentation | ||
198 | + success Entities::Task | ||
199 | + failure [[401,'Unauthorized']] | ||
200 | + named 'ArticleSuggest' | ||
201 | + end | ||
202 | + post ':id/children/suggest' do | ||
203 | + authenticate! | ||
204 | + parent_article = environment.articles.find(params[:id]) | ||
205 | + | ||
206 | + suggest_article = SuggestArticle.new | ||
207 | + suggest_article.article = params[:article] | ||
208 | + suggest_article.article[:parent_id] = parent_article.id | ||
209 | + suggest_article.target = parent_article.profile | ||
210 | + suggest_article.requestor = current_person | ||
211 | + | ||
212 | + unless suggest_article.save | ||
213 | + render_api_errors!(suggest_article.article_object.errors.full_messages) | ||
214 | + end | ||
215 | + present_partial suggest_article, :with => Entities::Task | ||
216 | + end | ||
217 | + | ||
218 | + # Example Request: | ||
219 | + # POST api/v1/articles/:id/children?private_token=234298743290432&article[name]=title&article[body]=body | ||
220 | + desc 'Add a child article to a parent identified by id' do | ||
221 | + detail 'Create a new article and associate to a parent' | ||
222 | + params Entities::Article.documentation | ||
223 | + success Entities::Article | ||
224 | + failure [[401,'Unauthorized']] | ||
225 | + named 'ArticleAddChild' | ||
226 | + end | ||
227 | + post ':id/children' do | ||
228 | + parent_article = environment.articles.find(params[:id]) | ||
229 | + params[:article][:parent_id] = parent_article.id | ||
230 | + post_article(parent_article.profile, params) | ||
231 | + end | ||
232 | + end | ||
233 | + | ||
234 | + resource :profiles do | ||
235 | + get ':id/home_page' do | ||
236 | + profiles = environment.profiles | ||
237 | + profiles = profiles.visible_for_person(current_person) | ||
238 | + profile = profiles.find_by id: params[:id] | ||
239 | + present_partial profile.home_page, :with => Entities::Article | ||
240 | + end | ||
241 | + end | ||
242 | + | ||
243 | + kinds = %w[profile community person enterprise] | ||
244 | + kinds.each do |kind| | ||
245 | + resource kind.pluralize.to_sym do | ||
246 | + segment "/:#{kind}_id" do | ||
247 | + resource :articles do | ||
248 | + | ||
249 | + desc "Return all articles associate with a profile of type #{kind}" do | ||
250 | + detail 'Get a list of articles of a profile' | ||
251 | + params Entities::Article.documentation | ||
252 | + success Entities::Article | ||
253 | + failure [[403, 'Forbidden']] | ||
254 | + named 'ArticlesOfProfile' | ||
255 | + end | ||
256 | + get do | ||
257 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
258 | + | ||
259 | + if params[:path].present? | ||
260 | + article = profile.articles.find_by path: params[:path] | ||
261 | + if !article || !article.display_to?(current_person) | ||
262 | + article = forbidden! | ||
263 | + end | ||
264 | + | ||
265 | + present_partial article, :with => Entities::Article | ||
266 | + else | ||
267 | + | ||
268 | + present_articles_for_asset(profile) | ||
269 | + end | ||
270 | + end | ||
271 | + | ||
272 | + desc "Return a article associate with a profile of type #{kind}" do | ||
273 | + detail 'Get only one article of a profile' | ||
274 | + params Entities::Article.documentation | ||
275 | + success Entities::Article | ||
276 | + failure [[403, 'Forbidden']] | ||
277 | + named 'ArticleOfProfile' | ||
278 | + end | ||
279 | + get ':id' do | ||
280 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
281 | + present_article(profile) | ||
282 | + end | ||
283 | + | ||
284 | + # Example Request: | ||
285 | + # POST api/v1/{people,communities,enterprises}/:asset_id/articles?private_token=234298743290432&article[name]=title&article[body]=body | ||
286 | + desc "Add a new article associated with a profile of type #{kind}" do | ||
287 | + detail 'Create a new article and associate with a profile' | ||
288 | + params Entities::Article.documentation | ||
289 | + success Entities::Article | ||
290 | + failure [[403, 'Forbidden']] | ||
291 | + named 'ArticleCreateToProfile' | ||
292 | + end | ||
293 | + post do | ||
294 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
295 | + post_article(profile, params) | ||
296 | + end | ||
297 | + end | ||
298 | + end | ||
299 | + end | ||
300 | + end | ||
301 | + end | ||
302 | + end | ||
303 | +end |
@@ -0,0 +1,15 @@ | @@ -0,0 +1,15 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + | ||
4 | + class Blocks < Grape::API | ||
5 | + resource :blocks do | ||
6 | + get ':id' do | ||
7 | + block = Block.find(params["id"]) | ||
8 | + return forbidden! unless block.visible_to_user?(current_person) | ||
9 | + present block, :with => Entities::Block, display_api_content: true | ||
10 | + end | ||
11 | + end | ||
12 | + end | ||
13 | + | ||
14 | + end | ||
15 | +end |
@@ -0,0 +1,45 @@ | @@ -0,0 +1,45 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + | ||
4 | + class Boxes < Grape::API | ||
5 | + | ||
6 | + kinds = %w[profile community person enterprise] | ||
7 | + kinds.each do |kind| | ||
8 | + | ||
9 | + resource kind.pluralize.to_sym do | ||
10 | + | ||
11 | + segment "/:#{kind}_id" do | ||
12 | + resource :boxes do | ||
13 | + get do | ||
14 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
15 | + return forbidden! unless profile.display_info_to?(current_person) | ||
16 | + present profile.boxes, :with => Entities::Box | ||
17 | + end | ||
18 | + end | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
22 | + end | ||
23 | + | ||
24 | + resource :environments do | ||
25 | + [ '/default', '/context', ':environment_id' ].each do |route| | ||
26 | + segment route do | ||
27 | + resource :boxes do | ||
28 | + get do | ||
29 | + if (route.match(/default/)) | ||
30 | + env = Environment.default | ||
31 | + elsif (route.match(/context/)) | ||
32 | + env = environment | ||
33 | + else | ||
34 | + env = Environment.find(params[:environment_id]) | ||
35 | + end | ||
36 | + present env.boxes, :with => Entities::Box | ||
37 | + end | ||
38 | + end | ||
39 | + end | ||
40 | + end | ||
41 | + end | ||
42 | + end | ||
43 | + | ||
44 | + end | ||
45 | +end |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Categories < Grape::API | ||
4 | + | ||
5 | + resource :categories do | ||
6 | + | ||
7 | + get do | ||
8 | + type = params[:category_type] | ||
9 | + include_parent = params[:include_parent] == 'true' | ||
10 | + include_children = params[:include_children] == 'true' | ||
11 | + | ||
12 | + categories = type.nil? ? environment.categories : environment.categories.where(:type => type) | ||
13 | + present categories, :with => Entities::Category, parent: include_parent, children: include_children | ||
14 | + end | ||
15 | + | ||
16 | + desc "Return the category by id" | ||
17 | + get ':id' do | ||
18 | + present environment.categories.find(params[:id]), :with => Entities::Category, parent: true, children: true | ||
19 | + end | ||
20 | + | ||
21 | + end | ||
22 | + | ||
23 | + end | ||
24 | + end | ||
25 | +end |
@@ -0,0 +1,49 @@ | @@ -0,0 +1,49 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Comments < Grape::API | ||
4 | + MAX_PER_PAGE = 20 | ||
5 | + | ||
6 | + | ||
7 | + resource :articles do | ||
8 | + paginate max_per_page: MAX_PER_PAGE | ||
9 | + # Collect comments from articles | ||
10 | + # | ||
11 | + # Parameters: | ||
12 | + # reference_id - comment id used as reference to collect comment | ||
13 | + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected | ||
14 | + # limit - amount of comments returned. The default value is 20 | ||
15 | + # | ||
16 | + # Example Request: | ||
17 | + # GET /articles/12/comments?oldest&limit=10&reference_id=23 | ||
18 | + get ":id/comments" do | ||
19 | + article = find_article(environment.articles, params[:id]) | ||
20 | + comments = select_filtered_collection_of(article, :comments, params) | ||
21 | + comments = comments.without_spam | ||
22 | + comments = comments.without_reply if(params[:without_reply].present?) | ||
23 | + comments = plugins.filter(:unavailable_comments, comments) | ||
24 | + present paginate(comments), :with => Entities::Comment, :current_person => current_person | ||
25 | + end | ||
26 | + | ||
27 | + get ":id/comments/:comment_id" do | ||
28 | + article = find_article(environment.articles, params[:id]) | ||
29 | + present article.comments.find(params[:comment_id]), :with => Entities::Comment, :current_person => current_person | ||
30 | + end | ||
31 | + | ||
32 | + # Example Request: | ||
33 | + # POST api/v1/articles/12/comments?private_token=2298743290432&body=new comment&title=New | ||
34 | + post ":id/comments" do | ||
35 | + authenticate! | ||
36 | + article = find_article(environment.articles, params[:id]) | ||
37 | + options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article) | ||
38 | + begin | ||
39 | + comment = Comment.create!(options) | ||
40 | + rescue ActiveRecord::RecordInvalid => e | ||
41 | + render_api_error!(e.message, 400) | ||
42 | + end | ||
43 | + present comment, :with => Entities::Comment, :current_person => current_person | ||
44 | + end | ||
45 | + end | ||
46 | + | ||
47 | + end | ||
48 | + end | ||
49 | +end |
@@ -0,0 +1,82 @@ | @@ -0,0 +1,82 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Communities < Grape::API | ||
4 | + | ||
5 | + resource :communities do | ||
6 | + | ||
7 | + # Collect comments from articles | ||
8 | + # | ||
9 | + # Parameters: | ||
10 | + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created | ||
11 | + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected | ||
12 | + # limit - amount of comments returned. The default value is 20 | ||
13 | + # | ||
14 | + # Example Request: | ||
15 | + # GET /communities?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10 | ||
16 | + # GET /communities?reference_id=10&limit=10&oldest | ||
17 | + get do | ||
18 | + communities = select_filtered_collection_of(environment, 'communities', params) | ||
19 | + communities = profiles_for_person(communities, current_person) | ||
20 | + communities = communities.by_location(params) # Must be the last. May return Exception obj | ||
21 | + present communities, :with => Entities::Community, :current_person => current_person | ||
22 | + end | ||
23 | + | ||
24 | + | ||
25 | + # Example Request: | ||
26 | + # POST api/v1/communties?private_token=234298743290432&community[name]=some_name | ||
27 | + # for each custom field for community, add &community[field_name]=field_value to the request | ||
28 | + post do | ||
29 | + authenticate! | ||
30 | + params[:community] ||= {} | ||
31 | + | ||
32 | + params[:community][:custom_values]={} | ||
33 | + params[:community].keys.each do |key| | ||
34 | + params[:community][:custom_values][key]=params[:community].delete(key) if Community.custom_fields(environment).any?{|cf| cf.name==key} | ||
35 | + end | ||
36 | + | ||
37 | + begin | ||
38 | + community = Community.create_after_moderation(current_person, params[:community].merge({:environment => environment})) | ||
39 | + rescue | ||
40 | + community = Community.new(params[:community]) | ||
41 | + end | ||
42 | + | ||
43 | + if !community.save | ||
44 | + render_api_errors!(community.errors.full_messages) | ||
45 | + end | ||
46 | + | ||
47 | + present community, :with => Entities::Community, :current_person => current_person | ||
48 | + end | ||
49 | + | ||
50 | + get ':id' do | ||
51 | + community = profiles_for_person(environment.communities, current_person).find_by_id(params[:id]) | ||
52 | + present community, :with => Entities::Community, :current_person => current_person | ||
53 | + end | ||
54 | + | ||
55 | + end | ||
56 | + | ||
57 | + resource :people do | ||
58 | + | ||
59 | + segment '/:person_id' do | ||
60 | + | ||
61 | + resource :communities do | ||
62 | + | ||
63 | + get do | ||
64 | + person = environment.people.find(params[:person_id]) | ||
65 | + | ||
66 | + not_found! if person.blank? | ||
67 | + forbidden! if !person.display_info_to?(current_person) | ||
68 | + | ||
69 | + communities = select_filtered_collection_of(person, 'communities', params) | ||
70 | + communities = communities.visible | ||
71 | + present communities, :with => Entities::Community, :current_person => current_person | ||
72 | + end | ||
73 | + | ||
74 | + end | ||
75 | + | ||
76 | + end | ||
77 | + | ||
78 | + end | ||
79 | + | ||
80 | + end | ||
81 | + end | ||
82 | +end |
@@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Contacts < Grape::API | ||
4 | + | ||
5 | + resource :communities do | ||
6 | + | ||
7 | + resource ':id/contact' do | ||
8 | + #contact => {:name => 'some name', :email => 'test@mail.com', :subject => 'some title', :message => 'some message'} | ||
9 | + desc "Send a contact message" | ||
10 | + post do | ||
11 | + profile = environment.communities.find(params[:id]) | ||
12 | + forbidden! unless profile.present? | ||
13 | + contact = Contact.new params[:contact].merge(dest: profile) | ||
14 | + if contact.deliver | ||
15 | + {:success => true} | ||
16 | + else | ||
17 | + {:success => false} | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
21 | + end | ||
22 | + end | ||
23 | + | ||
24 | + end | ||
25 | + end | ||
26 | +end |
@@ -0,0 +1,55 @@ | @@ -0,0 +1,55 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Enterprises < Grape::API | ||
4 | + | ||
5 | + resource :enterprises do | ||
6 | + | ||
7 | + # Collect enterprises from environment | ||
8 | + # | ||
9 | + # Parameters: | ||
10 | + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created | ||
11 | + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected | ||
12 | + # limit - amount of comments returned. The default value is 20 | ||
13 | + # georef params - read `Profile.by_location` for more information. | ||
14 | + # | ||
15 | + # Example Request: | ||
16 | + # GET /enterprises?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10 | ||
17 | + # GET /enterprises?reference_id=10&limit=10&oldest | ||
18 | + get do | ||
19 | + enterprises = select_filtered_collection_of(environment, 'enterprises', params) | ||
20 | + enterprises = enterprises.visible | ||
21 | + enterprises = enterprises.by_location(params) # Must be the last. May return Exception obj. | ||
22 | + present enterprises, :with => Entities::Enterprise, :current_person => current_person | ||
23 | + end | ||
24 | + | ||
25 | + desc "Return one enterprise by id" | ||
26 | + get ':id' do | ||
27 | + enterprise = environment.enterprises.visible.find_by(id: params[:id]) | ||
28 | + present enterprise, :with => Entities::Enterprise, :current_person => current_person | ||
29 | + end | ||
30 | + | ||
31 | + end | ||
32 | + | ||
33 | + resource :people do | ||
34 | + | ||
35 | + segment '/:person_id' do | ||
36 | + | ||
37 | + resource :enterprises do | ||
38 | + | ||
39 | + get do | ||
40 | + person = environment.people.find(params[:person_id]) | ||
41 | + enterprises = select_filtered_collection_of(person, 'enterprises', params) | ||
42 | + enterprises = enterprises.visible.by_location(params) | ||
43 | + present enterprises, :with => Entities::Enterprise, :current_person => current_person | ||
44 | + end | ||
45 | + | ||
46 | + end | ||
47 | + | ||
48 | + end | ||
49 | + | ||
50 | + end | ||
51 | + | ||
52 | + | ||
53 | + end | ||
54 | + end | ||
55 | +end |
@@ -0,0 +1,28 @@ | @@ -0,0 +1,28 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Environments < Grape::API | ||
4 | + | ||
5 | + resource :environment do | ||
6 | + | ||
7 | + desc "Return the person information" | ||
8 | + get '/signup_person_fields' do | ||
9 | + present environment.signup_person_fields | ||
10 | + end | ||
11 | + | ||
12 | + get ':id' do | ||
13 | + local_environment = nil | ||
14 | + if (params[:id] == "default") | ||
15 | + local_environment = Environment.default | ||
16 | + elsif (params[:id] == "context") | ||
17 | + local_environment = environment | ||
18 | + else | ||
19 | + local_environment = Environment.find(params[:id]) | ||
20 | + end | ||
21 | + present_partial local_environment, :with => Entities::Environment, :is_admin => is_admin?(local_environment) | ||
22 | + end | ||
23 | + | ||
24 | + end | ||
25 | + | ||
26 | + end | ||
27 | + end | ||
28 | +end |
@@ -0,0 +1,127 @@ | @@ -0,0 +1,127 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class People < Grape::API | ||
4 | + | ||
5 | + MAX_PER_PAGE = 50 | ||
6 | + | ||
7 | + desc 'API Root' | ||
8 | + | ||
9 | + resource :people do | ||
10 | + paginate max_per_page: MAX_PER_PAGE | ||
11 | + | ||
12 | + # -- A note about privacy -- | ||
13 | + # We wold find people by location, but we must test if the related | ||
14 | + # fields are public. We can't do it now, with SQL, while the location | ||
15 | + # data and the fields_privacy are a serialized settings. | ||
16 | + # We must build a new table for profile data, where we can set meta-data | ||
17 | + # like: | ||
18 | + # | id | profile_id | key | value | privacy_level | source | | ||
19 | + # | 1 | 99 | city | Salvador | friends | user | | ||
20 | + # | 2 | 99 | lng | -38.521 | me only | automatic | | ||
21 | + | ||
22 | + # Collect people from environment | ||
23 | + # | ||
24 | + # Parameters: | ||
25 | + # from - date where the search will begin. If nothing is passed the default date will be the date of the first article created | ||
26 | + # oldest - Collect the oldest comments from reference_id comment. If nothing is passed the newest comments are collected | ||
27 | + # limit - amount of comments returned. The default value is 20 | ||
28 | + # | ||
29 | + # Example Request: | ||
30 | + # GET /people?from=2013-04-04-14:41:43&until=2014-04-04-14:41:43&limit=10 | ||
31 | + # GET /people?reference_id=10&limit=10&oldest | ||
32 | + | ||
33 | + desc "Find environment's people" | ||
34 | + get do | ||
35 | + people = select_filtered_collection_of(environment, 'people', params) | ||
36 | + people = people.visible | ||
37 | + present_partial people, :with => Entities::Person, :current_person => current_person | ||
38 | + end | ||
39 | + | ||
40 | + desc "Return the logged user information" | ||
41 | + get "/me" do | ||
42 | + authenticate! | ||
43 | + present_partial current_person, :with => Entities::Person, :current_person => current_person | ||
44 | + end | ||
45 | + | ||
46 | + desc "Return the person information" | ||
47 | + get ':id' do | ||
48 | + person = environment.people.visible.find_by(id: params[:id]) | ||
49 | + return not_found! if person.blank? | ||
50 | + present person, :with => Entities::Person, :current_person => current_person | ||
51 | + end | ||
52 | + | ||
53 | + desc "Update person information" | ||
54 | + post ':id' do | ||
55 | + authenticate! | ||
56 | + return forbidden! if current_person.id.to_s != params[:id] | ||
57 | + current_person.update_attributes!(asset_with_image(params[:person])) | ||
58 | + present current_person, :with => Entities::Person, :current_person => current_person | ||
59 | + end | ||
60 | + | ||
61 | + # POST api/v1/people?person[login]=some_login&person[password]=some_password&person[name]=Jack | ||
62 | + # for each custom field for person, add &person[field_name]=field_value to the request | ||
63 | + desc "Create person" | ||
64 | + post do | ||
65 | + authenticate! | ||
66 | + user_data = {} | ||
67 | + user_data[:login] = params[:person].delete(:login) || params[:person][:identifier] | ||
68 | + user_data[:email] = params[:person].delete(:email) | ||
69 | + user_data[:password] = params[:person].delete(:password) | ||
70 | + user_data[:password_confirmation] = params[:person].delete(:password_confirmation) | ||
71 | + | ||
72 | + params[:person][:custom_values]={} | ||
73 | + params[:person].keys.each do |key| | ||
74 | + params[:person][:custom_values][key]=params[:person].delete(key) if Person.custom_fields(environment).any?{|cf| cf.name==key} | ||
75 | + end | ||
76 | + | ||
77 | + user = User.build(user_data, asset_with_image(params[:person]), environment) | ||
78 | + | ||
79 | + begin | ||
80 | + user.signup! | ||
81 | + rescue ActiveRecord::RecordInvalid | ||
82 | + render_api_errors!(user.errors.full_messages) | ||
83 | + end | ||
84 | + | ||
85 | + present user.person, :with => Entities::Person, :current_person => user.person | ||
86 | + end | ||
87 | + | ||
88 | + desc "Return the person friends" | ||
89 | + get ':id/friends' do | ||
90 | + person = environment.people.visible.find_by(id: params[:id]) | ||
91 | + return not_found! if person.blank? | ||
92 | + friends = person.friends.visible | ||
93 | + present friends, :with => Entities::Person, :current_person => current_person | ||
94 | + end | ||
95 | + | ||
96 | + desc "Return the person permissions on other profiles" | ||
97 | + get ":id/permissions" do | ||
98 | + authenticate! | ||
99 | + person = environment.people.find(params[:id]) | ||
100 | + return not_found! if person.blank? | ||
101 | + return forbidden! unless current_person == person || environment.admins.include?(current_person) | ||
102 | + | ||
103 | + output = {} | ||
104 | + person.role_assignments.map do |role_assigment| | ||
105 | + if role_assigment.resource.respond_to?(:identifier) | ||
106 | + output[role_assigment.resource.identifier] = role_assigment.role.permissions | ||
107 | + end | ||
108 | + end | ||
109 | + present output | ||
110 | + end | ||
111 | + end | ||
112 | + | ||
113 | + resource :profiles do | ||
114 | + segment '/:profile_id' do | ||
115 | + resource :members do | ||
116 | + paginate max_per_page: MAX_PER_PAGE | ||
117 | + get do | ||
118 | + profile = environment.profiles.find_by id: params[:profile_id] | ||
119 | + members = select_filtered_collection_of(profile, 'members', params) | ||
120 | + present members, :with => Entities::Person, :current_person => current_person | ||
121 | + end | ||
122 | + end | ||
123 | + end | ||
124 | + end | ||
125 | + end | ||
126 | + end | ||
127 | +end |
@@ -0,0 +1,42 @@ | @@ -0,0 +1,42 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Profiles < Grape::API | ||
4 | + | ||
5 | + resource :profiles do | ||
6 | + | ||
7 | + get do | ||
8 | + profiles = select_filtered_collection_of(environment, 'profiles', params) | ||
9 | + profiles = profiles.visible | ||
10 | + profiles = profiles.by_location(params) # Must be the last. May return Exception obj. | ||
11 | + present profiles, :with => Entities::Profile, :current_person => current_person | ||
12 | + end | ||
13 | + | ||
14 | + get ':id' do | ||
15 | + profiles = environment.profiles | ||
16 | + profiles = profiles.visible | ||
17 | + profile = profiles.find_by id: params[:id] | ||
18 | + | ||
19 | + if profile | ||
20 | + present profile, :with => Entities::Profile, :current_person => current_person | ||
21 | + else | ||
22 | + not_found! | ||
23 | + end | ||
24 | + end | ||
25 | + | ||
26 | + delete ':id' do | ||
27 | + authenticate! | ||
28 | + profiles = environment.profiles | ||
29 | + profile = profiles.find_by id: params[:id] | ||
30 | + | ||
31 | + not_found! if profile.blank? | ||
32 | + | ||
33 | + if current_person.has_permission?(:destroy_profile, profile) | ||
34 | + profile.destroy | ||
35 | + else | ||
36 | + forbidden! | ||
37 | + end | ||
38 | + end | ||
39 | + end | ||
40 | + end | ||
41 | + end | ||
42 | +end |
@@ -0,0 +1,37 @@ | @@ -0,0 +1,37 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Search < Grape::API | ||
4 | + | ||
5 | + resource :search do | ||
6 | + resource :article do | ||
7 | + paginate max_per_page: 200 | ||
8 | + get do | ||
9 | + # Security checks | ||
10 | + sanitize_params_hash(params) | ||
11 | + # Api::Helpers | ||
12 | + asset = :articles | ||
13 | + context = environment | ||
14 | + | ||
15 | + profile = environment.profiles.find(params[:profile_id]) if params[:profile_id] | ||
16 | + scope = profile.nil? ? environment.articles.is_public : profile.articles.is_public | ||
17 | + scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article') | ||
18 | + scope = scope.where(make_conditions_with_parameter(params)) | ||
19 | + scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present? | ||
20 | + scope = scope.where('articles.children_count > 0') if params[:has_children].present? | ||
21 | + query = params[:query] || "" | ||
22 | + order = "more_recent" | ||
23 | + | ||
24 | + options = {:filter => order, :template_id => params[:template_id]} | ||
25 | + | ||
26 | + search_result = find_by_contents(asset, context, scope, query, {:page => 1}, options) | ||
27 | + | ||
28 | + articles = search_result[:results] | ||
29 | + | ||
30 | + present_articles(articles) | ||
31 | + end | ||
32 | + end | ||
33 | + end | ||
34 | + | ||
35 | + end | ||
36 | + end | ||
37 | +end |
@@ -0,0 +1,157 @@ | @@ -0,0 +1,157 @@ | ||
1 | +require "uri" | ||
2 | + | ||
3 | +module Api | ||
4 | + module V1 | ||
5 | + class Session < Grape::API | ||
6 | + | ||
7 | + # Login to get token | ||
8 | + # | ||
9 | + # Parameters: | ||
10 | + # login (*required) - user login or email | ||
11 | + # password (required) - user password | ||
12 | + # | ||
13 | + # Example Request: | ||
14 | + # POST http://localhost:3000/api/v1/login?login=adminuser&password=admin | ||
15 | + post "/login" do | ||
16 | + begin | ||
17 | + user ||= User.authenticate(params[:login], params[:password], environment) | ||
18 | + rescue User::UserNotActivated => e | ||
19 | + render_api_error!(e.message, 401) | ||
20 | + end | ||
21 | + | ||
22 | + return unauthorized! unless user | ||
23 | + @current_user = user | ||
24 | + present user, :with => Entities::UserLogin, :current_person => current_person | ||
25 | + end | ||
26 | + | ||
27 | + post "/login_from_cookie" do | ||
28 | + return unauthorized! if cookies[:auth_token].blank? | ||
29 | + user = User.where(remember_token: cookies[:auth_token]).first | ||
30 | + return unauthorized! unless user && user.activated? | ||
31 | + @current_user = user | ||
32 | + present user, :with => Entities::UserLogin, :current_person => current_person | ||
33 | + end | ||
34 | + | ||
35 | + # Create user. | ||
36 | + # | ||
37 | + # Parameters: | ||
38 | + # email (required) - Email | ||
39 | + # password (required) - Password | ||
40 | + # login - login | ||
41 | + # Example Request: | ||
42 | + # POST /register?email=some@mail.com&password=pas&password_confirmation=pas&login=some | ||
43 | + params do | ||
44 | + requires :email, type: String, desc: _("Email") | ||
45 | + requires :login, type: String, desc: _("Login") | ||
46 | + requires :password, type: String, desc: _("Password") | ||
47 | + end | ||
48 | + | ||
49 | + post "/register" do | ||
50 | + attrs = attributes_for_keys [:email, :login, :password, :password_confirmation] + environment.signup_person_fields | ||
51 | + name = params[:name].present? ? params[:name] : attrs[:email] | ||
52 | + attrs[:password_confirmation] = attrs[:password] if !attrs.has_key?(:password_confirmation) | ||
53 | + user = User.new(attrs.merge(:name => name)) | ||
54 | + | ||
55 | + begin | ||
56 | + user.signup! | ||
57 | + user.generate_private_token! if user.activated? | ||
58 | + present user, :with => Entities::UserLogin, :current_person => user.person | ||
59 | + rescue ActiveRecord::RecordInvalid | ||
60 | + message = user.errors.as_json.merge((user.person.present? ? user.person.errors : {}).as_json).to_json | ||
61 | + render_api_error!(message, 400) | ||
62 | + end | ||
63 | + end | ||
64 | + | ||
65 | + params do | ||
66 | + requires :activation_code, type: String, desc: _("Activation token") | ||
67 | + end | ||
68 | + | ||
69 | + # Activate a user. | ||
70 | + # | ||
71 | + # Parameter: | ||
72 | + # activation_code (required) - Activation token | ||
73 | + # Example Request: | ||
74 | + # PATCH /activate?activation_code=28259abd12cc6a64ef9399cf3286cb998b96aeaf | ||
75 | + patch "/activate" do | ||
76 | + user = User.find_by activation_code: params[:activation_code] | ||
77 | + if user | ||
78 | + unless user.environment.enabled?('admin_must_approve_new_users') | ||
79 | + if user.activate | ||
80 | + user.generate_private_token! | ||
81 | + present user, :with => Entities::UserLogin, :current_person => current_person | ||
82 | + end | ||
83 | + else | ||
84 | + if user.create_moderate_task | ||
85 | + user.activation_code = nil | ||
86 | + user.save! | ||
87 | + | ||
88 | + # Waiting for admin moderate user registration | ||
89 | + status 202 | ||
90 | + body({ | ||
91 | + :message => 'Waiting for admin moderate user registration' | ||
92 | + }) | ||
93 | + end | ||
94 | + end | ||
95 | + else | ||
96 | + # Token not found in database | ||
97 | + render_api_error!(_('Token is invalid'), 412) | ||
98 | + end | ||
99 | + end | ||
100 | + | ||
101 | + # Request a new password. | ||
102 | + # | ||
103 | + # Parameters: | ||
104 | + # value (required) - Email or login | ||
105 | + # Example Request: | ||
106 | + # POST /forgot_password?value=some@mail.com | ||
107 | + post "/forgot_password" do | ||
108 | + requestors = fetch_requestors(params[:value]) | ||
109 | + not_found! if requestors.blank? | ||
110 | + remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR']) | ||
111 | + requestors.each do |requestor| | ||
112 | + ChangePassword.create!(:requestor => requestor) | ||
113 | + end | ||
114 | + end | ||
115 | + | ||
116 | + # Resend activation code. | ||
117 | + # | ||
118 | + # Parameters: | ||
119 | + # value (required) - Email or login | ||
120 | + # Example Request: | ||
121 | + # POST /resend_activation_code?value=some@mail.com | ||
122 | + post "/resend_activation_code" do | ||
123 | + requestors = fetch_requestors(params[:value]) | ||
124 | + not_found! if requestors.blank? | ||
125 | + remote_ip = (request.respond_to?(:remote_ip) && request.remote_ip) || (env && env['REMOTE_ADDR']) | ||
126 | + requestors.each do |requestor| | ||
127 | + requestor.user.resend_activation_code | ||
128 | + end | ||
129 | + present requestors.map(&:user), :with => Entities::UserLogin | ||
130 | + end | ||
131 | + | ||
132 | + params do | ||
133 | + requires :code, type: String, desc: _("Forgot password code") | ||
134 | + end | ||
135 | + # Change password | ||
136 | + # | ||
137 | + # Parameters: | ||
138 | + # code (required) - Change password code | ||
139 | + # password (required) | ||
140 | + # password_confirmation (required) | ||
141 | + # Example Request: | ||
142 | + # PATCH /new_password?code=xxxx&password=secret&password_confirmation=secret | ||
143 | + patch "/new_password" do | ||
144 | + change_password = ChangePassword.find_by code: params[:code] | ||
145 | + not_found! if change_password.nil? | ||
146 | + | ||
147 | + if change_password.update_attributes(:password => params[:password], :password_confirmation => params[:password_confirmation]) | ||
148 | + change_password.finish | ||
149 | + present change_password.requestor.user, :with => Entities::UserLogin, :current_person => current_person | ||
150 | + else | ||
151 | + something_wrong! | ||
152 | + end | ||
153 | + end | ||
154 | + | ||
155 | + end | ||
156 | + end | ||
157 | +end |
@@ -0,0 +1,30 @@ | @@ -0,0 +1,30 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Tags < Grape::API | ||
4 | + resource :articles do | ||
5 | + resource ':id/tags' do | ||
6 | + get do | ||
7 | + article = find_article(environment.articles, params[:id]) | ||
8 | + present article.tag_list | ||
9 | + end | ||
10 | + | ||
11 | + desc "Add a tag to an article" | ||
12 | + post do | ||
13 | + authenticate! | ||
14 | + article = find_article(environment.articles, params[:id]) | ||
15 | + article.tag_list=params[:tags] | ||
16 | + article.save | ||
17 | + present article.tag_list | ||
18 | + end | ||
19 | + end | ||
20 | + end | ||
21 | + | ||
22 | + resource :environment do | ||
23 | + desc 'Return the tag counts for this environment' | ||
24 | + get '/tags' do | ||
25 | + present environment.tag_counts | ||
26 | + end | ||
27 | + end | ||
28 | + end | ||
29 | + end | ||
30 | +end |
@@ -0,0 +1,57 @@ | @@ -0,0 +1,57 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Tasks < Grape::API | ||
4 | +# before { authenticate! } | ||
5 | + | ||
6 | +# ARTICLE_TYPES = Article.descendants.map{|a| a.to_s} | ||
7 | + | ||
8 | + resource :tasks do | ||
9 | + | ||
10 | + # Collect tasks | ||
11 | + # | ||
12 | + # 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 | + # oldest - Collect the oldest articles. If nothing is passed the newest articles are collected | ||
15 | + # limit - amount of articles returned. The default value is 20 | ||
16 | + # | ||
17 | + # 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 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 | ||
23 | + end | ||
24 | + | ||
25 | + desc "Return the task id" | ||
26 | + get ':id' do | ||
27 | + task = find_task(environment, params[:id]) | ||
28 | + present_partial task, :with => Entities::Task | ||
29 | + end | ||
30 | + end | ||
31 | + | ||
32 | + kinds = %w[community person enterprise] | ||
33 | + kinds.each do |kind| | ||
34 | + resource kind.pluralize.to_sym do | ||
35 | + segment "/:#{kind}_id" do | ||
36 | + resource :tasks do | ||
37 | + get do | ||
38 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
39 | + present_tasks(profile) | ||
40 | + end | ||
41 | + | ||
42 | + get ':id' do | ||
43 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
44 | + present_task(profile) | ||
45 | + end | ||
46 | + | ||
47 | + post do | ||
48 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | ||
49 | + post_task(profile, params) | ||
50 | + end | ||
51 | + end | ||
52 | + end | ||
53 | + end | ||
54 | + end | ||
55 | + end | ||
56 | + end | ||
57 | +end |
@@ -0,0 +1,43 @@ | @@ -0,0 +1,43 @@ | ||
1 | +module Api | ||
2 | + module V1 | ||
3 | + class Users < Grape::API | ||
4 | + | ||
5 | + resource :users do | ||
6 | + | ||
7 | + get do | ||
8 | + users = select_filtered_collection_of(environment, 'users', params) | ||
9 | + users = users.select{|u| u.person.display_info_to? current_person} | ||
10 | + present users, :with => Entities::User, :current_person => current_person | ||
11 | + end | ||
12 | + | ||
13 | + get "/me" do | ||
14 | + authenticate! | ||
15 | + present current_user, :with => Entities::User, :current_person => current_person | ||
16 | + end | ||
17 | + | ||
18 | + get ":id" do | ||
19 | + user = environment.users.find_by id: params[:id] | ||
20 | + if user | ||
21 | + present user, :with => Entities::User, :current_person => current_person | ||
22 | + else | ||
23 | + not_found! | ||
24 | + end | ||
25 | + end | ||
26 | + | ||
27 | + get ":id/permissions" do | ||
28 | + authenticate! | ||
29 | + user = environment.users.find(params[:id]) | ||
30 | + output = {} | ||
31 | + user.person.role_assignments.map do |role_assigment| | ||
32 | + if role_assigment.resource.respond_to?(:identifier) && role_assigment.resource.identifier == params[:profile] | ||
33 | + output[:permissions] = role_assigment.role.permissions | ||
34 | + end | ||
35 | + end | ||
36 | + present output | ||
37 | + end | ||
38 | + | ||
39 | + end | ||
40 | + | ||
41 | + end | ||
42 | + end | ||
43 | +end |
app/controllers/admin/categories_controller.rb
@@ -7,7 +7,6 @@ class CategoriesController < AdminController | @@ -7,7 +7,6 @@ class CategoriesController < AdminController | ||
7 | def index | 7 | def index |
8 | @categories = environment.categories.where("parent_id is null AND type is null") | 8 | @categories = environment.categories.where("parent_id is null AND type is null") |
9 | @regions = environment.regions.where(:parent_id => nil) | 9 | @regions = environment.regions.where(:parent_id => nil) |
10 | - @product_categories = environment.product_categories.where(:parent_id => nil) | ||
11 | end | 10 | end |
12 | 11 | ||
13 | def get_children | 12 | def get_children |
app/controllers/admin/edit_template_controller.rb
1 | class EditTemplateController < AdminController | 1 | class EditTemplateController < AdminController |
2 | - | 2 | + |
3 | protect 'edit_environment_design', :environment | 3 | protect 'edit_environment_design', :environment |
4 | - | 4 | + |
5 | #FIXME | 5 | #FIXME |
6 | #design_editor :holder => 'environment', :autosave => true, :block_types => :block_types | 6 | #design_editor :holder => 'environment', :autosave => true, :block_types => :block_types |
7 | 7 | ||
@@ -9,7 +9,6 @@ class EditTemplateController < AdminController | @@ -9,7 +9,6 @@ class EditTemplateController < AdminController | ||
9 | %w[ | 9 | %w[ |
10 | FavoriteLinks | 10 | FavoriteLinks |
11 | ListBlock | 11 | ListBlock |
12 | - SellersSearchBlock | ||
13 | ] | 12 | ] |
14 | end | 13 | end |
15 | 14 |
app/controllers/admin/environment_design_controller.rb
1 | class EnvironmentDesignController < BoxOrganizerController | 1 | class EnvironmentDesignController < BoxOrganizerController |
2 | - | 2 | + |
3 | protect 'edit_environment_design', :environment | 3 | protect 'edit_environment_design', :environment |
4 | 4 | ||
5 | def available_blocks | 5 | def available_blocks |
6 | - @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, SellersSearchBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, FeaturedProductsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ] | 6 | + @available_blocks ||= [ ArticleBlock, LoginBlock, RecentDocumentsBlock, EnterprisesBlock, CommunitiesBlock, LinkListBlock, FeedReaderBlock, SlideshowBlock, HighlightsBlock, CategoriesBlock, RawHTMLBlock, TagsBlock ] |
7 | @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment) | 7 | @available_blocks += plugins.dispatch(:extra_blocks, :type => Environment) |
8 | end | 8 | end |
9 | 9 |
app/controllers/admin/users_controller.rb
@@ -45,7 +45,6 @@ class UsersController < AdminController | @@ -45,7 +45,6 @@ class UsersController < AdminController | ||
45 | redirect_to :action => :index, :q => params[:q], :filter => params[:filter] | 45 | redirect_to :action => :index, :q => params[:q], :filter => params[:filter] |
46 | end | 46 | end |
47 | 47 | ||
48 | - | ||
49 | def destroy_user | 48 | def destroy_user |
50 | if request.post? | 49 | if request.post? |
51 | person = environment.people.find_by id: params[:id] | 50 | person = environment.people.find_by id: params[:id] |
@@ -58,7 +57,6 @@ class UsersController < AdminController | @@ -58,7 +57,6 @@ class UsersController < AdminController | ||
58 | redirect_to :action => :index, :q => params[:q], :filter => params[:filter] | 57 | redirect_to :action => :index, :q => params[:q], :filter => params[:filter] |
59 | end | 58 | end |
60 | 59 | ||
61 | - | ||
62 | def download | 60 | def download |
63 | respond_to do |format| | 61 | respond_to do |format| |
64 | format.html | 62 | format.html |
@@ -87,8 +85,11 @@ class UsersController < AdminController | @@ -87,8 +85,11 @@ class UsersController < AdminController | ||
87 | end | 85 | end |
88 | 86 | ||
89 | def send_mail | 87 | def send_mail |
90 | - @mailing = environment.mailings.build(params[:mailing]) | ||
91 | if request.post? | 88 | if request.post? |
89 | + @mailing = environment.mailings.build(params[:mailing]) | ||
90 | + @mailing.recipients_roles = [] | ||
91 | + @mailing.recipients_roles << "profile_admin" if params[:recipients][:profile_admins].include?("true") | ||
92 | + @mailing.recipients_roles << "environment_administrator" if params[:recipients][:env_admins].include?("true") | ||
92 | @mailing.locale = locale | 93 | @mailing.locale = locale |
93 | @mailing.person = user | 94 | @mailing.person = user |
94 | if @mailing.save | 95 | if @mailing.save |
app/controllers/my_profile/cms_controller.rb
@@ -103,12 +103,10 @@ class CmsController < MyProfileController | @@ -103,12 +103,10 @@ class CmsController < MyProfileController | ||
103 | end | 103 | end |
104 | end | 104 | end |
105 | end | 105 | end |
106 | - | ||
107 | - escape_fields @article | ||
108 | end | 106 | end |
109 | 107 | ||
110 | def new | 108 | def new |
111 | - # FIXME this method should share some logic wirh edit !!! | 109 | + # FIXME this method should share some logic with edit !!! |
112 | 110 | ||
113 | @success_back_to = params[:success_back_to] | 111 | @success_back_to = params[:success_back_to] |
114 | # user must choose an article type first | 112 | # user must choose an article type first |
@@ -174,9 +172,6 @@ class CmsController < MyProfileController | @@ -174,9 +172,6 @@ class CmsController < MyProfileController | ||
174 | return | 172 | return |
175 | end | 173 | end |
176 | end | 174 | end |
177 | - | ||
178 | - escape_fields @article | ||
179 | - | ||
180 | render :action => 'edit' | 175 | render :action => 'edit' |
181 | end | 176 | end |
182 | 177 | ||
@@ -365,7 +360,7 @@ class CmsController < MyProfileController | @@ -365,7 +360,7 @@ class CmsController < MyProfileController | ||
365 | def search | 360 | def search |
366 | query = params[:q] | 361 | query = params[:q] |
367 | results = find_by_contents(:uploaded_files, profile, profile.files.published, query)[:results] | 362 | results = find_by_contents(:uploaded_files, profile, profile.files.published, query)[:results] |
368 | - render :text => article_list_to_json(results), :content_type => 'application/json' | 363 | + render :text => article_list_to_json(results).html_safe, :content_type => 'application/json' |
369 | end | 364 | end |
370 | 365 | ||
371 | def search_article_privacy_exceptions | 366 | def search_article_privacy_exceptions |
@@ -409,9 +404,6 @@ class CmsController < MyProfileController | @@ -409,9 +404,6 @@ class CmsController < MyProfileController | ||
409 | ] | 404 | ] |
410 | articles += special_article_types if params && params[:cms] | 405 | articles += special_article_types if params && params[:cms] |
411 | parent_id = params ? params[:parent_id] : nil | 406 | parent_id = params ? params[:parent_id] : nil |
412 | - if profile.enterprise? | ||
413 | - articles << EnterpriseHomepage | ||
414 | - end | ||
415 | if @parent && @parent.blog? | 407 | if @parent && @parent.blog? |
416 | articles -= Article.folder_types.map(&:constantize) | 408 | articles -= Article.folder_types.map(&:constantize) |
417 | end | 409 | end |
@@ -451,9 +443,7 @@ class CmsController < MyProfileController | @@ -451,9 +443,7 @@ class CmsController < MyProfileController | ||
451 | end | 443 | end |
452 | 444 | ||
453 | def refuse_blocks | 445 | def refuse_blocks |
454 | - if ['TinyMceArticle', 'TextileArticle', 'Event', 'EnterpriseHomepage'].include?(@type) | ||
455 | - @no_design_blocks = true | ||
456 | - end | 446 | + @no_design_blocks = @type.present? && valid_article_type?(@type) ? !@type.constantize.can_display_blocks? : false |
457 | end | 447 | end |
458 | 448 | ||
459 | def per_page | 449 | def per_page |
@@ -521,10 +511,4 @@ class CmsController < MyProfileController | @@ -521,10 +511,4 @@ class CmsController < MyProfileController | ||
521 | end | 511 | end |
522 | end | 512 | end |
523 | 513 | ||
524 | - def escape_fields article | ||
525 | - unless article.kind_of?(RssFeed) | ||
526 | - @escaped_body = CGI::escapeHTML(article.body || '') | ||
527 | - @escaped_abstract = CGI::escapeHTML(article.abstract || '') | ||
528 | - end | ||
529 | - end | ||
530 | end | 514 | end |
app/controllers/my_profile/profile_design_controller.rb
@@ -45,17 +45,10 @@ class ProfileDesignController < BoxOrganizerController | @@ -45,17 +45,10 @@ class ProfileDesignController < BoxOrganizerController | ||
45 | if profile.enterprise? | 45 | if profile.enterprise? |
46 | blocks << DisabledEnterpriseMessageBlock | 46 | blocks << DisabledEnterpriseMessageBlock |
47 | blocks << HighlightsBlock | 47 | blocks << HighlightsBlock |
48 | - blocks << ProductCategoriesBlock | ||
49 | - blocks << FeaturedProductsBlock | ||
50 | blocks << FansBlock | 48 | blocks << FansBlock |
51 | blocks += plugins.dispatch(:extra_blocks, :type => Enterprise) | 49 | blocks += plugins.dispatch(:extra_blocks, :type => Enterprise) |
52 | end | 50 | end |
53 | 51 | ||
54 | - # product block exclusive for enterprises in environments that permits it | ||
55 | - if profile.enterprise? && profile.environment.enabled?('products_for_enterprises') | ||
56 | - blocks << ProductsBlock | ||
57 | - end | ||
58 | - | ||
59 | # block exclusive to profiles that have blog | 52 | # block exclusive to profiles that have blog |
60 | if profile.has_blog? | 53 | if profile.has_blog? |
61 | blocks << BlogArchivesBlock | 54 | blocks << BlogArchivesBlock |
app/controllers/my_profile/profile_editor_controller.rb
@@ -29,6 +29,7 @@ class ProfileEditorController < MyProfileController | @@ -29,6 +29,7 @@ class ProfileEditorController < MyProfileController | ||
29 | Image.transaction do | 29 | Image.transaction do |
30 | begin | 30 | begin |
31 | @plugins.dispatch(:profile_editor_transaction_extras) | 31 | @plugins.dispatch(:profile_editor_transaction_extras) |
32 | + # TODO: This is unsafe! Add sanitizer | ||
32 | @profile_data.update!(params[:profile_data]) | 33 | @profile_data.update!(params[:profile_data]) |
33 | redirect_to :action => 'index', :profile => profile.identifier | 34 | redirect_to :action => 'index', :profile => profile.identifier |
34 | rescue Exception => ex | 35 | rescue Exception => ex |
app/controllers/my_profile/tasks_controller.rb
@@ -14,20 +14,23 @@ class TasksController < MyProfileController | @@ -14,20 +14,23 @@ 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 | - | ||
18 | - @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc') | 17 | + @tasks = Task.pending_all(profile, @filter_type, @filter_text).order_by('created_at', 'asc').paginate(:per_page => Task.per_page, :page => params[:page]) |
19 | @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? |
20 | @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) | 19 | @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) |
21 | - | ||
22 | @failed = params ? params[:failed] : {} | 20 | @failed = params ? params[:failed] : {} |
23 | 21 | ||
24 | @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization? | 22 | @responsible_candidates = profile.members.by_role(profile.roles.reject {|r| !r.has_permission?('perform_task')}) if profile.organization? |
25 | 23 | ||
26 | @view_only = !current_person.has_permission?(:perform_task, profile) | 24 | @view_only = !current_person.has_permission?(:perform_task, profile) |
25 | + | ||
27 | end | 26 | end |
28 | 27 | ||
29 | def processed | 28 | def processed |
30 | - @tasks = Task.to(profile).without_spam.closed.sort_by(&:created_at) | 29 | + @tasks = Task.to(profile).without_spam.closed.order('tasks.created_at DESC') |
30 | + @filter = params[:filter] || {} | ||
31 | + @tasks = filter_tasks(@filter, @tasks) | ||
32 | + @tasks = @tasks.paginate(:per_page => Task.per_page, :page => params[:page]) | ||
33 | + @task_types = Task.closed_types_for(profile) | ||
31 | end | 34 | end |
32 | 35 | ||
33 | def change_responsible | 36 | def change_responsible |
@@ -95,4 +98,36 @@ class TasksController < MyProfileController | @@ -95,4 +98,36 @@ class TasksController < MyProfileController | ||
95 | @ticket = Ticket.where('(requestor_id = ? or target_id = ?) and id = ?', profile.id, profile.id, params[:id]).first | 98 | @ticket = Ticket.where('(requestor_id = ? or target_id = ?) and id = ?', profile.id, profile.id, params[:id]).first |
96 | end | 99 | end |
97 | 100 | ||
101 | + def search_tasks | ||
102 | + filter_type = params[:filter_type].presence | ||
103 | + filter_text = params[:filter_text].presence | ||
104 | + result = Task.pending_all(profile,filter_type, filter_text) | ||
105 | + | ||
106 | + render :json => result.map { |task| {:label => task.data[:name], :value => task.data[:name]} } | ||
107 | + end | ||
108 | + | ||
109 | + protected | ||
110 | + | ||
111 | + def filter_tasks(filter, tasks) | ||
112 | + tasks = tasks.eager_load(:requestor, :closed_by) | ||
113 | + tasks = tasks.of(filter[:type].presence) | ||
114 | + tasks = tasks.where(:status => filter[:status]) unless filter[:status].blank? | ||
115 | + | ||
116 | + filter[:created_from] = Date.parse(filter[:created_from]) unless filter[:created_from].blank? | ||
117 | + filter[:created_until] = Date.parse(filter[:created_until]) unless filter[:created_until].blank? | ||
118 | + filter[:closed_from] = Date.parse(filter[:closed_from]) unless filter[:closed_from].blank? | ||
119 | + filter[:closed_until] = Date.parse(filter[:closed_until]) unless filter[:closed_until].blank? | ||
120 | + | ||
121 | + tasks = tasks.from_creation_date filter[:created_from] unless filter[:created_from].blank? | ||
122 | + tasks = tasks.until_creation_date filter[:created_until] unless filter[:created_until].blank? | ||
123 | + | ||
124 | + tasks = tasks.from_closed_date filter[:closed_from] unless filter[:closed_from].blank? | ||
125 | + tasks = tasks.until_closed_date filter[:closed_until] unless filter[:closed_until].blank? | ||
126 | + | ||
127 | + tasks = tasks.where('profiles.name LIKE ?', filter[:requestor]) unless filter[:requestor].blank? | ||
128 | + tasks = tasks.where('closed_bies_tasks.name LIKE ?', filter[:closed_by]) unless filter[:closed_by].blank? | ||
129 | + tasks = tasks.where('tasks.data LIKE ?', "%#{filter[:text]}%") unless filter[:text].blank? | ||
130 | + tasks | ||
131 | + end | ||
132 | + | ||
98 | end | 133 | end |
app/controllers/public/api_controller.rb
app/controllers/public/profile_controller.rb
@@ -86,8 +86,16 @@ class ProfileController < PublicController | @@ -86,8 +86,16 @@ class ProfileController < PublicController | ||
86 | @articles = profile.top_level_articles.includes([:profile, :parent]) | 86 | @articles = profile.top_level_articles.includes([:profile, :parent]) |
87 | end | 87 | end |
88 | 88 | ||
89 | + def join_modal | ||
90 | + profile.add_member(user) | ||
91 | + session[:notice] = _('%s administrator still needs to accept you as member.') % profile.name | ||
92 | + redirect_to :action => :index | ||
93 | + end | ||
94 | + | ||
89 | def join | 95 | def join |
90 | if !user.memberships.include?(profile) | 96 | if !user.memberships.include?(profile) |
97 | + return if profile.community? && show_confirmation_modal?(profile) | ||
98 | + | ||
91 | profile.add_member(user) | 99 | profile.add_member(user) |
92 | if !profile.members.include?(user) | 100 | if !profile.members.include?(user) |
93 | render :text => {:message => _('%s administrator still needs to accept you as member.') % profile.name}.to_json | 101 | render :text => {:message => _('%s administrator still needs to accept you as member.') % profile.name}.to_json |
app/controllers/public/search_controller.rb
@@ -3,7 +3,10 @@ class SearchController < PublicController | @@ -3,7 +3,10 @@ class SearchController < PublicController | ||
3 | helper TagsHelper | 3 | helper TagsHelper |
4 | include SearchHelper | 4 | include SearchHelper |
5 | include ActionView::Helpers::NumberHelper | 5 | include ActionView::Helpers::NumberHelper |
6 | + include SanitizeParams | ||
6 | 7 | ||
8 | + | ||
9 | + before_filter :sanitize_params | ||
7 | before_filter :redirect_asset_param, :except => [:assets, :suggestions] | 10 | before_filter :redirect_asset_param, :except => [:assets, :suggestions] |
8 | before_filter :load_category, :except => :suggestions | 11 | before_filter :load_category, :except => :suggestions |
9 | before_filter :load_search_assets, :except => :suggestions | 12 | before_filter :load_search_assets, :except => :suggestions |
@@ -49,7 +52,6 @@ class SearchController < PublicController | @@ -49,7 +52,6 @@ class SearchController < PublicController | ||
49 | [ | 52 | [ |
50 | [ :people, _('People'), :recent_people ], | 53 | [ :people, _('People'), :recent_people ], |
51 | [ :enterprises, _('Enterprises'), :recent_enterprises ], | 54 | [ :enterprises, _('Enterprises'), :recent_enterprises ], |
52 | - [ :products, _('Products'), :recent_products ], | ||
53 | [ :events, _('Upcoming events'), :upcoming_events ], | 55 | [ :events, _('Upcoming events'), :upcoming_events ], |
54 | [ :communities, _('Communities'), :recent_communities ], | 56 | [ :communities, _('Communities'), :recent_communities ], |
55 | [ :articles, _('Contents'), :recent_articles ] | 57 | [ :articles, _('Contents'), :recent_articles ] |
@@ -75,16 +77,17 @@ class SearchController < PublicController | @@ -75,16 +77,17 @@ class SearchController < PublicController | ||
75 | full_text_search | 77 | full_text_search |
76 | end | 78 | end |
77 | 79 | ||
78 | - def products | ||
79 | - @scope = @environment.products | ||
80 | - full_text_search | ||
81 | - end | ||
82 | - | ||
83 | def enterprises | 80 | def enterprises |
84 | @scope = visible_profiles(Enterprise) | 81 | @scope = visible_profiles(Enterprise) |
85 | full_text_search | 82 | full_text_search |
86 | end | 83 | end |
87 | 84 | ||
85 | + # keep URL compatibility | ||
86 | + def products | ||
87 | + return render_not_found unless defined? ProductsPlugin | ||
88 | + redirect_to url_for(params.merge controller: 'products_plugin/search', action: :products) | ||
89 | + end | ||
90 | + | ||
88 | def communities | 91 | def communities |
89 | @scope = visible_profiles(Community) | 92 | @scope = visible_profiles(Community) |
90 | full_text_search | 93 | full_text_search |
@@ -134,7 +137,8 @@ class SearchController < PublicController | @@ -134,7 +137,8 @@ class SearchController < PublicController | ||
134 | 137 | ||
135 | def tag | 138 | def tag |
136 | @tag = params[:tag] | 139 | @tag = params[:tag] |
137 | - @tag_cache_key = "tag_#{CGI.escape(@tag.to_s)}_env_#{environment.id.to_s}_page_#{params[:npage]}" | 140 | + tag_str = @tag.kind_of?(Array) ? @tag.join(" ") : @tag.to_str |
141 | + @tag_cache_key = "tag_#{CGI.escape(tag_str)}_env_#{environment.id.to_s}_page_#{params[:npage]}" | ||
138 | if is_cache_expired?(@tag_cache_key) | 142 | if is_cache_expired?(@tag_cache_key) |
139 | @searches[@asset] = {:results => environment.articles.tagged_with(@tag).paginate(paginate_options)} | 143 | @searches[@asset] = {:results => environment.articles.tagged_with(@tag).paginate(paginate_options)} |
140 | end | 144 | end |
@@ -182,7 +186,6 @@ class SearchController < PublicController | @@ -182,7 +186,6 @@ class SearchController < PublicController | ||
182 | people: _('People'), | 186 | people: _('People'), |
183 | communities: _('Communities'), | 187 | communities: _('Communities'), |
184 | enterprises: _('Enterprises'), | 188 | enterprises: _('Enterprises'), |
185 | - products: _('Products and Services'), | ||
186 | events: _('Events'), | 189 | events: _('Events'), |
187 | } | 190 | } |
188 | end | 191 | end |
@@ -256,12 +259,11 @@ class SearchController < PublicController | @@ -256,12 +259,11 @@ class SearchController < PublicController | ||
256 | end | 259 | end |
257 | 260 | ||
258 | def available_assets | 261 | def available_assets |
259 | - assets = { | 262 | + { |
260 | articles: _('Contents'), | 263 | articles: _('Contents'), |
261 | enterprises: _('Enterprises'), | 264 | enterprises: _('Enterprises'), |
262 | people: _('People'), | 265 | people: _('People'), |
263 | communities: _('Communities'), | 266 | communities: _('Communities'), |
264 | - products: _('Products and Services'), | ||
265 | } | 267 | } |
266 | end | 268 | end |
267 | 269 |
app/helpers/action_tracker_helper.rb
@@ -5,22 +5,22 @@ module ActionTrackerHelper | @@ -5,22 +5,22 @@ module ActionTrackerHelper | ||
5 | end | 5 | end |
6 | 6 | ||
7 | def new_friendship_description ta | 7 | def new_friendship_description ta |
8 | - n_('has made 1 new friend:<br />%{name}', 'has made %{num} new friends:<br />%{name}', ta.get_friend_name.size) % { | 8 | + n_('has made 1 new friend:<br />%{name}', 'has made %{num} new friends:<br />%{name}', ta.get_friend_name.size).html_safe % { |
9 | num: ta.get_friend_name.size, | 9 | num: ta.get_friend_name.size, |
10 | - name: ta.collect_group_with_index(:friend_name) do |n,i| | 10 | + name: safe_join(ta.collect_group_with_index(:friend_name) do |n,i| |
11 | link_to image_tag(ta.get_friend_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")), | 11 | link_to image_tag(ta.get_friend_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/person-icon.png")), |
12 | ta.get_friend_url[i], title: n | 12 | ta.get_friend_url[i], title: n |
13 | - end.join | 13 | + end) |
14 | } | 14 | } |
15 | end | 15 | end |
16 | 16 | ||
17 | def join_community_description ta | 17 | def join_community_description ta |
18 | - n_('has joined 1 community:<br />%{name}', 'has joined %{num} communities:<br />%{name}', ta.get_resource_name.size) % { | 18 | + n_('has joined 1 community:<br />%{name}'.html_safe, 'has joined %{num} communities:<br />%{name}'.html_safe, ta.get_resource_name.size) % { |
19 | num: ta.get_resource_name.size, | 19 | num: ta.get_resource_name.size, |
20 | name: ta.collect_group_with_index(:resource_name) do |n,i| | 20 | name: ta.collect_group_with_index(:resource_name) do |n,i| |
21 | - link_to image_tag(ta.get_resource_profile_custom_icon[i] || default_or_themed_icon("/images/icons-app/community-icon.png")), | 21 | + 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 | 22 | ta.get_resource_url[i], title: n |
23 | - end.join | 23 | + end.join.html_safe |
24 | } | 24 | } |
25 | end | 25 | end |
26 | 26 | ||
@@ -67,24 +67,6 @@ module ActionTrackerHelper | @@ -67,24 +67,6 @@ module ActionTrackerHelper | ||
67 | } | 67 | } |
68 | end | 68 | end |
69 | 69 | ||
70 | - def create_product_description ta | ||
71 | - _('created the product %{title}') % { | ||
72 | - title: link_to(truncate(ta.get_name), ta.get_url), | ||
73 | - } | ||
74 | - end | ||
75 | - | ||
76 | - def update_product_description ta | ||
77 | - _('updated the product %{title}') % { | ||
78 | - title: link_to(truncate(ta.get_name), ta.get_url), | ||
79 | - } | ||
80 | - end | ||
81 | - | ||
82 | - def remove_product_description ta | ||
83 | - _('removed the product %{title}') % { | ||
84 | - title: truncate(ta.get_name), | ||
85 | - } | ||
86 | - end | ||
87 | - | ||
88 | def favorite_enterprise_description ta | 70 | def favorite_enterprise_description ta |
89 | _('favorited enterprise %{title}') % { | 71 | _('favorited enterprise %{title}') % { |
90 | title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url), | 72 | title: link_to(truncate(ta.get_enterprise_name), ta.get_enterprise_url), |
app/helpers/application_helper.rb
@@ -44,8 +44,6 @@ module ApplicationHelper | @@ -44,8 +44,6 @@ module ApplicationHelper | ||
44 | 44 | ||
45 | include TokenHelper | 45 | include TokenHelper |
46 | 46 | ||
47 | - include CatalogHelper | ||
48 | - | ||
49 | include PluginsHelper | 47 | include PluginsHelper |
50 | 48 | ||
51 | include ButtonsHelper | 49 | include ButtonsHelper |
@@ -56,6 +54,8 @@ module ApplicationHelper | @@ -56,6 +54,8 @@ module ApplicationHelper | ||
56 | 54 | ||
57 | include TaskHelper | 55 | include TaskHelper |
58 | 56 | ||
57 | + include MembershipsHelper | ||
58 | + | ||
59 | def locale | 59 | def locale |
60 | (@page && !@page.language.blank?) ? @page.language : FastGettext.locale | 60 | (@page && !@page.language.blank?) ? @page.language : FastGettext.locale |
61 | end | 61 | end |
@@ -99,7 +99,6 @@ module ApplicationHelper | @@ -99,7 +99,6 @@ module ApplicationHelper | ||
99 | # | 99 | # |
100 | # TODO: implement correcly the 'Help' button click | 100 | # TODO: implement correcly the 'Help' button click |
101 | def help(content = nil, link_name = nil, options = {}, &block) | 101 | def help(content = nil, link_name = nil, options = {}, &block) |
102 | - | ||
103 | link_name ||= _('Help') | 102 | link_name ||= _('Help') |
104 | 103 | ||
105 | @help_message_id ||= 1 | 104 | @help_message_id ||= 1 |
@@ -122,7 +121,7 @@ module ApplicationHelper | @@ -122,7 +121,7 @@ module ApplicationHelper | ||
122 | button = link_to_function(content_tag('span', link_name), "Element.show('#{help_id}')", options ) | 121 | button = link_to_function(content_tag('span', link_name), "Element.show('#{help_id}')", options ) |
123 | close_button = content_tag("div", link_to_function(_("Close"), "Element.hide('#{help_id}')", :class => 'close_help_button')) | 122 | close_button = content_tag("div", link_to_function(_("Close"), "Element.hide('#{help_id}')", :class => 'close_help_button')) |
124 | 123 | ||
125 | - text = content_tag('div', button + content_tag('div', content_tag('div', content) + close_button, :class => 'help_message', :id => help_id, :style => 'display: none;'), :class => 'help_box') | 124 | + text = content_tag('div', button + content_tag('div', content_tag('div', content.html_safe) + close_button, :class => 'help_message', :id => help_id, :style => 'display: none;'), :class => 'help_box') |
126 | 125 | ||
127 | unless block.nil? | 126 | unless block.nil? |
128 | concat(text) | 127 | concat(text) |
@@ -234,13 +233,6 @@ module ApplicationHelper | @@ -234,13 +233,6 @@ module ApplicationHelper | ||
234 | link_to(content_tag('span', text), url, html_options.merge(:class => the_class, :title => text)) | 233 | link_to(content_tag('span', text), url, html_options.merge(:class => the_class, :title => text)) |
235 | end | 234 | end |
236 | 235 | ||
237 | - def button_bar(options = {}, &block) | ||
238 | - options[:class].nil? ? | ||
239 | - options[:class]='button-bar' : | ||
240 | - options[:class]+=' button-bar' | ||
241 | - concat(content_tag('div', capture(&block).to_s + tag('br', :style => 'clear: left;'), options)) | ||
242 | - end | ||
243 | - | ||
244 | def render_profile_actions klass | 236 | def render_profile_actions klass |
245 | name = klass.to_s.underscore | 237 | name = klass.to_s.underscore |
246 | begin | 238 | begin |
@@ -362,8 +354,8 @@ module ApplicationHelper | @@ -362,8 +354,8 @@ module ApplicationHelper | ||
362 | def popover_menu(title,menu_title,links,html_options={}) | 354 | def popover_menu(title,menu_title,links,html_options={}) |
363 | html_options[:class] = "" unless html_options[:class] | 355 | html_options[:class] = "" unless html_options[:class] |
364 | html_options[:class] << " menu-submenu-trigger" | 356 | html_options[:class] << " menu-submenu-trigger" |
365 | - html_options[:onclick] = "toggleSubmenu(this, '#{menu_title}', #{CGI::escapeHTML(links.to_json)}); return false" | ||
366 | 357 | ||
358 | + html_options[:onclick] = "toggleSubmenu(this, '#{menu_title}', #{CGI::escapeHTML(links.to_json)}); return false".html_safe | ||
367 | link_to(content_tag(:span, title), '#', html_options) | 359 | link_to(content_tag(:span, title), '#', html_options) |
368 | end | 360 | end |
369 | 361 | ||
@@ -473,9 +465,9 @@ module ApplicationHelper | @@ -473,9 +465,9 @@ module ApplicationHelper | ||
473 | map(&:role) | 465 | map(&:role) |
474 | names = [] | 466 | names = [] |
475 | roles.each do |role| | 467 | roles.each do |role| |
476 | - names << content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}") | 468 | + names << content_tag('span', role.name, :style => "color: #{role_color(role, resource.environment.id)}").html_safe |
477 | end | 469 | end |
478 | - names.join(', ') | 470 | + safe_join(names, ', ') |
479 | end | 471 | end |
480 | 472 | ||
481 | def role_color(role, env_id) | 473 | def role_color(role, env_id) |
@@ -788,7 +780,7 @@ module ApplicationHelper | @@ -788,7 +780,7 @@ module ApplicationHelper | ||
788 | return "" if categories.blank? | 780 | return "" if categories.blank? |
789 | content_tag(:ul) do | 781 | content_tag(:ul) do |
790 | categories.map do |category| | 782 | categories.map do |category| |
791 | - category_path = category.kind_of?(ProductCategory) ? {:controller => 'search', :action => 'assets', :asset => 'products', :product_category => category.id} : { :controller => 'search', :action => 'category_index', :category_path => category.explode_path } | 783 | + category_path = { :controller => 'search', :action => 'category_index', :category_path => category.explode_path } |
792 | if category.display_in_menu? | 784 | if category.display_in_menu? |
793 | content_tag(:li) do | 785 | content_tag(:li) do |
794 | if !category.is_leaf_displayable_in_menu? | 786 | if !category.is_leaf_displayable_in_menu? |
@@ -911,7 +903,8 @@ module ApplicationHelper | @@ -911,7 +903,8 @@ module ApplicationHelper | ||
911 | end | 903 | end |
912 | 904 | ||
913 | def admin_link | 905 | def admin_link |
914 | - user.is_admin?(environment) ? link_to('<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>', environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') : '' | 906 | + admin_icon = '<i class="icon-menu-admin"></i><strong>' + _('Administration') + '</strong>' |
907 | + user.is_admin?(environment) ? link_to(admin_icon.html_safe, environment.admin_url, :title => _("Configure the environment"), :class => 'admin-link') : '' | ||
915 | end | 908 | end |
916 | 909 | ||
917 | def usermenu_logged_in | 910 | def usermenu_logged_in |
@@ -920,23 +913,39 @@ module ApplicationHelper | @@ -920,23 +913,39 @@ module ApplicationHelper | ||
920 | if count > 0 | 913 | if count > 0 |
921 | pending_tasks_count = link_to(count.to_s, user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) | 914 | pending_tasks_count = link_to(count.to_s, user.tasks_url, :id => 'pending-tasks-count', :title => _("Manage your pending tasks")) |
922 | end | 915 | end |
916 | + user_identifier = "<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>" | ||
917 | + welcome_link = link_to(user_identifier.html_safe, user.public_profile_url, :id => "homepage-link", :title => _('Go to your homepage')) | ||
918 | + welcome_span = _("<span class='welcome'>Welcome,</span> %s") % welcome_link.html_safe | ||
919 | + ctrl_panel_icon = '<i class="icon-menu-ctrl-panel"></i>' | ||
920 | + ctrl_panel_section = '<strong>' + ctrl_panel_icon + _('Control panel') + '</strong>' | ||
921 | + ctrl_panel_link = link_to(ctrl_panel_section.html_safe, user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content")) | ||
922 | + logout_icon = '<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>' | ||
923 | + logout_link = link_to(logout_icon.html_safe, { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) | ||
924 | + join_result = safe_join( | ||
925 | + [welcome_span.html_safe, render_environment_features(:usermenu).html_safe, admin_link.html_safe, | ||
926 | + manage_enterprises.html_safe, manage_communities.html_safe, ctrl_panel_link.html_safe, | ||
927 | + pending_tasks_count.html_safe, logout_link.html_safe], "") | ||
928 | + join_result | ||
929 | + end | ||
923 | 930 | ||
924 | - (_("<span class='welcome'>Welcome,</span> %s") % link_to("<i style='background-image:url(#{user.profile_custom_icon(gravatar_default)})'></i><strong>#{user.identifier}</strong>", user.url, :id => "homepage-link", :title => _('Go to your homepage'))) + | ||
925 | - render_environment_features(:usermenu) + | ||
926 | - admin_link + | ||
927 | - manage_enterprises + | ||
928 | - manage_communities + | ||
929 | - link_to('<i class="icon-menu-ctrl-panel"></i><strong>' + _('Control panel') + '</strong>', user.admin_url, :class => 'ctrl-panel', :title => _("Configure your personal account and content")) + | ||
930 | - pending_tasks_count + | ||
931 | - link_to('<i class="icon-menu-logout"></i><strong>' + _('Logout') + '</strong>', { :controller => 'account', :action => 'logout'} , :id => "logout", :title => _("Leave the system")) | 931 | + def usermenu_notlogged_in |
932 | + login_str = '<i class="icon-menu-login"></i><strong>' + _('Login') + '</strong>' | ||
933 | + ret = _("<span class='login'>%s</span>") % modal_inline_link_to(login_str.html_safe, login_url, '#inlineLoginBox', :id => 'link_login') | ||
934 | + return ret.html_safe | ||
932 | end | 935 | end |
933 | 936 | ||
937 | + def usermenu_signup | ||
938 | + signup_str = '<strong>' + _('Sign up') + '</strong>' | ||
939 | + ret = _("<span class='or'>or</span> <span class='signup'>%s</span>") % link_to(signup_str.html_safe, :controller => 'account', :action => 'signup') | ||
940 | + return ret.html_safe | ||
941 | + | ||
942 | + end | ||
934 | def limited_text_area(object_name, method, limit, text_area_id, options = {}) | 943 | def limited_text_area(object_name, method, limit, text_area_id, options = {}) |
935 | - content_tag(:div, [ | 944 | + content_tag(:div, safe_join([ |
936 | text_area(object_name, method, { :id => text_area_id, :onkeyup => "limited_text_area('#{text_area_id}', #{limit})" }.merge(options)), | 945 | text_area(object_name, method, { :id => text_area_id, :onkeyup => "limited_text_area('#{text_area_id}', #{limit})" }.merge(options)), |
937 | content_tag(:p, content_tag(:span, limit) + ' ' + _(' characters left'), :id => text_area_id + '_left'), | 946 | content_tag(:p, content_tag(:span, limit) + ' ' + _(' characters left'), :id => text_area_id + '_left'), |
938 | content_tag(:p, _('Limit of characters reached'), :id => text_area_id + '_limit', :style => 'display: none') | 947 | content_tag(:p, _('Limit of characters reached'), :id => text_area_id + '_limit', :style => 'display: none') |
939 | - ].join, :class => 'limited-text-area') | 948 | + ]), :class => 'limited-text-area') |
940 | end | 949 | end |
941 | 950 | ||
942 | def expandable_text_area(object_name, method, text_area_id, options = {}) | 951 | def expandable_text_area(object_name, method, text_area_id, options = {}) |
@@ -970,11 +979,11 @@ module ApplicationHelper | @@ -970,11 +979,11 @@ module ApplicationHelper | ||
970 | 979 | ||
971 | def task_information(task) | 980 | def task_information(task) |
972 | values = {} | 981 | values = {} |
982 | + values.merge!(task.information[:variables]) if task.information[:variables] | ||
973 | values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor | 983 | values.merge!({:requestor => link_to(task.requestor.name, task.requestor.url)}) if task.requestor |
974 | values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject | 984 | values.merge!({:subject => content_tag('span', task.subject, :class=>'task_target')}) if task.subject |
975 | values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject | 985 | values.merge!({:linked_subject => link_to(content_tag('span', task.linked_subject[:text], :class => 'task_target'), task.linked_subject[:url])}) if task.linked_subject |
976 | - values.merge!(task.information[:variables]) if task.information[:variables] | ||
977 | - task.information[:message] % values | 986 | + (task.information[:message] % values).html_safe |
978 | end | 987 | end |
979 | 988 | ||
980 | def add_zoom_to_article_images | 989 | def add_zoom_to_article_images |
@@ -1032,26 +1041,24 @@ module ApplicationHelper | @@ -1032,26 +1041,24 @@ module ApplicationHelper | ||
1032 | end | 1041 | end |
1033 | 1042 | ||
1034 | def render_tabs(tabs) | 1043 | def render_tabs(tabs) |
1035 | - titles = tabs.inject(''){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') } | ||
1036 | - contents = tabs.inject(''){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) } | 1044 | + titles = tabs.inject(''.html_safe){ |result, tab| result << content_tag(:li, link_to(tab[:title], '#'+tab[:id]), :class => 'tab') } |
1045 | + contents = tabs.inject(''.html_safe){ |result, tab| result << content_tag(:div, tab[:content], :id => tab[:id]) } | ||
1037 | 1046 | ||
1038 | content_tag(:div, content_tag(:ul, titles) + raw(contents), :class => 'ui-tabs') | 1047 | content_tag(:div, content_tag(:ul, titles) + raw(contents), :class => 'ui-tabs') |
1039 | end | 1048 | end |
1040 | 1049 | ||
1041 | def delete_article_message(article) | 1050 | def delete_article_message(article) |
1042 | - CGI.escapeHTML( | ||
1043 | - if article.folder? | ||
1044 | - _("Are you sure that you want to remove the folder \"%s\"? Note that all the items inside it will also be removed!") % article.name | ||
1045 | - else | ||
1046 | - _("Are you sure that you want to remove the item \"%s\"?") % article.name | ||
1047 | - end | ||
1048 | - ) | 1051 | + if article.folder? |
1052 | + _("Are you sure that you want to remove the folder \"%s\"? Note that all the items inside it will also be removed!") % article.name | ||
1053 | + else | ||
1054 | + _("Are you sure that you want to remove the item \"%s\"?") % article.name | ||
1055 | + end | ||
1049 | end | 1056 | end |
1050 | 1057 | ||
1051 | def expirable_link_to(expired, content, url, options = {}) | 1058 | def expirable_link_to(expired, content, url, options = {}) |
1052 | if expired | 1059 | if expired |
1053 | options[:class] = (options[:class] || '') + ' disabled' | 1060 | options[:class] = (options[:class] || '') + ' disabled' |
1054 | - content_tag('a', ' '+content_tag('span', content), options) | 1061 | + content_tag('a', ' '.html_safe+content_tag('span', content), options) |
1055 | else | 1062 | else |
1056 | if options[:modal] | 1063 | if options[:modal] |
1057 | options.delete(:modal) | 1064 | options.delete(:modal) |
@@ -1084,7 +1091,7 @@ module ApplicationHelper | @@ -1084,7 +1091,7 @@ module ApplicationHelper | ||
1084 | 1091 | ||
1085 | radios = templates.map do |template| | 1092 | radios = templates.map do |template| |
1086 | content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template))) | 1093 | content_tag('li', labelled_radio_button(link_to(template.name, template.url, :target => '_blank'), "#{field_name}[template_id]", template.id, environment.is_default_template?(template))) |
1087 | - end.join("\n") | 1094 | + end.join("\n").html_safe |
1088 | 1095 | ||
1089 | content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') + | 1096 | content_tag('div', content_tag('label', _('Profile organization'), :for => 'template-options', :class => 'formlabel') + |
1090 | content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') + | 1097 | content_tag('p', _('Your profile will be created according to the selected template. Click on the options to view them.'), :style => 'margin: 5px 15px;padding: 0px 10px;') + |
@@ -1124,7 +1131,7 @@ module ApplicationHelper | @@ -1124,7 +1131,7 @@ module ApplicationHelper | ||
1124 | content_tag(:div, :class => 'errorExplanation', :id => 'errorExplanation') do | 1131 | content_tag(:div, :class => 'errorExplanation', :id => 'errorExplanation') do |
1125 | content_tag(:h2, _('Errors while saving')) + | 1132 | content_tag(:h2, _('Errors while saving')) + |
1126 | content_tag(:ul) do | 1133 | content_tag(:ul) do |
1127 | - errors.map { |err| content_tag(:li, err) }.join | 1134 | + safe_join(errors.map { |err| content_tag(:li, err) }) |
1128 | end | 1135 | end |
1129 | end | 1136 | end |
1130 | end | 1137 | end |
@@ -1234,6 +1241,7 @@ module ApplicationHelper | @@ -1234,6 +1241,7 @@ module ApplicationHelper | ||
1234 | :href=>"#", | 1241 | :href=>"#", |
1235 | :title=>_("Exit full screen mode") | 1242 | :title=>_("Exit full screen mode") |
1236 | }) | 1243 | }) |
1244 | + content.html_safe | ||
1237 | end | 1245 | end |
1238 | 1246 | ||
1239 | end | 1247 | end |
app/helpers/article_helper.rb
@@ -69,14 +69,14 @@ module ArticleHelper | @@ -69,14 +69,14 @@ module ArticleHelper | ||
69 | content_tag('div', | 69 | content_tag('div', |
70 | content_tag('div', | 70 | content_tag('div', |
71 | radio_button(:article, :published, true) + | 71 | radio_button(:article, :published, true) + |
72 | - content_tag('span', ' ', :class => 'access-public-icon') + | 72 | + content_tag('span', ' '.html_safe, :class => 'access-public-icon') + |
73 | content_tag('label', _('Public'), :for => 'article_published_true') + | 73 | content_tag('label', _('Public'), :for => 'article_published_true') + |
74 | content_tag('span', _('Visible to other people'), :class => 'access-note'), | 74 | content_tag('span', _('Visible to other people'), :class => 'access-note'), |
75 | :class => 'access-item' | 75 | :class => 'access-item' |
76 | ) + | 76 | ) + |
77 | content_tag('div', | 77 | content_tag('div', |
78 | radio_button(:article, :published, false) + | 78 | radio_button(:article, :published, false) + |
79 | - content_tag('span', ' ', :class => 'access-private-icon') + | 79 | + content_tag('span', ' '.html_safe, :class => 'access-private-icon') + |
80 | content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") + | 80 | content_tag('label', _('Private'), :for => 'article_published_false', :id => "label_private") + |
81 | content_tag('span', _('Limit visibility of this article'), :class => 'access-note'), | 81 | content_tag('span', _('Limit visibility of this article'), :class => 'access-note'), |
82 | :class => 'access-item' | 82 | :class => 'access-item' |
@@ -187,9 +187,9 @@ module ArticleHelper | @@ -187,9 +187,9 @@ module ArticleHelper | ||
187 | def following_button(page, user) | 187 | def following_button(page, user) |
188 | if !user.blank? and user != page.author | 188 | if !user.blank? and user != page.author |
189 | if page.is_followed_by? user | 189 | if page.is_followed_by? user |
190 | - button :cancel, unfollow_button_text(page), {:controller => 'profile', :action => 'unfollow_article', :article_id => page.id} | 190 | + button :cancel, unfollow_button_text(page), {:controller => 'profile', :action => 'unfollow_article', :article_id => page.id, :profile => page.profile.identifier} |
191 | else | 191 | else |
192 | - button :add, follow_button_text(page), {:controller => 'profile', :action => 'follow_article', :article_id => page.id} | 192 | + button :add, follow_button_text(page), {:controller => 'profile', :action => 'follow_article', :article_id => page.id, :profile => page.profile.identifier} |
193 | end | 193 | end |
194 | end | 194 | end |
195 | end | 195 | end |
app/helpers/block_helper.rb
@@ -3,13 +3,13 @@ module BlockHelper | @@ -3,13 +3,13 @@ module BlockHelper | ||
3 | def block_title(title, subtitle=nil) | 3 | def block_title(title, subtitle=nil) |
4 | block_header = block_heading title | 4 | block_header = block_heading title |
5 | block_header += block_heading(subtitle, 'h4') if subtitle | 5 | block_header += block_heading(subtitle, 'h4') if subtitle |
6 | - content_tag 'div', block_header, :class => 'block-header' | 6 | + content_tag('div', block_header, :class => 'block-header').html_safe |
7 | end | 7 | end |
8 | 8 | ||
9 | def block_heading(title, heading='h3') | 9 | def block_heading(title, heading='h3') |
10 | tag_class = 'block-' + (heading == 'h3' ? 'title' : 'subtitle') | 10 | tag_class = 'block-' + (heading == 'h3' ? 'title' : 'subtitle') |
11 | tag_class += ' empty' if title.empty? | 11 | tag_class += ' empty' if title.empty? |
12 | - content_tag heading, content_tag('span', h(title)), :class => tag_class | 12 | + content_tag heading, content_tag('span', h(title)), :class => tag_class.html_safe |
13 | end | 13 | end |
14 | 14 | ||
15 | def highlights_block_config_image_fields(block, image={}, row_number=nil) | 15 | def highlights_block_config_image_fields(block, image={}, row_number=nil) |
@@ -28,7 +28,7 @@ module BlockHelper | @@ -28,7 +28,7 @@ module BlockHelper | ||
28 | }</label></td> | 28 | }</label></td> |
29 | <td>#{button_without_text(:delete, _('Remove'), '#', class: 'delete-highlight', data: {confirm: _('Are you sure you want to remove this highlight')})}</td> | 29 | <td>#{button_without_text(:delete, _('Remove'), '#', class: 'delete-highlight', data: {confirm: _('Are you sure you want to remove this highlight')})}</td> |
30 | </tr> | 30 | </tr> |
31 | - " | 31 | + ".html_safe |
32 | end | 32 | end |
33 | 33 | ||
34 | end | 34 | end |
app/helpers/blog_helper.rb
@@ -41,12 +41,12 @@ module BlogHelper | @@ -41,12 +41,12 @@ module BlogHelper | ||
41 | css_add << position | 41 | css_add << position |
42 | content << (content_tag 'div', id: "post-#{art.id}", class: css_add do | 42 | content << (content_tag 'div', id: "post-#{art.id}", class: css_add do |
43 | content_tag 'div', class: position + '-inner blog-post-inner' do | 43 | content_tag 'div', class: position + '-inner blog-post-inner' do |
44 | - display_post(art, conf[:format]).html_safe + | 44 | + display_post(art, conf[:format]) + |
45 | '<br style="clear:both"/>'.html_safe | 45 | '<br style="clear:both"/>'.html_safe |
46 | end | 46 | end |
47 | - end) | 47 | + end).html_safe |
48 | } | 48 | } |
49 | - content.join("\n<hr class='sep-posts'/>\n") + (pagination or '') | 49 | + safe_join(content, "\n<hr class='sep-posts'/>\n".html_safe) + (pagination or '').html_safe |
50 | end | 50 | end |
51 | 51 | ||
52 | def display_post(article, format = 'full') | 52 | def display_post(article, format = 'full') |
@@ -61,7 +61,8 @@ module BlogHelper | @@ -61,7 +61,8 @@ module BlogHelper | ||
61 | else | 61 | else |
62 | '<div class="post-pic" style="background-image:url('+img+')"></div>' | 62 | '<div class="post-pic" style="background-image:url('+img+')"></div>' |
63 | end | 63 | end |
64 | - end.to_s + title + html | 64 | + end.to_s.html_safe + |
65 | + title.html_safe + html | ||
65 | end | 66 | end |
66 | 67 | ||
67 | def display_compact_format(article) | 68 | def display_compact_format(article) |
app/helpers/box_organizer_helper.rb
@@ -38,7 +38,7 @@ module BoxOrganizerHelper | @@ -38,7 +38,7 @@ module BoxOrganizerHelper | ||
38 | content_tag(:ul, | 38 | content_tag(:ul, |
39 | images_path.map do |preview| | 39 | images_path.map do |preview| |
40 | content_tag(:li, image_tag(preview, height: '240', alt: '')) | 40 | content_tag(:li, image_tag(preview, height: '240', alt: '')) |
41 | - end.join("\n") | 41 | + end.join("\n").html_safe |
42 | ) | 42 | ) |
43 | end | 43 | end |
44 | 44 |
app/helpers/boxes_helper.rb
@@ -34,7 +34,7 @@ module BoxesHelper | @@ -34,7 +34,7 @@ module BoxesHelper | ||
34 | 34 | ||
35 | def display_boxes_editor(holder) | 35 | def display_boxes_editor(holder) |
36 | with_box_decorator self do | 36 | with_box_decorator self do |
37 | - content_tag('div', display_boxes(holder, '<' + _('Main content') + '>'), :id => 'box-organizer') | 37 | + content_tag('div', display_boxes(holder, '<' + _('Main content') + '>'), :id => 'box-organizer') |
38 | end | 38 | end |
39 | end | 39 | end |
40 | 40 | ||
@@ -44,7 +44,7 @@ module BoxesHelper | @@ -44,7 +44,7 @@ module BoxesHelper | ||
44 | 44 | ||
45 | def display_boxes(holder, main_content) | 45 | def display_boxes(holder, main_content) |
46 | boxes = holder.boxes.with_position.first(boxes_limit(holder)) | 46 | boxes = holder.boxes.with_position.first(boxes_limit(holder)) |
47 | - content = boxes.reverse.map { |item| display_box(item, main_content) }.join("\n") | 47 | + content = safe_join(boxes.reverse.map { |item| display_box(item, main_content) }, "\n") |
48 | content = main_content if (content.blank?) | 48 | content = main_content if (content.blank?) |
49 | 49 | ||
50 | content_tag('div', content, :class => 'boxes', :id => 'boxes' ) | 50 | content_tag('div', content, :class => 'boxes', :id => 'boxes' ) |
@@ -52,9 +52,9 @@ module BoxesHelper | @@ -52,9 +52,9 @@ module BoxesHelper | ||
52 | 52 | ||
53 | def maybe_display_custom_element(holder, element, options = {}) | 53 | def maybe_display_custom_element(holder, element, options = {}) |
54 | if holder.respond_to?(element) | 54 | if holder.respond_to?(element) |
55 | - content_tag('div', holder.send(element), options) | 55 | + content_tag('div', holder.send(element).to_s.html_safe, options) |
56 | else | 56 | else |
57 | - '' | 57 | + ''.html_safe |
58 | end | 58 | end |
59 | end | 59 | end |
60 | 60 | ||
@@ -64,15 +64,16 @@ module BoxesHelper | @@ -64,15 +64,16 @@ module BoxesHelper | ||
64 | 64 | ||
65 | def display_updated_box(box) | 65 | def display_updated_box(box) |
66 | with_box_decorator self do | 66 | with_box_decorator self do |
67 | - display_box_content(box, '<' + _('Main content') + '>') | 67 | + display_box_content(box, '<' + _('Main content') + '>') |
68 | end | 68 | end |
69 | end | 69 | end |
70 | 70 | ||
71 | def display_box_content(box, main_content) | 71 | def display_box_content(box, main_content) |
72 | context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params, :user => user, :controller => controller } | 72 | context = { :article => @page, :request_path => request.path, :locale => locale, :params => request.params, :user => user, :controller => controller } |
73 | - box_decorator.select_blocks(box, box.blocks.includes(:box), context).map do |item| | 73 | + blocks = box_decorator.select_blocks(box, box.blocks.includes(:box), context).map do |item| |
74 | display_block item, main_content | 74 | display_block item, main_content |
75 | - end.join("\n") + box_decorator.block_target(box) | 75 | + end |
76 | + safe_join(blocks, "\n") + box_decorator.block_target(box) | ||
76 | end | 77 | end |
77 | 78 | ||
78 | def select_blocks box, arr, context | 79 | def select_blocks box, arr, context |
@@ -136,17 +137,18 @@ module BoxesHelper | @@ -136,17 +137,18 @@ module BoxesHelper | ||
136 | 137 | ||
137 | result = filter_html(result, block) | 138 | result = filter_html(result, block) |
138 | 139 | ||
139 | - content_tag('div', | ||
140 | - box_decorator.block_target(block.box, block) + | ||
141 | - content_tag('div', | ||
142 | - content_tag('div', | ||
143 | - content_tag('div', | ||
144 | - result + footer_content + box_decorator.block_edit_buttons(block), | ||
145 | - :class => 'block-inner-2'), | ||
146 | - :class => 'block-inner-1'), | ||
147 | - options), | ||
148 | - :class => 'block-outer') + | ||
149 | - box_decorator.block_handle(block) | 140 | + join_result = safe_join([result, footer_content, box_decorator.block_edit_buttons(block)]) |
141 | + content_tag_inner_1 = content_tag('div', join_result, :class => 'block-inner-2') | ||
142 | + | ||
143 | + content_tag_inner_2 = content_tag('div', content_tag_inner_1, :class => 'block-inner-1') | ||
144 | + content_tag_inner_3 = content_tag('div', content_tag_inner_2, options) | ||
145 | + content_tag_inner_4 = box_decorator.block_target(block.box, block) + content_tag_inner_3 | ||
146 | + c = content_tag('div', content_tag_inner_4, :class => 'block-outer') | ||
147 | + box_decorator_result = box_decorator.block_handle(block) | ||
148 | + result_final = safe_join([c, box_decorator_result], "") | ||
149 | + | ||
150 | + | ||
151 | + return result_final | ||
150 | end | 152 | end |
151 | 153 | ||
152 | def wrap_main_content(content) | 154 | def wrap_main_content(content) |
@@ -156,17 +158,17 @@ module BoxesHelper | @@ -156,17 +158,17 @@ module BoxesHelper | ||
156 | def extract_block_content(content) | 158 | def extract_block_content(content) |
157 | case content | 159 | case content |
158 | when Hash | 160 | when Hash |
159 | - content_tag('iframe', '', :src => url_for(content)) | 161 | + content_tag('iframe', ''.html_safe, :src => url_for(content)) |
160 | when String | 162 | when String |
161 | if content.split("\n").size == 1 and content =~ /^https?:\/\// | 163 | if content.split("\n").size == 1 and content =~ /^https?:\/\// |
162 | - content_tag('iframe', '', :src => content) | 164 | + content_tag('iframe', ''.html_safe, :src => content) |
163 | else | 165 | else |
164 | content | 166 | content |
165 | end | 167 | end |
166 | when Proc | 168 | when Proc |
167 | self.instance_eval(&content) | 169 | self.instance_eval(&content) |
168 | when NilClass | 170 | when NilClass |
169 | - '' | 171 | + ''.html_safe |
170 | else | 172 | else |
171 | raise "Unsupported content for block (#{content.class})" | 173 | raise "Unsupported content for block (#{content.class})" |
172 | end | 174 | end |
@@ -175,14 +177,14 @@ module BoxesHelper | @@ -175,14 +177,14 @@ module BoxesHelper | ||
175 | module DontMoveBlocks | 177 | module DontMoveBlocks |
176 | # does nothing | 178 | # does nothing |
177 | def self.block_target(box, block = nil) | 179 | def self.block_target(box, block = nil) |
178 | - '' | 180 | + ''.html_safe |
179 | end | 181 | end |
180 | # does nothing | 182 | # does nothing |
181 | def self.block_handle(block) | 183 | def self.block_handle(block) |
182 | - '' | 184 | + ''.html_safe |
183 | end | 185 | end |
184 | def self.block_edit_buttons(block) | 186 | def self.block_edit_buttons(block) |
185 | - '' | 187 | + ''.html_safe |
186 | end | 188 | end |
187 | def self.select_blocks box, arr, context | 189 | def self.select_blocks box, arr, context |
188 | arr = arr.select{ |block| block.visible? context } | 190 | arr = arr.select{ |block| block.visible? context } |
@@ -229,9 +231,9 @@ module BoxesHelper | @@ -229,9 +231,9 @@ module BoxesHelper | ||
229 | # makes the given block draggable so it can be moved away. | 231 | # makes the given block draggable so it can be moved away. |
230 | def block_handle(block) | 232 | def block_handle(block) |
231 | return "" unless movable?(block) | 233 | return "" unless movable?(block) |
232 | - icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>" | 234 | + icon = "<div><div>#{display_icon(block.class)}</div><span>#{_(block.class.pretty_name)}</span></div>".html_safe |
233 | block_draggable("block-#{block.id}", | 235 | block_draggable("block-#{block.id}", |
234 | - :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}") | 236 | + :helper => "function() {return cloneDraggableBlock($(this), '#{icon}')}".html_safe) |
235 | end | 237 | end |
236 | 238 | ||
237 | def block_draggable(element_id, options={}) | 239 | def block_draggable(element_id, options={}) |
@@ -302,7 +304,7 @@ module BoxesHelper | @@ -302,7 +304,7 @@ module BoxesHelper | ||
302 | buttons << modal_inline_icon(:embed, _('Embed code'), {}, "#embed-code-box-#{block.id}") << html | 304 | buttons << modal_inline_icon(:embed, _('Embed code'), {}, "#embed-code-box-#{block.id}") << html |
303 | end | 305 | end |
304 | 306 | ||
305 | - content_tag('div', buttons.join("\n") + tag('br', :style => 'clear: left'), :class => 'button-bar') | 307 | + content_tag('div', buttons.join("\n").html_safe + tag('br', :style => 'clear: left'), :class => 'button-bar') |
306 | end | 308 | end |
307 | 309 | ||
308 | def current_blocks | 310 | def current_blocks |
app/helpers/buttons_helper.rb
1 | module ButtonsHelper | 1 | module ButtonsHelper |
2 | + | ||
3 | + def button_bar(options = {}, &block) | ||
4 | + options[:class] ||= '' | ||
5 | + options[:class] << ' button-bar' | ||
6 | + | ||
7 | + content_tag :div, options do | ||
8 | + [ | ||
9 | + capture(&block).to_s, | ||
10 | + tag(:br, style: 'clear: left;'), | ||
11 | + ].safe_join | ||
12 | + end | ||
13 | + end | ||
14 | + | ||
2 | def button(type, label, url, html_options = {}) | 15 | def button(type, label, url, html_options = {}) |
3 | html_options ||= {} | 16 | html_options ||= {} |
4 | the_class = 'with-text' | 17 | the_class = 'with-text' |
@@ -15,9 +28,9 @@ module ButtonsHelper | @@ -15,9 +28,9 @@ module ButtonsHelper | ||
15 | end | 28 | end |
16 | the_title = html_options[:title] || label | 29 | the_title = html_options[:title] || label |
17 | if html_options[:disabled] | 30 | if html_options[:disabled] |
18 | - content_tag('a', ' '+content_tag('span', label), html_options.merge(:class => the_class, :title => the_title)) | 31 | + content_tag('a', ' '.html_safe+content_tag('span', label), html_options.merge(:class => the_class, :title => the_title)) |
19 | else | 32 | else |
20 | - link_to(' '+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title)) | 33 | + link_to(' '.html_safe+content_tag('span', label), url, html_options.merge(:class => the_class, :title => the_title)) |
21 | end | 34 | end |
22 | end | 35 | end |
23 | 36 |
app/helpers/categories_helper.rb
@@ -2,7 +2,6 @@ module CategoriesHelper | @@ -2,7 +2,6 @@ module CategoriesHelper | ||
2 | 2 | ||
3 | TYPES = [ | 3 | TYPES = [ |
4 | [ _('General Category'), Category.to_s ], | 4 | [ _('General Category'), Category.to_s ], |
5 | - [ _('Product Category'), ProductCategory.to_s ], | ||
6 | [ _('Region'), Region.to_s ], | 5 | [ _('Region'), Region.to_s ], |
7 | ] | 6 | ] |
8 | 7 | ||
@@ -20,7 +19,7 @@ module CategoriesHelper | @@ -20,7 +19,7 @@ module CategoriesHelper | ||
20 | def selected_category_link(cat) | 19 | def selected_category_link(cat) |
21 | js_remove = "jQuery('#selected-category-#{cat.id}').remove();" | 20 | js_remove = "jQuery('#selected-category-#{cat.id}').remove();" |
22 | content_tag('div', button_to_function_without_text(:remove, _('Remove'), js_remove) + | 21 | content_tag('div', button_to_function_without_text(:remove, _('Remove'), js_remove) + |
23 | - link_to_function(cat.full_name(' → '), js_remove, :id => "remove-selected-category-#{cat.id}-button", :class => 'select-subcategory-link'), | 22 | + link_to_function(cat.full_name(' → ').html_safe, js_remove, :id => "remove-selected-category-#{cat.id}-button", :class => 'select-subcategory-link'), |
24 | :class => 'selected-category' | 23 | :class => 'selected-category' |
25 | ) | 24 | ) |
26 | end | 25 | end |
app/helpers/comment_helper.rb
@@ -66,7 +66,7 @@ module CommentHelper | @@ -66,7 +66,7 @@ module CommentHelper | ||
66 | 66 | ||
67 | def link_for_edit(comment) | 67 | def link_for_edit(comment) |
68 | if comment.can_be_updated_by?(user) | 68 | if comment.can_be_updated_by?(user) |
69 | - {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id),:class => 'modal')} | 69 | + {:link => expirable_comment_link(comment, :edit, _('Edit'), url_for(:profile => profile.identifier, :controller => :comment, :action => :edit, :id => comment.id), :modal => true)} |
70 | end | 70 | end |
71 | end | 71 | end |
72 | 72 |
app/helpers/content_viewer_helper.rb
@@ -7,7 +7,8 @@ module ContentViewerHelper | @@ -7,7 +7,8 @@ module ContentViewerHelper | ||
7 | def display_number_of_comments(n) | 7 | def display_number_of_comments(n) |
8 | base_str = "<span class='comment-count hide'>#{n}</span>" | 8 | base_str = "<span class='comment-count hide'>#{n}</span>" |
9 | amount_str = n == 0 ? _('no comments yet') : (n == 1 ? _('One comment') : _('%s comments') % n) | 9 | amount_str = n == 0 ? _('no comments yet') : (n == 1 ? _('One comment') : _('%s comments') % n) |
10 | - base_str + "<span class='comment-count-write-out'>#{amount_str}</span>" | 10 | + base_str += "<span class='comment-count-write-out'>#{amount_str}</span>" |
11 | + base_str.html_safe | ||
11 | end | 12 | end |
12 | 13 | ||
13 | def number_of_comments(article) | 14 | def number_of_comments(article) |
@@ -19,16 +20,16 @@ module ContentViewerHelper | @@ -19,16 +20,16 @@ module ContentViewerHelper | ||
19 | title = content_tag('h1', h(title), :class => 'title') | 20 | title = content_tag('h1', h(title), :class => 'title') |
20 | if article.belongs_to_blog? || article.belongs_to_forum? | 21 | if article.belongs_to_blog? || article.belongs_to_forum? |
21 | unless args[:no_link] | 22 | unless args[:no_link] |
22 | - title = content_tag('h1', link_to(article.name, article.url), :class => 'title') | 23 | + title = content_tag('h1', link_to(article.name, url_for(article.url)), :class => 'title') |
23 | end | 24 | end |
24 | comments = '' | 25 | comments = '' |
25 | unless args[:no_comments] || !article.accept_comments | 26 | unless args[:no_comments] || !article.accept_comments |
26 | - comments = (" - %s") % link_to_comments(article) | 27 | + comments = (" - %s").html_safe % link_to_comments(article) |
27 | end | 28 | end |
28 | date_format = show_with_right_format_date article | 29 | date_format = show_with_right_format_date article |
29 | title << content_tag('span', | 30 | title << content_tag('span', |
30 | date_format + | 31 | date_format + |
31 | - content_tag('span', _(", by %s") % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') + | 32 | + content_tag('span', _(", by %s").html_safe % (article.author ? link_to(article.author_name, article.author_url) : article.author_name), :class => 'author') + |
32 | content_tag('span', comments, :class => 'comments'), | 33 | content_tag('span', comments, :class => 'comments'), |
33 | :class => 'publishing-info' | 34 | :class => 'publishing-info' |
34 | ) | 35 | ) |
app/helpers/display_helper.rb
1 | module DisplayHelper | 1 | module DisplayHelper |
2 | 2 | ||
3 | - def link_to_product(product, opts={}) | ||
4 | - return _('No product') unless product | ||
5 | - target = product_path(product) | ||
6 | - link_to content_tag( 'span', product.name ), | ||
7 | - target, | ||
8 | - opts | ||
9 | - end | ||
10 | - | ||
11 | def themed_path(file) | 3 | def themed_path(file) |
12 | if File.exists?(File.join(Rails.root, 'public', theme_path, file)) | 4 | if File.exists?(File.join(Rails.root, 'public', theme_path, file)) |
13 | File.join(theme_path, file) | 5 | File.join(theme_path, file) |
@@ -16,55 +8,35 @@ module DisplayHelper | @@ -16,55 +8,35 @@ module DisplayHelper | ||
16 | end | 8 | end |
17 | end | 9 | end |
18 | 10 | ||
19 | - def image_link_to_product(product, opts={}) | ||
20 | - return _('No product') unless product | ||
21 | - target = product_path(product) | ||
22 | - link_to image_tag(product.default_image(:big), :alt => product.name), | ||
23 | - target, | ||
24 | - opts | ||
25 | - end | ||
26 | - | ||
27 | def price_span(price, options = {}) | 11 | def price_span(price, options = {}) |
28 | content_tag 'span', | 12 | content_tag 'span', |
29 | number_to_currency(price, :unit => environment.currency_unit, :delimiter => environment.currency_delimiter, :separator => environment.currency_separator), | 13 | number_to_currency(price, :unit => environment.currency_unit, :delimiter => environment.currency_delimiter, :separator => environment.currency_separator), |
30 | options | 14 | options |
31 | end | 15 | end |
32 | 16 | ||
33 | - def product_path(product) | ||
34 | - product.enterprise.enabled? ? product.enterprise.public_profile_url.merge(:controller => 'manage_products', :action => 'show', :id => product) : product.enterprise.url | ||
35 | - end | ||
36 | - | ||
37 | def link_to_tag(tag, html_options = {}) | 17 | def link_to_tag(tag, html_options = {}) |
38 | link_to tag.name, {:controller => 'search', :action => 'tag', :tag => tag.name}, html_options | 18 | link_to tag.name, {:controller => 'search', :action => 'tag', :tag => tag.name}, html_options |
39 | end | 19 | end |
40 | 20 | ||
41 | def link_to_category(category, full = true, html_options = {}) | 21 | def link_to_category(category, full = true, html_options = {}) |
42 | - return _('Uncategorized product') unless category | ||
43 | name = full ? category.full_name(' → ') : category.name | 22 | name = full ? category.full_name(' → ') : category.name |
44 | link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }), html_options | 23 | link_to name, Noosfero.url_options.merge({:controller => 'search', :action => 'category_index', :category_path => category.path.split('/'),:host => category.environment.default_hostname }), html_options |
45 | end | 24 | end |
46 | 25 | ||
47 | - def link_to_product_category(category) | ||
48 | - if category | ||
49 | - link_to(category.name, :controller => 'search', :action => 'products', :category_path => category.explode_path) | ||
50 | - else | ||
51 | - _('Uncategorized product') | ||
52 | - end | ||
53 | - end | ||
54 | - | ||
55 | def txt2html(txt) | 26 | def txt2html(txt) |
56 | - txt.strip. | 27 | + ret = txt.strip. |
57 | gsub( /\s*\n\s*\n\s*/, "\r<p/>\r" ). | 28 | gsub( /\s*\n\s*\n\s*/, "\r<p/>\r" ). |
58 | gsub( /\s*\n\s*/, "\n<br/>\n" ). | 29 | gsub( /\s*\n\s*/, "\n<br/>\n" ). |
59 | gsub( /\r/, "\n" ). | 30 | gsub( /\r/, "\n" ). |
60 | gsub( /(^|\s)(www\.[^\s]+|https?:\/\/[^\s]+)/ ) do | 31 | gsub( /(^|\s)(www\.[^\s]+|https?:\/\/[^\s]+)/ ) do |
61 | pre_char, href = $1, $2 | 32 | pre_char, href = $1, $2 |
62 | href = 'http://'+href if ! href.match /^https?:/ | 33 | href = 'http://'+href if ! href.match /^https?:/ |
63 | - content = href.gsub(/^https?:\/\//, '').scan(/.{1,4}/).join('​') | 34 | + content = safe_join(href.gsub(/^https?:\/\//, '').scan(/.{1,4}/), '​'.html_safe) |
64 | pre_char + | 35 | pre_char + |
65 | content_tag(:a, content, :href => href, :target => '_blank', | 36 | content_tag(:a, content, :href => href, :target => '_blank', |
66 | - :rel => 'nofolow', :onclick => "return confirm('%s')" % | 37 | + :rel => 'nofolow', :onclick => "return confirm('%s')".html_safe % |
67 | _('Are you sure you want to visit this web site?')) | 38 | _('Are you sure you want to visit this web site?')) |
68 | end | 39 | end |
40 | + ret.html_safe | ||
69 | end | 41 | end |
70 | end | 42 | end |
app/helpers/events_helper.rb
1 | module EventsHelper | 1 | module EventsHelper |
2 | 2 | ||
3 | include DatesHelper | 3 | include DatesHelper |
4 | + include ActionView::Helpers::OutputSafetyHelper | ||
5 | + | ||
4 | def list_events(date, events) | 6 | def list_events(date, events) |
5 | title = _('Events for %s') % show_date_month(date) | 7 | title = _('Events for %s') % show_date_month(date) |
8 | + user_events = events.select { |item| item.display_to?(user) } | ||
9 | + events_for_month = safe_join(user_events.map {|item| display_event_in_listing(item)}, '') | ||
6 | content_tag('h2', title) + | 10 | content_tag('h2', title) + |
7 | content_tag('div', | 11 | content_tag('div', |
8 | (events.any? ? | 12 | (events.any? ? |
9 | - content_tag('table', events.select { |item| item.display_to?(user) }.map {|item| display_event_in_listing(item)}.join('')) : | ||
10 | - content_tag('em', _('No events for this month'), :class => 'no-events') | 13 | + content_tag('table', events_for_month) : |
14 | + content_tag('em', _('No events for this month'), :class => 'no-events') | ||
11 | ), :id => 'agenda-items' | 15 | ), :id => 'agenda-items' |
12 | ) | 16 | ) |
13 | end | 17 | end |
app/helpers/forms_helper.rb
@@ -101,7 +101,7 @@ module FormsHelper | @@ -101,7 +101,7 @@ module FormsHelper | ||
101 | 101 | ||
102 | def required_fields_message | 102 | def required_fields_message |
103 | content_tag('p', content_tag('span', | 103 | content_tag('p', content_tag('span', |
104 | - _("The <label class='pseudoformlabel'>highlighted</label> fields are mandatory."), | 104 | + _("The <label class='pseudoformlabel'>highlighted</label> fields are mandatory.").html_safe, |
105 | :class => 'required-field' | 105 | :class => 'required-field' |
106 | )) | 106 | )) |
107 | end | 107 | end |
@@ -112,10 +112,11 @@ module FormsHelper | @@ -112,10 +112,11 @@ module FormsHelper | ||
112 | options_for_select = container.inject([]) do |options, element| | 112 | options_for_select = container.inject([]) do |options, element| |
113 | text, value = option_text_and_value(element) | 113 | text, value = option_text_and_value(element) |
114 | selected_attribute = ' selected="selected"' if option_value_selected?(value, selected) | 114 | selected_attribute = ' selected="selected"' if option_value_selected?(value, selected) |
115 | - options << %(<option title="#{html_escape(text.to_s)}" value="#{html_escape(value.to_s)}"#{selected_attribute}>#{html_escape(text.to_s)}</option>) | 115 | + opt = %(<option title="#{html_escape(text.to_s)}" value="#{html_escape(value.to_s)}"#{selected_attribute}>#{html_escape(text.to_s)}</option>) |
116 | + options << opt.html_safe | ||
116 | end | 117 | end |
117 | 118 | ||
118 | - options_for_select.join("\n") | 119 | + safe_join(options_for_select, "\n") |
119 | end | 120 | end |
120 | 121 | ||
121 | def balanced_table(items, per_row=3) | 122 | def balanced_table(items, per_row=3) |
@@ -248,8 +249,8 @@ module FormsHelper | @@ -248,8 +249,8 @@ module FormsHelper | ||
248 | def date_range_field(from_name, to_name, from_value, to_value, datepicker_options = {}, html_options = {}) | 249 | def date_range_field(from_name, to_name, from_value, to_value, datepicker_options = {}, html_options = {}) |
249 | from_id = html_options[:from_id] || 'datepicker-from-date' | 250 | from_id = html_options[:from_id] || 'datepicker-from-date' |
250 | to_id = html_options[:to_id] || 'datepicker-to-date' | 251 | to_id = html_options[:to_id] || 'datepicker-to-date' |
251 | - return _('From') +' '+ date_field(from_name, from_value, datepicker_options, html_options.merge({:id => from_id})) + | ||
252 | - ' ' + _('until') +' '+ date_field(to_name, to_value, datepicker_options, html_options.merge({:id => to_id})) | 252 | + return (_('From') +' '+ date_field(from_name, from_value, datepicker_options, html_options.merge({:id => from_id})) + |
253 | + ' ' + _('until') +' '+ date_field(to_name, to_value, datepicker_options, html_options.merge({:id => to_id}))).html_safe | ||
253 | end | 254 | end |
254 | 255 | ||
255 | def select_folder(label_text, field_id, collection, default_value=nil, html_options = {}, js_options = {}) | 256 | def select_folder(label_text, field_id, collection, default_value=nil, html_options = {}, js_options = {}) |
app/helpers/forum_helper.rb
@@ -35,7 +35,7 @@ module ForumHelper | @@ -35,7 +35,7 @@ module ForumHelper | ||
35 | :id => "post-#{art.id}" | 35 | :id => "post-#{art.id}" |
36 | ) | 36 | ) |
37 | } | 37 | } |
38 | - content_tag('table', content.join) + (pagination or '') | 38 | + content_tag('table', safe_join(content, "")) + (pagination or '').html_safe |
39 | end | 39 | end |
40 | 40 | ||
41 | def last_topic_update(article) | 41 | def last_topic_update(article) |
app/helpers/language_helper.rb
@@ -40,7 +40,7 @@ module LanguageHelper | @@ -40,7 +40,7 @@ module LanguageHelper | ||
40 | else | 40 | else |
41 | link_to(name, params.merge(:lang => code), :rel => 'nofollow') | 41 | link_to(name, params.merge(:lang => code), :rel => 'nofollow') |
42 | end | 42 | end |
43 | - end.join(separator) | 43 | + end.join(separator).html_safe |
44 | content_tag('div', languages, :id => 'language-chooser', :help => _('The language you choose here is the language used for options, buttons, etc. It does not affect the language of the content created by other users.')) | 44 | content_tag('div', languages, :id => 'language-chooser', :help => _('The language you choose here is the language used for options, buttons, etc. It does not affect the language of the content created by other users.')) |
45 | end | 45 | end |
46 | end | 46 | end |
app/helpers/layout_helper.rb
@@ -40,7 +40,8 @@ module LayoutHelper | @@ -40,7 +40,8 @@ module LayoutHelper | ||
40 | 40 | ||
41 | output += templete_javascript_ng.to_s | 41 | output += templete_javascript_ng.to_s |
42 | 42 | ||
43 | - output | 43 | + # This output should be safe! |
44 | + output.html_safe | ||
44 | end | 45 | end |
45 | 46 | ||
46 | def noosfero_stylesheets | 47 | def noosfero_stylesheets |
@@ -64,7 +65,9 @@ module LayoutHelper | @@ -64,7 +65,9 @@ module LayoutHelper | ||
64 | output << stylesheet_link_tag(global_css_pub) | 65 | output << stylesheet_link_tag(global_css_pub) |
65 | end | 66 | end |
66 | output << stylesheet_link_tag(theme_stylesheet_path) | 67 | output << stylesheet_link_tag(theme_stylesheet_path) |
67 | - output.join "\n" | 68 | + |
69 | + # This output should be safe! | ||
70 | + output.join("\n").html_safe | ||
68 | end | 71 | end |
69 | 72 | ||
70 | def noosfero_layout_features | 73 | def noosfero_layout_features |
@@ -94,9 +97,7 @@ module LayoutHelper | @@ -94,9 +97,7 @@ module LayoutHelper | ||
94 | end | 97 | end |
95 | 98 | ||
96 | def addthis_javascript | 99 | def addthis_javascript |
97 | - if NOOSFERO_CONF['addthis_enabled'] | ||
98 | - '<script src="https://s7.addthis.com/js/152/addthis_widget.js"></script>' | ||
99 | - end | 100 | + NOOSFERO_CONF['addthis_enabled'] ? '<script src="https://s7.addthis.com/js/152/addthis_widget.js"></script>' : '' |
100 | end | 101 | end |
101 | 102 | ||
102 | end | 103 | end |
app/helpers/macros_helper.rb
app/helpers/memberships_helper.rb
1 | module MembershipsHelper | 1 | module MembershipsHelper |
2 | + | ||
3 | + def join_community_button options={:logged => false} | ||
4 | + url = options[:logged] ? profile.join_url : profile.join_not_logged_url | ||
5 | + | ||
6 | + if show_confirmation_modal? profile | ||
7 | + modal_button :add, _('Join this community'), url, class: 'join-community' | ||
8 | + else | ||
9 | + button :add, _('Join this community'), url, class: 'join-community' | ||
10 | + end | ||
11 | + end | ||
12 | + | ||
13 | + def show_confirmation_modal? profile | ||
14 | + profile.requires_email? && current_person && !current_person.public_fields.include?("email") | ||
15 | + end | ||
16 | + | ||
2 | end | 17 | end |
app/helpers/partials_helper.rb
@@ -29,14 +29,49 @@ module PartialsHelper | @@ -29,14 +29,49 @@ module PartialsHelper | ||
29 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' | 29 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' |
30 | end | 30 | end |
31 | 31 | ||
32 | - def render_partial_for_class klass, *args | 32 | + |
33 | + def partial_for_class(klass, prefix=nil, suffix=nil) | ||
33 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? | 34 | raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' if klass.nil? |
35 | + name = klass.name.underscore | ||
36 | + controller.view_paths.each do |view_path| | ||
37 | + partial = partial_for_class_in_view_path(klass, view_path, prefix, suffix) | ||
38 | + return partial if partial | ||
39 | + end | ||
40 | + | ||
41 | + raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' | ||
42 | + end | ||
43 | + | ||
44 | + ## | ||
45 | + # Calculate partial name with prefix and suffix | ||
46 | + # Togheter with render_partial_for_class, | ||
47 | + # it should replace #partial_for_class_in_view_path in the future | ||
48 | + # | ||
49 | + def partial_name_for underscore, prefix = nil, suffix = nil | ||
50 | + parts = underscore.split '/' | ||
51 | + if prefix or suffix | ||
52 | + partial = [prefix, parts.last, suffix].compact.map(&:to_s).join '_' | ||
53 | + else | ||
54 | + partial = parts.last | ||
55 | + end | ||
56 | + if parts.size > 1 | ||
57 | + "#{params[:controller]}/#{parts.first}/#{partial}" | ||
58 | + else | ||
59 | + partial | ||
60 | + end | ||
61 | + end | ||
62 | + | ||
63 | + def render_for_class klass, *args, &block | ||
64 | + raise ArgumentError, 'No partial for object. Is there a partial for any class in the inheritance hierarchy?' unless klass | ||
34 | begin | 65 | begin |
35 | - partial = klass.name.underscore | ||
36 | - partial = "#{params[:controller]}/#{partial}" if params[:controller] and partial.index '/' | ||
37 | - return render partial, *args | 66 | + capture klass, &block |
38 | rescue ActionView::MissingTemplate | 67 | rescue ActionView::MissingTemplate |
39 | - return render_partial_for_class klass.superclass, *args | 68 | + render_for_class klass.superclass, *args, &block |
69 | + end | ||
70 | + end | ||
71 | + | ||
72 | + def render_partial_for_class klass, *args | ||
73 | + render_for_class klass do |klass| | ||
74 | + render partial_name_for(klass.name.underscore), *args | ||
40 | end | 75 | end |
41 | end | 76 | end |
42 | 77 |
app/helpers/profile_editor_helper.rb
@@ -129,7 +129,11 @@ module ProfileEditorHelper | @@ -129,7 +129,11 @@ module ProfileEditorHelper | ||
129 | else | 129 | else |
130 | domains = environment.domains | 130 | domains = environment.domains |
131 | end | 131 | end |
132 | - labelled_form_field(_('Preferred domain name:'), select(object, :preferred_domain_id, domains.map {|item| [item.name, item.id]}, :prompt => '<' + _('Select domain') + '>')) | 132 | + select_domain_prompt = '<'.html_safe + _('Select domain').html_safe + '>'.html_safe |
133 | + select_field = select(object, :preferred_domain_id, domains.map { | ||
134 | + |item| [item.name, item.id]}, :prompt => select_domain_prompt.html_safe) | ||
135 | + | ||
136 | + labelled_form_field(_('Preferred domain name:'), select_field) | ||
133 | end | 137 | end |
134 | 138 | ||
135 | def control_panel(&block) | 139 | def control_panel(&block) |
app/helpers/profile_helper.rb
@@ -84,7 +84,7 @@ module ProfileHelper | @@ -84,7 +84,7 @@ module ProfileHelper | ||
84 | entries.map do |entry| | 84 | entries.map do |entry| |
85 | content = self.send("treat_#{field}", entry) | 85 | content = self.send("treat_#{field}", entry) |
86 | unless content.blank? | 86 | unless content.blank? |
87 | - content_tag('tr', content_tag('td', title(field, entry), :class => 'field-name') + content_tag('td', content)) | 87 | + content_tag('tr', content_tag('td', title(field, entry), :class => 'field-name') + content_tag('td', content.to_s.html_safe)) |
88 | end | 88 | end |
89 | end.join("\n") | 89 | end.join("\n") |
90 | end | 90 | end |
app/helpers/profile_image_helper.rb
@@ -61,6 +61,8 @@ module ProfileImageHelper | @@ -61,6 +61,8 @@ module ProfileImageHelper | ||
61 | image_tag(profile_icon(profile, size), opt ) | 61 | image_tag(profile_icon(profile, size), opt ) |
62 | end | 62 | end |
63 | 63 | ||
64 | + include MembershipsHelper | ||
65 | + | ||
64 | def links_for_balloon(profile) | 66 | def links_for_balloon(profile) |
65 | if environment.enabled?(:show_balloon_with_profile_links_when_clicked) | 67 | if environment.enabled?(:show_balloon_with_profile_links_when_clicked) |
66 | if profile.kind_of?(Person) | 68 | if profile.kind_of?(Person) |
@@ -76,13 +78,12 @@ module ProfileImageHelper | @@ -76,13 +78,12 @@ module ProfileImageHelper | ||
76 | {_('Wall') => {:href => url_for(profile.public_profile_url)}}, | 78 | {_('Wall') => {:href => url_for(profile.public_profile_url)}}, |
77 | {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, | 79 | {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, |
78 | {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}}, | 80 | {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}}, |
79 | - {_('Join') => {:href => url_for(profile.join_url), :class => 'join-community', :style => 'display: none'}}, | 81 | + {_('Join') => {:href => url_for(profile.join_url), :class => 'join-community'+ (show_confirmation_modal?(profile) ? ' modal-toggle' : '') , :style => 'display: none'}}, |
80 | {_('Leave community') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}}, | 82 | {_('Leave community') => {:href => url_for(profile.leave_url), :class => 'leave-community', :style => 'display: none'}}, |
81 | {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}} | 83 | {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}} |
82 | ] | 84 | ] |
83 | elsif profile.kind_of?(Enterprise) | 85 | elsif profile.kind_of?(Enterprise) |
84 | [ | 86 | [ |
85 | - {_('Products') => {:href => catalog_path(profile.identifier)}}, | ||
86 | {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, | 87 | {_('Members') => {:href => url_for(:controller => :profile, :action => :members, :profile => profile.identifier)}}, |
87 | {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}}, | 88 | {_('Agenda') => {:href => url_for(:controller => :profile, :action => :events, :profile => profile.identifier)}}, |
88 | {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}}, | 89 | {_('Send an e-mail') => {:href => url_for(:profile => profile.identifier, :controller => 'contact', :action => 'new'), :class => 'send-an-email', :style => 'display: none'}}, |
@@ -131,7 +132,7 @@ module ProfileImageHelper | @@ -131,7 +132,7 @@ module ProfileImageHelper | ||
131 | links = links_for_balloon(profile) | 132 | links = links_for_balloon(profile) |
132 | content_tag('div', content_tag(tag, | 133 | content_tag('div', content_tag(tag, |
133 | (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? | 134 | (environment.enabled?(:show_balloon_with_profile_links_when_clicked) ? |
134 | - popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "") + | 135 | + popover_menu(_('Profile links'),profile.short_name,links,{:class => trigger_class, :url => url}) : "").html_safe + |
135 | link_to( | 136 | link_to( |
136 | content_tag( 'span', profile_image( profile, size ), :class => img_class ) + | 137 | content_tag( 'span', profile_image( profile, size ), :class => img_class ) + |
137 | content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + | 138 | content_tag( 'span', h(name), :class => ( profile.class == Person ? 'fn' : 'org' ) ) + |
@@ -139,7 +140,7 @@ module ProfileImageHelper | @@ -139,7 +140,7 @@ module ProfileImageHelper | ||
139 | profile.url, | 140 | profile.url, |
140 | :class => 'profile_link url', | 141 | :class => 'profile_link url', |
141 | :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, | 142 | :help => _('Click on this icon to go to the <b>%s</b>\'s home page') % profile.name, |
142 | - :title => profile.name ), | 143 | + :title => profile.name ).html_safe, |
143 | :class => 'vcard'), :class => 'common-profile-list-block') | 144 | :class => 'vcard'), :class => 'common-profile-list-block') |
144 | end | 145 | end |
145 | end | 146 | end |
@@ -0,0 +1,25 @@ | @@ -0,0 +1,25 @@ | ||
1 | +module SanitizeHelper | ||
2 | + | ||
3 | + def sanitize_html(text, type= :full_sanitize) | ||
4 | + sanitizer(type).sanitize(text, scrubber: permit_scrubber) | ||
5 | + end | ||
6 | + | ||
7 | + def sanitize_link(text) | ||
8 | + sanitizer(:white_list).sanitize(text, scrubber:permit_scrubber) | ||
9 | + end | ||
10 | + | ||
11 | +protected | ||
12 | + | ||
13 | + def permit_scrubber | ||
14 | + scrubber = Rails::Html::PermitScrubber.new | ||
15 | + scrubber.tags = Rails.application.config.action_view.sanitized_allowed_tags | ||
16 | + scrubber.attributes = Rails.application.config.action_view.sanitized_allowed_attributes | ||
17 | + scrubber | ||
18 | + end | ||
19 | + | ||
20 | + def sanitizer type = :full_sanitize | ||
21 | + return HTML::WhiteListSanitizer.new if type == :white_list | ||
22 | + HTML::FullSanitizer.new | ||
23 | + end | ||
24 | + | ||
25 | +end |
app/helpers/search_helper.rb
@@ -124,10 +124,10 @@ module SearchHelper | @@ -124,10 +124,10 @@ module SearchHelper | ||
124 | def filters(asset) | 124 | def filters(asset) |
125 | return if !asset | 125 | return if !asset |
126 | klass = asset_class(asset) | 126 | klass = asset_class(asset) |
127 | - content_tag('div', klass::SEARCH_FILTERS.map do |name, options| | 127 | + content_tag('div', safe_join(klass::SEARCH_FILTERS.map do |name, options| |
128 | default = klass.respond_to?("default_search_#{name}") ? klass.send("default_search_#{name}".to_s) : nil | 128 | default = klass.respond_to?("default_search_#{name}") ? klass.send("default_search_#{name}".to_s) : nil |
129 | select_filter(name, options, default) | 129 | select_filter(name, options, default) |
130 | - end.join("\n"), :id => 'search-filters') | 130 | + end, "\n"), :id => 'search-filters') |
131 | end | 131 | end |
132 | 132 | ||
133 | def assets_menu(selected) | 133 | def assets_menu(selected) |
@@ -137,11 +137,11 @@ module SearchHelper | @@ -137,11 +137,11 @@ module SearchHelper | ||
137 | # menu. | 137 | # menu. |
138 | assets.delete(:events) | 138 | assets.delete(:events) |
139 | content_tag('ul', | 139 | content_tag('ul', |
140 | - assets.map do |asset| | 140 | + safe_join(assets.map do |asset| |
141 | options = {} | 141 | options = {} |
142 | options.merge!(:class => 'selected') if selected.to_s == asset.to_s | 142 | options.merge!(:class => 'selected') if selected.to_s == asset.to_s |
143 | content_tag('li', asset_link(asset), options) | 143 | content_tag('li', asset_link(asset), options) |
144 | - end.join("\n"), | 144 | + end, "\n"), |
145 | :id => 'assets-menu') | 145 | :id => 'assets-menu') |
146 | end | 146 | end |
147 | 147 |
app/helpers/tags_helper.rb
@@ -58,7 +58,7 @@ module TagsHelper | @@ -58,7 +58,7 @@ module TagsHelper | ||
58 | 58 | ||
59 | if options[:show_count] | 59 | if options[:show_count] |
60 | display_count = options[:show_count] ? "<small><sup>(#{count})</sup></small>" : "" | 60 | display_count = options[:show_count] ? "<small><sup>(#{count})</sup></small>" : "" |
61 | - link_to tag + display_count, destination, :style => style | 61 | + link_to (tag + display_count).html_safe, destination, :style => style |
62 | else | 62 | else |
63 | link_to h(tag) , destination, :style => style, | 63 | link_to h(tag) , destination, :style => style, |
64 | :title => n_( 'one item', '%d items', count ) % count | 64 | :title => n_( 'one item', '%d items', count ) % count |
app/helpers/tinymce_helper.rb
@@ -7,7 +7,7 @@ module TinymceHelper | @@ -7,7 +7,7 @@ module TinymceHelper | ||
7 | output += javascript_include_tag 'tinymce/js/tinymce/jquery.tinymce.min.js' | 7 | output += javascript_include_tag 'tinymce/js/tinymce/jquery.tinymce.min.js' |
8 | output += javascript_include_tag 'tinymce.js' | 8 | output += javascript_include_tag 'tinymce.js' |
9 | output += include_macro_js_files.to_s | 9 | output += include_macro_js_files.to_s |
10 | - output | 10 | + output.html_safe |
11 | end | 11 | end |
12 | 12 | ||
13 | def tinymce_init_js options = {} | 13 | def tinymce_init_js options = {} |
@@ -37,7 +37,7 @@ module TinymceHelper | @@ -37,7 +37,7 @@ module TinymceHelper | ||
37 | #cleanup non tinymce options | 37 | #cleanup non tinymce options |
38 | options = options.except :mode | 38 | options = options.except :mode |
39 | 39 | ||
40 | - "noosfero.tinymce.init(#{options.to_json})" | 40 | + "noosfero.tinymce.init(#{options.to_json})".html_safe |
41 | end | 41 | end |
42 | 42 | ||
43 | def menubar mode | 43 | def menubar mode |
app/helpers/users_helper.rb
1 | module UsersHelper | 1 | module UsersHelper |
2 | 2 | ||
3 | - FILTER_TRANSLATION = { | 3 | + def filter_translation |
4 | + { | ||
4 | 'all_users' => _('All users'), | 5 | 'all_users' => _('All users'), |
5 | 'admin_users' => _('Admin users'), | 6 | 'admin_users' => _('Admin users'), |
6 | 'activated_users' => _('Activated users'), | 7 | 'activated_users' => _('Activated users'), |
7 | 'deactivated_users' => _('Deativated users'), | 8 | 'deactivated_users' => _('Deativated users'), |
8 | - } | 9 | + } |
10 | + end | ||
9 | 11 | ||
10 | def filter_selector(filter, float = 'right') | 12 | def filter_selector(filter, float = 'right') |
11 | - options = options_for_select(FILTER_TRANSLATION.map {|key, name| [name, key]}, :selected => filter) | 13 | + options = options_for_select(filter_translation.map {|key, name| [name, key]}, :selected => filter) |
12 | url_params = url_for(params.merge(:filter => 'FILTER')) | 14 | url_params = url_for(params.merge(:filter => 'FILTER')) |
13 | onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)" | 15 | onchange = "document.location.href = '#{url_params}'.replace('FILTER', this.value)" |
14 | select_field = select_tag(:filter, options, :onchange => onchange) | 16 | select_field = select_tag(:filter, options, :onchange => onchange) |
@@ -19,7 +21,7 @@ module UsersHelper | @@ -19,7 +21,7 @@ module UsersHelper | ||
19 | end | 21 | end |
20 | 22 | ||
21 | def users_filter_title(filter) | 23 | def users_filter_title(filter) |
22 | - FILTER_TRANSLATION[filter] | 24 | + filter_translation[filter] |
23 | end | 25 | end |
24 | 26 | ||
25 | end | 27 | end |
@@ -0,0 +1,14 @@ | @@ -0,0 +1,14 @@ | ||
1 | +class ActivitiesCounterCacheJob | ||
2 | + | ||
3 | + def perform | ||
4 | + person_activities_counts = ApplicationRecord.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.user_id WHERE (action_tracker.created_at >= #{ApplicationRecord.connection.quote(ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db))}) AND ( (profiles.type = 'Person' ) ) GROUP BY profiles.id;") | ||
5 | + organization_activities_counts = ApplicationRecord.connection.execute("SELECT profiles.id, count(action_tracker.id) as count FROM profiles LEFT OUTER JOIN action_tracker ON profiles.id = action_tracker.target_id WHERE (action_tracker.created_at >= #{ApplicationRecord.connection.quote(ActionTracker::Record::RECENT_DELAY.days.ago.to_s(:db))}) AND ( (profiles.type = 'Community' OR profiles.type = 'Enterprise' OR profiles.type = 'Organization' ) ) GROUP BY profiles.id;") | ||
6 | + activities_counts = person_activities_counts.entries + organization_activities_counts.entries | ||
7 | + activities_counts.each do |count| | ||
8 | + update_sql = ApplicationRecord.__send__(:sanitize_sql, ["UPDATE profiles SET activities_count=? WHERE profiles.id=?;", count['count'].to_i, count['id'] ], '') | ||
9 | + ApplicationRecord.connection.execute(update_sql) | ||
10 | + end | ||
11 | + Delayed::Job.enqueue(ActivitiesCounterCacheJob.new, {:priority => -3, :run_at => 1.day.from_now}) | ||
12 | + end | ||
13 | + | ||
14 | +end |
@@ -0,0 +1,11 @@ | @@ -0,0 +1,11 @@ | ||
1 | +class CreateThumbnailsJob < Struct.new(:class_name, :file_id) | ||
2 | + def perform | ||
3 | + return unless class_name.constantize.exists?(file_id) | ||
4 | + file = class_name.constantize.find(file_id) | ||
5 | + file.create_thumbnails | ||
6 | + article = Article.where(:image_id => file_id).first | ||
7 | + if article | ||
8 | + article.touch | ||
9 | + end | ||
10 | + end | ||
11 | +end |
app/mailers/environment_mailing.rb
1 | class EnvironmentMailing < Mailing | 1 | class EnvironmentMailing < Mailing |
2 | 2 | ||
3 | + settings_items :recipients_roles, :type => :array | ||
4 | + attr_accessible :recipients_roles | ||
5 | + | ||
3 | def recipients(offset=0, limit=100) | 6 | def recipients(offset=0, limit=100) |
4 | - source.people.order(:id).offset(offset).limit(limit) | 7 | + recipients_by_role.order(:id).offset(offset).limit(limit) |
5 | .joins("LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)") | 8 | .joins("LEFT OUTER JOIN mailing_sents m ON (m.mailing_id = #{id} AND m.person_id = profiles.id)") |
6 | .where("m.person_id" => nil) | 9 | .where("m.person_id" => nil) |
7 | end | 10 | end |
8 | 11 | ||
12 | + def recipients_by_role | ||
13 | + if recipients_roles.blank? | ||
14 | + source.people | ||
15 | + else | ||
16 | + roles = Environment::Role.where("key in (?)", self.recipients_roles) | ||
17 | + Person.by_role(roles).where(environment_id: self.source_id) | ||
18 | + end | ||
19 | + end | ||
20 | + | ||
9 | def each_recipient | 21 | def each_recipient |
10 | offset = 0 | 22 | offset = 0 |
11 | limit = 100 | 23 | limit = 100 |
app/mailers/mailing.rb
app/models/abuse_report.rb
app/models/action_tracker_notification.rb
1 | -class ActionTrackerNotification < ActiveRecord::Base | 1 | +class ActionTrackerNotification < ApplicationRecord |
2 | 2 | ||
3 | belongs_to :profile | 3 | belongs_to :profile |
4 | belongs_to :action_tracker, :class_name => 'ActionTracker::Record', :foreign_key => 'action_tracker_id' | 4 | belongs_to :action_tracker, :class_name => 'ActionTracker::Record', :foreign_key => 'action_tracker_id' |
app/models/add_member.rb
@@ -29,16 +29,18 @@ class AddMember < Task | @@ -29,16 +29,18 @@ class AddMember < Task | ||
29 | end | 29 | end |
30 | 30 | ||
31 | def information | 31 | def information |
32 | - requestor_email = " (#{requestor.email})" if requestor.may_display_field_to?("email") | ||
33 | - | ||
34 | - {:message => _("%{requestor}%{requestor_email} wants to be a member of '%{organization}'."), | ||
35 | - variables: {requestor: requestor.name, requestor_email: requestor_email, organization: organization.name}} | 32 | + {:message => _("%{requestor} wants to be a member of '%{target}'."), |
33 | + variables: {requestor: requestor.name, target: target.name}} | ||
36 | end | 34 | end |
37 | 35 | ||
38 | def accept_details | 36 | def accept_details |
39 | true | 37 | true |
40 | end | 38 | end |
41 | 39 | ||
40 | + def footer | ||
41 | + true | ||
42 | + end | ||
43 | + | ||
42 | def icon | 44 | def icon |
43 | {:type => :profile_image, :profile => requestor, :url => requestor.url} | 45 | {:type => :profile_image, :profile => requestor, :url => requestor.url} |
44 | end | 46 | end |
@@ -63,4 +65,15 @@ class AddMember < Task | @@ -63,4 +65,15 @@ class AddMember < Task | ||
63 | suggestion.disable if suggestion | 65 | suggestion.disable if suggestion |
64 | end | 66 | end |
65 | 67 | ||
68 | + def task_finished_message | ||
69 | + _("You have been accepted at \"%{target}\" with the profile \"%{requestor}\"") % | ||
70 | + {:target => self.target.name, | ||
71 | + :requestor => self.requestor.name} | ||
72 | + end | ||
73 | + | ||
74 | + def task_cancelled_message | ||
75 | + _("Your request to enter community \"%{target} with the profile \"%{requestor}\" was not accepted. Please contact any profile admin from %{url} for more information.") % | ||
76 | + {:target => self.target.name, :url => self.target.url, | ||
77 | + :requestor => self.requestor.name} | ||
78 | + end | ||
66 | end | 79 | end |
@@ -0,0 +1,61 @@ | @@ -0,0 +1,61 @@ | ||
1 | +class ApplicationRecord < ActiveRecord::Base | ||
2 | + | ||
3 | + self.abstract_class = true | ||
4 | + self.store_full_sti_class = true | ||
5 | + | ||
6 | + # an ActionView instance for rendering views on models | ||
7 | + def self.action_view | ||
8 | + @action_view ||= begin | ||
9 | + view_paths = ::ActionController::Base.view_paths | ||
10 | + action_view = ::ActionView::Base.new view_paths | ||
11 | + # for using Noosfero helpers inside render calls | ||
12 | + action_view.extend ::ApplicationHelper | ||
13 | + action_view | ||
14 | + end | ||
15 | + end | ||
16 | + | ||
17 | + # default value needed for the above ActionView | ||
18 | + def to_partial_path | ||
19 | + self.class.name.underscore | ||
20 | + end | ||
21 | + | ||
22 | + alias :meta_cache_key :cache_key | ||
23 | + def cache_key | ||
24 | + key = [Noosfero::VERSION, meta_cache_key] | ||
25 | + key.unshift ApplicationRecord.connection.schema_search_path | ||
26 | + key.join('/') | ||
27 | + end | ||
28 | + | ||
29 | + def self.like_search(query, options={}) | ||
30 | + if defined?(self::SEARCHABLE_FIELDS) || options[:fields].present? | ||
31 | + fields_per_table = {} | ||
32 | + fields_per_table[table_name] = (options[:fields].present? ? options[:fields] : self::SEARCHABLE_FIELDS.keys.map(&:to_s)) & column_names | ||
33 | + | ||
34 | + if options[:joins].present? | ||
35 | + join_asset = options[:joins].to_s.classify.constantize | ||
36 | + if defined?(join_asset::SEARCHABLE_FIELDS) || options[:fields].present? | ||
37 | + fields_per_table[join_asset.table_name] = (options[:fields].present? ? options[:fields] : join_asset::SEARCHABLE_FIELDS.keys.map(&:to_s)) & join_asset.column_names | ||
38 | + end | ||
39 | + end | ||
40 | + | ||
41 | + query = query.downcase.strip | ||
42 | + fields_per_table.delete_if { |table,fields| fields.blank? } | ||
43 | + conditions = fields_per_table.map do |table,fields| | ||
44 | + fields.map do |field| | ||
45 | + "lower(#{table}.#{field}) LIKE '%#{query}%'" | ||
46 | + end.join(' OR ') | ||
47 | + end.join(' OR ') | ||
48 | + | ||
49 | + if options[:joins].present? | ||
50 | + joins(options[:joins]).where(conditions) | ||
51 | + else | ||
52 | + where(conditions) | ||
53 | + end | ||
54 | + | ||
55 | + else | ||
56 | + raise "No searchable fields defined for #{self.name}" | ||
57 | + end | ||
58 | + end | ||
59 | + | ||
60 | +end | ||
61 | + |
app/models/approve_article.rb
@@ -86,7 +86,7 @@ class ApproveArticle < Task | @@ -86,7 +86,7 @@ class ApproveArticle < Task | ||
86 | 86 | ||
87 | def information | 87 | def information |
88 | if article | 88 | if article |
89 | - {:message => _('%{requestor} wants to publish the article: %{linked_subject}.')} | 89 | + {:message => _('%{requestor} wants to publish the article: %{linked_subject}.').html_safe} |
90 | else | 90 | else |
91 | {:message => _("The article was removed.")} | 91 | {:message => _("The article was removed.")} |
92 | end | 92 | end |
app/models/article.rb
1 | 1 | ||
2 | -class Article < ActiveRecord::Base | 2 | +class Article < ApplicationRecord |
3 | + | ||
4 | + include SanitizeHelper | ||
3 | 5 | ||
4 | attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, | 6 | attr_accessible :name, :body, :abstract, :profile, :tag_list, :parent, |
5 | :allow_members_to_edit, :translation_of_id, :language, | 7 | :allow_members_to_edit, :translation_of_id, :language, |
@@ -54,6 +56,7 @@ class Article < ActiveRecord::Base | @@ -54,6 +56,7 @@ class Article < ActiveRecord::Base | ||
54 | track_actions :create_article, :after_create, :keep_params => [:name, :url, :lead, :first_image], :if => Proc.new { |a| a.is_trackable? && !a.image? } | 56 | track_actions :create_article, :after_create, :keep_params => [:name, :url, :lead, :first_image], :if => Proc.new { |a| a.is_trackable? && !a.image? } |
55 | 57 | ||
56 | # xss_terminate plugin can't sanitize array fields | 58 | # xss_terminate plugin can't sanitize array fields |
59 | + # sanitize_tag_list is used with SanitizeHelper | ||
57 | before_save :sanitize_tag_list | 60 | before_save :sanitize_tag_list |
58 | 61 | ||
59 | before_create do |article| | 62 | before_create do |article| |
@@ -601,7 +604,7 @@ class Article < ActiveRecord::Base | @@ -601,7 +604,7 @@ class Article < ActiveRecord::Base | ||
601 | end | 604 | end |
602 | 605 | ||
603 | def accept_category?(cat) | 606 | def accept_category?(cat) |
604 | - !cat.is_a?(ProductCategory) | 607 | + true |
605 | end | 608 | end |
606 | 609 | ||
607 | def public? | 610 | def public? |
@@ -803,11 +806,13 @@ class Article < ActiveRecord::Base | @@ -803,11 +806,13 @@ class Article < ActiveRecord::Base | ||
803 | end | 806 | end |
804 | 807 | ||
805 | def body_images_paths | 808 | def body_images_paths |
806 | - Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i| | 809 | + paths = Nokogiri::HTML.fragment(self.body.to_s).css('img[src]').collect do |i| |
807 | src = i['src'] | 810 | src = i['src'] |
808 | src = URI.escape src if self.new_record? # xss_terminate runs on save | 811 | src = URI.escape src if self.new_record? # xss_terminate runs on save |
809 | (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, src).to_s : src | 812 | (self.profile && self.profile.environment) ? URI.join(self.profile.environment.top_url, src).to_s : src |
810 | end | 813 | end |
814 | + paths.unshift(URI.join(self.profile.environment.top_url, self.image.public_filename).to_s) if self.image.present? | ||
815 | + paths | ||
811 | end | 816 | end |
812 | 817 | ||
813 | def more_comments_label | 818 | def more_comments_label |
@@ -859,6 +864,10 @@ class Article < ActiveRecord::Base | @@ -859,6 +864,10 @@ class Article < ActiveRecord::Base | ||
859 | HashWithIndifferentAccess.new :name => name, :abstract => abstract, :body => body, :id => id, :parent_id => parent_id, :author => author | 864 | HashWithIndifferentAccess.new :name => name, :abstract => abstract, :body => body, :id => id, :parent_id => parent_id, :author => author |
860 | end | 865 | end |
861 | 866 | ||
867 | + def self.can_display_blocks? | ||
868 | + true | ||
869 | + end | ||
870 | + | ||
862 | private | 871 | private |
863 | 872 | ||
864 | def sanitize_tag_list | 873 | def sanitize_tag_list |
@@ -870,11 +879,6 @@ class Article < ActiveRecord::Base | @@ -870,11 +879,6 @@ class Article < ActiveRecord::Base | ||
870 | tag_name.gsub(/[<>]/, '') | 879 | tag_name.gsub(/[<>]/, '') |
871 | end | 880 | end |
872 | 881 | ||
873 | - def sanitize_html(text) | ||
874 | - sanitizer = HTML::FullSanitizer.new | ||
875 | - sanitizer.sanitize(text) | ||
876 | - end | ||
877 | - | ||
878 | def parent_archived? | 882 | def parent_archived? |
879 | if self.parent_id_changed? && self.parent && self.parent.archived? | 883 | if self.parent_id_changed? && self.parent && self.parent.archived? |
880 | errors.add(:parent_folder, N_('is archived!!')) | 884 | errors.add(:parent_folder, N_('is archived!!')) |
app/models/article_categorization.rb
app/models/article_follower.rb
app/models/block.rb
1 | -class Block < ActiveRecord::Base | 1 | +class Block < ApplicationRecord |
2 | 2 | ||
3 | attr_accessible :title, :subtitle, :display, :limit, :box_id, :posts_per_page, | 3 | attr_accessible :title, :subtitle, :display, :limit, :box_id, :posts_per_page, |
4 | :visualization_format, :language, :display_user, | 4 | :visualization_format, :language, :display_user, |
@@ -76,6 +76,17 @@ class Block < ActiveRecord::Base | @@ -76,6 +76,17 @@ class Block < ActiveRecord::Base | ||
76 | true | 76 | true |
77 | end | 77 | end |
78 | 78 | ||
79 | + def visible_to_user?(user) | ||
80 | + visible = self.display_to_user?(user) | ||
81 | + if self.owner.kind_of?(Profile) | ||
82 | + visible &= self.owner.display_info_to?(user) | ||
83 | + visible &= (self.visible? || user && user.has_permission?(:edit_profile_design, self.owner)) | ||
84 | + elsif self.owner.kind_of?(Environment) | ||
85 | + visible &= (self.visible? || user && user.has_permission?(:edit_environment_design, self.owner)) | ||
86 | + end | ||
87 | + visible | ||
88 | + end | ||
89 | + | ||
79 | def display_to_user?(user) | 90 | def display_to_user?(user) |
80 | display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && user.follows?(owner)) | 91 | display_user == 'all' || (user.nil? && display_user == 'not_logged') || (user && display_user == 'logged') || (user && display_user == 'followers' && user.follows?(owner)) |
81 | end | 92 | end |
@@ -314,6 +325,14 @@ class Block < ActiveRecord::Base | @@ -314,6 +325,14 @@ class Block < ActiveRecord::Base | ||
314 | self.observers << block | 325 | self.observers << block |
315 | end | 326 | end |
316 | 327 | ||
328 | + def api_content | ||
329 | + nil | ||
330 | + end | ||
331 | + | ||
332 | + def display_api_content_by_default? | ||
333 | + false | ||
334 | + end | ||
335 | + | ||
317 | private | 336 | private |
318 | 337 | ||
319 | def home_page_path | 338 | def home_page_path |
app/models/box.rb
1 | -class Box < ActiveRecord::Base | 1 | +class Box < ApplicationRecord |
2 | 2 | ||
3 | acts_as_list scope: -> box { where owner_id: box.owner_id, owner_type: box.owner_type } | 3 | acts_as_list scope: -> box { where owner_id: box.owner_id, owner_type: box.owner_type } |
4 | 4 | ||
@@ -41,7 +41,6 @@ class Box < ActiveRecord::Base | @@ -41,7 +41,6 @@ class Box < ActiveRecord::Base | ||
41 | ProfileImageBlock, | 41 | ProfileImageBlock, |
42 | RawHTMLBlock, | 42 | RawHTMLBlock, |
43 | RecentDocumentsBlock, | 43 | RecentDocumentsBlock, |
44 | - SellersSearchBlock, | ||
45 | TagsBlock ] | 44 | TagsBlock ] |
46 | end | 45 | end |
47 | 46 | ||
@@ -54,21 +53,17 @@ class Box < ActiveRecord::Base | @@ -54,21 +53,17 @@ class Box < ActiveRecord::Base | ||
54 | EnterprisesBlock, | 53 | EnterprisesBlock, |
55 | FansBlock, | 54 | FansBlock, |
56 | FavoriteEnterprisesBlock, | 55 | FavoriteEnterprisesBlock, |
57 | - FeaturedProductsBlock, | ||
58 | FeedReaderBlock, | 56 | FeedReaderBlock, |
59 | HighlightsBlock, | 57 | HighlightsBlock, |
60 | LinkListBlock, | 58 | LinkListBlock, |
61 | LocationBlock, | 59 | LocationBlock, |
62 | LoginBlock, | 60 | LoginBlock, |
63 | MyNetworkBlock, | 61 | MyNetworkBlock, |
64 | - ProductsBlock, | ||
65 | - ProductCategoriesBlock, | ||
66 | ProfileImageBlock, | 62 | ProfileImageBlock, |
67 | ProfileInfoBlock, | 63 | ProfileInfoBlock, |
68 | ProfileSearchBlock, | 64 | ProfileSearchBlock, |
69 | RawHTMLBlock, | 65 | RawHTMLBlock, |
70 | RecentDocumentsBlock, | 66 | RecentDocumentsBlock, |
71 | - SellersSearchBlock, | ||
72 | SlideshowBlock, | 67 | SlideshowBlock, |
73 | TagsBlock | 68 | TagsBlock |
74 | ] | 69 | ] |
app/models/category.rb
1 | -class Category < ActiveRecord::Base | 1 | +class Category < ApplicationRecord |
2 | 2 | ||
3 | attr_accessible :name, :parent_id, :display_color, :display_in_menu, :image_builder, :environment, :parent | 3 | attr_accessible :name, :parent_id, :display_color, :display_in_menu, :image_builder, :environment, :parent |
4 | 4 | ||
@@ -35,8 +35,6 @@ class Category < ActiveRecord::Base | @@ -35,8 +35,6 @@ class Category < ActiveRecord::Base | ||
35 | has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' | 35 | has_many :people, :through => :profile_categorizations, :source => :profile, :class_name => 'Person' |
36 | has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community' | 36 | has_many :communities, :through => :profile_categorizations, :source => :profile, :class_name => 'Community' |
37 | 37 | ||
38 | - has_many :products, :through => :enterprises | ||
39 | - | ||
40 | acts_as_having_image | 38 | acts_as_having_image |
41 | 39 | ||
42 | before_save :normalize_display_color | 40 | before_save :normalize_display_color |
@@ -64,10 +62,6 @@ class Category < ActiveRecord::Base | @@ -64,10 +62,6 @@ class Category < ActiveRecord::Base | ||
64 | self.communities.reorder('created_at DESC, id DESC').paginate(page: 1, per_page: limit) | 62 | self.communities.reorder('created_at DESC, id DESC').paginate(page: 1, per_page: limit) |
65 | end | 63 | end |
66 | 64 | ||
67 | - def recent_products(limit = 10) | ||
68 | - self.products.reorder('created_at DESC, id DESC').paginate(page: 1, per_page: limit) | ||
69 | - end | ||
70 | - | ||
71 | def recent_articles(limit = 10) | 65 | def recent_articles(limit = 10) |
72 | self.articles.recent(limit) | 66 | self.articles.recent(limit) |
73 | end | 67 | end |
app/models/chat_message.rb
app/models/comment.rb
app/models/community.rb
@@ -2,6 +2,7 @@ class Community < Organization | @@ -2,6 +2,7 @@ class Community < Organization | ||
2 | 2 | ||
3 | attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type | 3 | attr_accessible :accessor_id, :accessor_type, :role_id, :resource_id, :resource_type |
4 | attr_accessible :address_reference, :district, :tag_list, :language, :description | 4 | attr_accessible :address_reference, :district, :tag_list, :language, :description |
5 | + attr_accessible :requires_email | ||
5 | after_destroy :check_invite_member_for_destroy | 6 | after_destroy :check_invite_member_for_destroy |
6 | 7 | ||
7 | def self.type_name | 8 | def self.type_name |
@@ -12,6 +13,9 @@ class Community < Organization | @@ -12,6 +13,9 @@ class Community < Organization | ||
12 | N_('Language') | 13 | N_('Language') |
13 | 14 | ||
14 | settings_items :language | 15 | settings_items :language |
16 | + settings_items :requires_email, :type => :boolean | ||
17 | + | ||
18 | + alias_method :requires_email?, :requires_email | ||
15 | 19 | ||
16 | extend SetProfileRegionFromCityState::ClassMethods | 20 | extend SetProfileRegionFromCityState::ClassMethods |
17 | set_profile_region_from_city_state | 21 | set_profile_region_from_city_state |
app/models/contact_list.rb
app/models/create_community.rb
@@ -60,9 +60,9 @@ class CreateCommunity < Task | @@ -60,9 +60,9 @@ class CreateCommunity < Task | ||
60 | 60 | ||
61 | def information | 61 | def information |
62 | if description.blank? | 62 | if description.blank? |
63 | - { :message => _('%{requestor} wants to create community %{subject} with no description.') } | 63 | + { :message => _('%{requestor} wants to create community %{subject} with no description.').html_safe } |
64 | else | 64 | else |
65 | - { :message => _('%{requestor} wants to create community %{subject} with this description:<p><em>%{description}</em></p>'), | 65 | + { :message => _('%{requestor} wants to create community %{subject} with this description:<p><em>%{description}</em></p>').html_safe, |
66 | :variables => {:description => description} } | 66 | :variables => {:description => description} } |
67 | end | 67 | end |
68 | end | 68 | end |
app/models/create_enterprise.rb
@@ -163,7 +163,7 @@ class CreateEnterprise < Task | @@ -163,7 +163,7 @@ class CreateEnterprise < Task | ||
163 | end | 163 | end |
164 | 164 | ||
165 | def information | 165 | def information |
166 | - {:message => _('%{requestor} wants to create enterprise %{subject}.')} | 166 | + {:message => _('%{requestor} wants to create enterprise %{subject}.').html_safe} |
167 | end | 167 | end |
168 | 168 | ||
169 | def reject_details | 169 | def reject_details |
app/models/custom_field.rb
1 | -class CustomField < ActiveRecord::Base | 1 | +class CustomField < ApplicationRecord |
2 | + | ||
2 | attr_accessible :name, :default_value, :format, :extras, :customized_type, :active, :required, :signup, :environment, :moderation_task | 3 | attr_accessible :name, :default_value, :format, :extras, :customized_type, :active, :required, :signup, :environment, :moderation_task |
3 | serialize :customized_type | 4 | serialize :customized_type |
4 | serialize :extras | 5 | serialize :extras |
app/models/custom_field_value.rb
1 | -class CustomFieldValue < ActiveRecord::Base | 1 | +class CustomFieldValue < ApplicationRecord |
2 | + | ||
2 | belongs_to :custom_field | 3 | belongs_to :custom_field |
3 | belongs_to :customized, :polymorphic => true | 4 | belongs_to :customized, :polymorphic => true |
4 | attr_accessible :value, :public, :customized, :custom_field, :customized_type | 5 | attr_accessible :value, :public, :customized, :custom_field, :customized_type |
app/models/doc_item.rb
app/models/domain.rb
app/models/email_template.rb
app/models/enterprise.rb
1 | -# An enterprise is a kind of organization. According to the system concept, | ||
2 | -# only enterprises can offer products and services. | ||
3 | class Enterprise < Organization | 1 | class Enterprise < Organization |
4 | 2 | ||
5 | - attr_accessible :business_name, :address_reference, :district, :tag_list, :organization_website, :historic_and_current_context, :activities_short_description, :products_per_catalog_page | 3 | + attr_accessible :business_name, :address_reference, :district, :tag_list, |
4 | + :organization_website, :historic_and_current_context, :activities_short_description | ||
6 | 5 | ||
7 | SEARCH_FILTERS = { | 6 | SEARCH_FILTERS = { |
8 | :order => %w[more_recent more_popular more_active], | 7 | :order => %w[more_recent more_popular more_active], |
@@ -17,11 +16,6 @@ class Enterprise < Organization | @@ -17,11 +16,6 @@ class Enterprise < Organization | ||
17 | 16 | ||
18 | acts_as_trackable after_add: proc{ |p, t| notify_activity t } | 17 | acts_as_trackable after_add: proc{ |p, t| notify_activity t } |
19 | 18 | ||
20 | - has_many :products, :foreign_key => :profile_id, :dependent => :destroy | ||
21 | - has_many :product_categories, :through => :products | ||
22 | - has_many :inputs, :through => :products | ||
23 | - has_many :production_costs, :as => :owner | ||
24 | - | ||
25 | has_many :favorite_enterprise_people | 19 | has_many :favorite_enterprise_people |
26 | has_many :fans, source: :person, through: :favorite_enterprise_people | 20 | has_many :fans, source: :person, through: :favorite_enterprise_people |
27 | 21 | ||
@@ -29,10 +23,6 @@ class Enterprise < Organization | @@ -29,10 +23,6 @@ class Enterprise < Organization | ||
29 | 23 | ||
30 | settings_items :organization_website, :historic_and_current_context, :activities_short_description | 24 | settings_items :organization_website, :historic_and_current_context, :activities_short_description |
31 | 25 | ||
32 | - settings_items :products_per_catalog_page, :type => :integer, :default => 6 | ||
33 | - alias_method :products_per_catalog_page_before_type_cast, :products_per_catalog_page | ||
34 | - validates_numericality_of :products_per_catalog_page, :allow_nil => true, :greater_than => 0 | ||
35 | - | ||
36 | extend SetProfileRegionFromCityState::ClassMethods | 26 | extend SetProfileRegionFromCityState::ClassMethods |
37 | set_profile_region_from_city_state | 27 | set_profile_region_from_city_state |
38 | 28 | ||
@@ -66,10 +56,6 @@ class Enterprise < Organization | @@ -66,10 +56,6 @@ class Enterprise < Organization | ||
66 | environment ? environment.active_enterprise_fields : [] | 56 | environment ? environment.active_enterprise_fields : [] |
67 | end | 57 | end |
68 | 58 | ||
69 | - def highlighted_products_with_image(options = {}) | ||
70 | - Product.where(:highlighted => true).joins(:image) | ||
71 | - end | ||
72 | - | ||
73 | def required_fields | 59 | def required_fields |
74 | environment ? environment.required_enterprise_fields : [] | 60 | environment ? environment.required_enterprise_fields : [] |
75 | end | 61 | end |
@@ -136,19 +122,14 @@ class Enterprise < Organization | @@ -136,19 +122,14 @@ class Enterprise < Organization | ||
136 | links = [ | 122 | links = [ |
137 | {:name => _("Enterprises's profile"), :address => '/profile/{profile}', :icon => 'ok'}, | 123 | {:name => _("Enterprises's profile"), :address => '/profile/{profile}', :icon => 'ok'}, |
138 | {:name => _('Blog'), :address => '/{profile}/blog', :icon => 'edit'}, | 124 | {:name => _('Blog'), :address => '/{profile}/blog', :icon => 'edit'}, |
139 | - {:name => _('Products'), :address => '/catalog/{profile}', :icon => 'new'}, | ||
140 | ] | 125 | ] |
141 | blocks = [ | 126 | blocks = [ |
142 | [MainBlock.new], | 127 | [MainBlock.new], |
143 | [ ProfileImageBlock.new, | 128 | [ ProfileImageBlock.new, |
144 | LinkListBlock.new(:links => links), | 129 | LinkListBlock.new(:links => links), |
145 | - ProductCategoriesBlock.new | ||
146 | ], | 130 | ], |
147 | [LocationBlock.new] | 131 | [LocationBlock.new] |
148 | ] | 132 | ] |
149 | - if environment.enabled?('products_for_enterprises') | ||
150 | - blocks[2].unshift ProductsBlock.new | ||
151 | - end | ||
152 | blocks | 133 | blocks |
153 | end | 134 | end |
154 | 135 | ||
@@ -189,14 +170,6 @@ class Enterprise < Organization | @@ -189,14 +170,6 @@ class Enterprise < Organization | ||
189 | {:title => _('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'} | 170 | {:title => _('Enterprise Info and settings'), :icon => 'edit-profile-enterprise'} |
190 | end | 171 | end |
191 | 172 | ||
192 | - def create_product? | ||
193 | - true | ||
194 | - end | ||
195 | - | ||
196 | - def catalog_url | ||
197 | - { :profile => identifier, :controller => 'catalog'} | ||
198 | - end | ||
199 | - | ||
200 | def more_recent_label | 173 | def more_recent_label |
201 | '' | 174 | '' |
202 | end | 175 | end |
@@ -205,5 +178,4 @@ class Enterprise < Organization | @@ -205,5 +178,4 @@ class Enterprise < Organization | ||
205 | super or self.fans.where(id: person.id).count > 0 | 178 | super or self.fans.where(id: person.id).count > 0 |
206 | end | 179 | end |
207 | 180 | ||
208 | - | ||
209 | end | 181 | end |
app/models/environment.rb
1 | # A Environment is like a website to be hosted in the platform. It may | 1 | # A Environment is like a website to be hosted in the platform. It may |
2 | # contain multiple Profile's and can be identified by several different | 2 | # contain multiple Profile's and can be identified by several different |
3 | # domains. | 3 | # domains. |
4 | -class Environment < ActiveRecord::Base | 4 | +class Environment < ApplicationRecord |
5 | 5 | ||
6 | attr_accessible :name, :is_default, :signup_welcome_text_subject, | 6 | attr_accessible :name, :is_default, :signup_welcome_text_subject, |
7 | :signup_welcome_text_body, :terms_of_use, | 7 | :signup_welcome_text_body, :terms_of_use, |
@@ -13,7 +13,9 @@ class Environment < ActiveRecord::Base | @@ -13,7 +13,9 @@ class Environment < ActiveRecord::Base | ||
13 | :reports_lower_bound, :noreply_email, | 13 | :reports_lower_bound, :noreply_email, |
14 | :signup_welcome_screen_body, :members_whitelist_enabled, | 14 | :signup_welcome_screen_body, :members_whitelist_enabled, |
15 | :members_whitelist, :highlighted_news_amount, | 15 | :members_whitelist, :highlighted_news_amount, |
16 | - :portal_news_amount, :date_format, :signup_intro | 16 | + :portal_news_amount, :date_format, :signup_intro, |
17 | + :enable_feed_proxy, :http_feed_proxy, :https_feed_proxy, | ||
18 | + :disable_feed_ssl | ||
17 | 19 | ||
18 | has_many :users | 20 | has_many :users |
19 | 21 | ||
@@ -126,7 +128,6 @@ class Environment < ActiveRecord::Base | @@ -126,7 +128,6 @@ class Environment < ActiveRecord::Base | ||
126 | 'disable_asset_enterprises' => _('Disable search for enterprises'), | 128 | 'disable_asset_enterprises' => _('Disable search for enterprises'), |
127 | 'disable_asset_people' => _('Disable search for people'), | 129 | 'disable_asset_people' => _('Disable search for people'), |
128 | 'disable_asset_communities' => _('Disable search for communities'), | 130 | 'disable_asset_communities' => _('Disable search for communities'), |
129 | - 'disable_asset_products' => _('Disable search for products'), | ||
130 | 'disable_asset_events' => _('Disable search for events'), | 131 | 'disable_asset_events' => _('Disable search for events'), |
131 | 'disable_categories' => _('Disable categories'), | 132 | 'disable_categories' => _('Disable categories'), |
132 | 'disable_header_and_footer' => _('Disable header/footer editing by users'), | 133 | 'disable_header_and_footer' => _('Disable header/footer editing by users'), |
@@ -137,7 +138,6 @@ class Environment < ActiveRecord::Base | @@ -137,7 +138,6 @@ class Environment < ActiveRecord::Base | ||
137 | 'disable_contact_community' => _('Disable contact for groups/communities'), | 138 | 'disable_contact_community' => _('Disable contact for groups/communities'), |
138 | 'forbid_destroy_profile' => _('Forbid users of removing profiles'), | 139 | 'forbid_destroy_profile' => _('Forbid users of removing profiles'), |
139 | 140 | ||
140 | - 'products_for_enterprises' => _('Enable products for enterprises'), | ||
141 | 'enterprise_registration' => _('Enterprise registration'), | 141 | 'enterprise_registration' => _('Enterprise registration'), |
142 | 'enterprise_activation' => _('Enable activation of enterprises'), | 142 | 'enterprise_activation' => _('Enable activation of enterprises'), |
143 | 'enterprises_are_disabled_when_created' => _('Enterprises are disabled when created'), | 143 | 'enterprises_are_disabled_when_created' => _('Enterprises are disabled when created'), |
@@ -224,7 +224,6 @@ class Environment < ActiveRecord::Base | @@ -224,7 +224,6 @@ class Environment < ActiveRecord::Base | ||
224 | 224 | ||
225 | has_many :organizations | 225 | has_many :organizations |
226 | has_many :enterprises | 226 | has_many :enterprises |
227 | - has_many :products, :through => :enterprises | ||
228 | has_many :people | 227 | has_many :people |
229 | has_many :communities | 228 | has_many :communities |
230 | has_many :licenses | 229 | has_many :licenses |
@@ -234,23 +233,16 @@ class Environment < ActiveRecord::Base | @@ -234,23 +233,16 @@ class Environment < ActiveRecord::Base | ||
234 | order('display_color').where('display_color is not null and parent_id is null') | 233 | order('display_color').where('display_color is not null and parent_id is null') |
235 | }, class_name: 'Category' | 234 | }, class_name: 'Category' |
236 | 235 | ||
237 | - has_many :product_categories, -> { where type: 'ProductCategory'} | ||
238 | has_many :regions | 236 | has_many :regions |
239 | has_many :states | 237 | has_many :states |
240 | has_many :cities | 238 | has_many :cities |
241 | 239 | ||
242 | has_many :roles, :dependent => :destroy | 240 | has_many :roles, :dependent => :destroy |
243 | 241 | ||
244 | - has_many :qualifiers | ||
245 | - has_many :certifiers | ||
246 | - | ||
247 | has_many :mailings, :class_name => 'EnvironmentMailing', :foreign_key => :source_id, :as => 'source' | 242 | has_many :mailings, :class_name => 'EnvironmentMailing', :foreign_key => :source_id, :as => 'source' |
248 | 243 | ||
249 | acts_as_accessible | 244 | acts_as_accessible |
250 | 245 | ||
251 | - has_many :units, -> { order 'position' } | ||
252 | - has_many :production_costs, :as => :owner | ||
253 | - | ||
254 | def superior_intances | 246 | def superior_intances |
255 | [self, nil] | 247 | [self, nil] |
256 | end | 248 | end |
@@ -439,9 +431,7 @@ class Environment < ActiveRecord::Base | @@ -439,9 +431,7 @@ class Environment < ActiveRecord::Base | ||
439 | end | 431 | end |
440 | 432 | ||
441 | DEFAULT_FEATURES = %w( | 433 | DEFAULT_FEATURES = %w( |
442 | - disable_asset_products | ||
443 | disable_gender_icon | 434 | disable_gender_icon |
444 | - products_for_enterprises | ||
445 | disable_select_city_for_contact | 435 | disable_select_city_for_contact |
446 | enterprise_registration | 436 | enterprise_registration |
447 | media_panel | 437 | media_panel |
@@ -729,7 +719,7 @@ class Environment < ActiveRecord::Base | @@ -729,7 +719,7 @@ class Environment < ActiveRecord::Base | ||
729 | url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname) | 719 | url << (Noosfero.url_options.key?(:host) ? Noosfero.url_options[:host] : default_hostname) |
730 | url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port) | 720 | url << ':' << Noosfero.url_options[:port].to_s if Noosfero.url_options.key?(:port) |
731 | url << Noosfero.root('') | 721 | url << Noosfero.root('') |
732 | - url | 722 | + url.html_safe |
733 | end | 723 | end |
734 | 724 | ||
735 | def to_s | 725 | def to_s |
@@ -966,10 +956,6 @@ class Environment < ActiveRecord::Base | @@ -966,10 +956,6 @@ class Environment < ActiveRecord::Base | ||
966 | end | 956 | end |
967 | end | 957 | end |
968 | 958 | ||
969 | - def highlighted_products_with_image(options = {}) | ||
970 | - self.products.where(highlighted: true).joins(:image).order('created_at ASC') | ||
971 | - end | ||
972 | - | ||
973 | settings_items :home_cache_in_minutes, :type => :integer, :default => 5 | 959 | settings_items :home_cache_in_minutes, :type => :integer, :default => 5 |
974 | settings_items :general_cache_in_minutes, :type => :integer, :default => 15 | 960 | settings_items :general_cache_in_minutes, :type => :integer, :default => 15 |
975 | settings_items :profile_cache_in_minutes, :type => :integer, :default => 15 | 961 | settings_items :profile_cache_in_minutes, :type => :integer, :default => 15 |