Commit 100df3575f11f2c551eb1e950440e3f648f19b98
1 parent
ea20a3dc
Exists in
web_steps_improvements
and in
8 other branches
API improvements
- changes pagination to use api-pagination gem - new endpoints to boxes, activities, and profiles - new exposed attributes for some entities - other minor changes Signed-off-by: Leandro Nunes dos Santos <leandronunes@gmail.com> Signed-off-by: Marcos Ronaldo <marcos.rpj2@gmail.com> Signed-off-by: Michel Felipe de Oliveira Ferreira <michel.ferreira@serpro.gov.br> Signed-off-by: Victor Costa <vfcosta@gmail.com>
Showing
23 changed files
with
445 additions
and
61 deletions
Show diff stats
Gemfile
... | ... | @@ -34,10 +34,11 @@ gem 'slim' |
34 | 34 | |
35 | 35 | # API dependencies |
36 | 36 | gem 'grape', '~> 0.12' |
37 | -gem 'grape-entity' | |
37 | +gem 'grape-entity', '0.4.8' | |
38 | 38 | gem 'grape_logging' |
39 | 39 | gem 'rack-cors' |
40 | 40 | gem 'rack-contrib' |
41 | +gem 'api-pagination', '~> 4.1.1' | |
41 | 42 | |
42 | 43 | # asset pipeline |
43 | 44 | gem 'uglifier', '>= 1.0.3' | ... | ... |
app/models/profile.rb
... | ... | @@ -388,6 +388,10 @@ class Profile < ActiveRecord::Base |
388 | 388 | !profiles.exists? |
389 | 389 | end |
390 | 390 | |
391 | + def self.visible_for_person(person) | |
392 | + self.all | |
393 | + end | |
394 | + | |
391 | 395 | validates_presence_of :identifier, :name |
392 | 396 | validates_length_of :nickname, :maximum => 16, :allow_nil => true |
393 | 397 | validate :valid_template | ... | ... |
lib/noosfero/api/api.rb
lib/noosfero/api/entities.rb
... | ... | @@ -79,6 +79,18 @@ module Noosfero |
79 | 79 | expose :parent_id |
80 | 80 | end |
81 | 81 | |
82 | + class Block < Entity | |
83 | + root 'blocks', 'block' | |
84 | + expose :id, :type, :settings, :position, :enabled | |
85 | + expose :mirror, :mirror_block_id, :title | |
86 | + end | |
87 | + | |
88 | + class Box < Entity | |
89 | + root 'boxes', 'box' | |
90 | + expose :id, :position | |
91 | + expose :blocks, :using => Block | |
92 | + end | |
93 | + | |
82 | 94 | class Profile < Entity |
83 | 95 | expose :identifier, :name, :id |
84 | 96 | expose :created_at, :format_with => :timestamp |
... | ... | @@ -99,6 +111,7 @@ module Noosfero |
99 | 111 | end |
100 | 112 | expose :image, :using => Image |
101 | 113 | expose :region, :using => Region |
114 | + expose :type | |
102 | 115 | end |
103 | 116 | |
104 | 117 | class UserBasic < Entity |
... | ... | @@ -109,6 +122,16 @@ module Noosfero |
109 | 122 | class Person < Profile |
110 | 123 | root 'people', 'person' |
111 | 124 | expose :user, :using => UserBasic, documentation: {type: 'User', desc: 'The user data of a person' } |
125 | + expose :vote_count | |
126 | + expose :comments_count do |person, options| | |
127 | + person.comments.count | |
128 | + end | |
129 | + expose :following_articles_count do |person, options| | |
130 | + person.following_articles.count | |
131 | + end | |
132 | + expose :articles_count do |person, options| | |
133 | + person.articles.count | |
134 | + end | |
112 | 135 | end |
113 | 136 | |
114 | 137 | class Enterprise < Profile |
... | ... | @@ -149,6 +172,8 @@ module Noosfero |
149 | 172 | expose :slug, :documentation => {:type => "String", :desc => "Trimmed and parsed name of a article"} |
150 | 173 | expose :path |
151 | 174 | expose :followers_count |
175 | + expose :votes_count | |
176 | + expose :comments_count | |
152 | 177 | end |
153 | 178 | |
154 | 179 | class Article < ArticleBase |
... | ... | @@ -189,7 +214,7 @@ module Noosfero |
189 | 214 | |
190 | 215 | class UserLogin < User |
191 | 216 | root 'users', 'user' |
192 | - expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'} | |
217 | + expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'}, if: lambda {|object, options| object.activated? } | |
193 | 218 | end |
194 | 219 | |
195 | 220 | class Task < Entity |
... | ... | @@ -207,7 +232,15 @@ module Noosfero |
207 | 232 | expose :name |
208 | 233 | end |
209 | 234 | |
210 | - | |
235 | + class Activity < Entity | |
236 | + root 'activities', 'activity' | |
237 | + expose :id, :params, :verb, :created_at, :updated_at, :comments_count, :visible | |
238 | + expose :user, :using => Profile | |
239 | + expose :target do |activity, opts| | |
240 | + type_map = {Profile => ::Profile, ArticleBase => ::Article}.find {|h| activity.target.kind_of?(h.last)} | |
241 | + type_map.first.represent(activity.target) unless type_map.nil? | |
242 | + end | |
243 | + end | |
211 | 244 | end |
212 | 245 | end |
213 | 246 | end | ... | ... |
lib/noosfero/api/entity.rb
... | ... | @@ -22,18 +22,4 @@ class Noosfero::API::Entity < Grape::Entity |
22 | 22 | end |
23 | 23 | end |
24 | 24 | |
25 | - def self.fields_condition(fields) | |
26 | - lambda do |object, options| | |
27 | - return true if options[:fields].blank? | |
28 | - fields.map { |field| options[:fields].include?(field.to_s)}.grep(true).present? | |
29 | - end | |
30 | - end | |
31 | - | |
32 | - def self.expose(*args, &block) | |
33 | - hash = args.last.is_a?(Hash) ? args.pop : {} | |
34 | - hash.merge!({:if => fields_condition(args)}) if hash[:if].blank? | |
35 | - args << hash | |
36 | - super | |
37 | - end | |
38 | - | |
39 | 25 | end | ... | ... |
lib/noosfero/api/helpers.rb
... | ... | @@ -5,7 +5,7 @@ require_relative '../../find_by_contents' |
5 | 5 | module API |
6 | 6 | module APIHelpers |
7 | 7 | PRIVATE_TOKEN_PARAM = :private_token |
8 | - DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id] | |
8 | + DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier] | |
9 | 9 | |
10 | 10 | include SanitizeParams |
11 | 11 | include Noosfero::Plugin::HotSpot |
... | ... | @@ -38,6 +38,20 @@ require_relative '../../find_by_contents' |
38 | 38 | @environment |
39 | 39 | end |
40 | 40 | |
41 | + def present_partial(model, options) | |
42 | + if(params[:fields].present?) | |
43 | + begin | |
44 | + fields = JSON.parse(params[:fields]) | |
45 | + if fields.present? | |
46 | + options.merge!(fields.symbolize_keys.slice(:only, :except)) | |
47 | + end | |
48 | + rescue | |
49 | + options[:only] = Array.wrap(params[:fields]) | |
50 | + end | |
51 | + end | |
52 | + present model, options | |
53 | + end | |
54 | + | |
41 | 55 | include FindByContents |
42 | 56 | |
43 | 57 | #################################################################### |
... | ... | @@ -87,7 +101,7 @@ require_relative '../../find_by_contents' |
87 | 101 | def post_article(asset, params) |
88 | 102 | return forbidden! unless current_person.can_post_content?(asset) |
89 | 103 | |
90 | - klass_type= params[:content_type].nil? ? 'TinyMceArticle' : params[:content_type] | |
104 | + klass_type= params[:content_type].nil? ? TinyMceArticle.name : params[:content_type] | |
91 | 105 | return forbidden! unless ARTICLE_TYPES.include?(klass_type) |
92 | 106 | |
93 | 107 | article = klass_type.constantize.new(params[:article]) |
... | ... | @@ -98,12 +112,12 @@ require_relative '../../find_by_contents' |
98 | 112 | if !article.save |
99 | 113 | render_api_errors!(article.errors.full_messages) |
100 | 114 | end |
101 | - present article, :with => Entities::Article, :fields => params[:fields] | |
115 | + present_partial article, :with => Entities::Article | |
102 | 116 | end |
103 | 117 | |
104 | 118 | def present_article(asset) |
105 | 119 | article = find_article(asset.articles, params[:id]) |
106 | - present article, :with => Entities::Article, :fields => params[:fields] | |
120 | + present_partial article, :with => Entities::Article | |
107 | 121 | end |
108 | 122 | |
109 | 123 | def present_articles_for_asset(asset, method = 'articles') |
... | ... | @@ -112,7 +126,7 @@ require_relative '../../find_by_contents' |
112 | 126 | end |
113 | 127 | |
114 | 128 | def present_articles(articles) |
115 | - present articles, :with => Entities::Article, :fields => params[:fields] | |
129 | + present_partial paginate(articles), :with => Entities::Article | |
116 | 130 | end |
117 | 131 | |
118 | 132 | def find_articles(asset, method = 'articles') |
... | ... | @@ -142,19 +156,19 @@ require_relative '../../find_by_contents' |
142 | 156 | if !task.save |
143 | 157 | render_api_errors!(task.errors.full_messages) |
144 | 158 | end |
145 | - present task, :with => Entities::Task, :fields => params[:fields] | |
159 | + present_partial task, :with => Entities::Task | |
146 | 160 | end |
147 | 161 | |
148 | 162 | def present_task(asset) |
149 | 163 | task = find_task(asset, params[:id]) |
150 | - present task, :with => Entities::Task, :fields => params[:fields] | |
164 | + present_partial task, :with => Entities::Task | |
151 | 165 | end |
152 | 166 | |
153 | 167 | def present_tasks(asset) |
154 | 168 | tasks = select_filtered_collection_of(asset, 'tasks', params) |
155 | 169 | tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)} |
156 | 170 | return forbidden! if tasks.empty? && !current_person.has_permission?(:perform_task, asset) |
157 | - present tasks, :with => Entities::Task, :fields => params[:fields] | |
171 | + present_partial tasks, :with => Entities::Task | |
158 | 172 | end |
159 | 173 | |
160 | 174 | def make_conditions_with_parameter(params = {}) |
... | ... | @@ -194,15 +208,6 @@ require_relative '../../find_by_contents' |
194 | 208 | return order |
195 | 209 | end |
196 | 210 | |
197 | - def make_page_number_with_parameters(params) | |
198 | - params[:page] || 1 | |
199 | - end | |
200 | - | |
201 | - def make_per_page_with_parameters(params) | |
202 | - params[:per_page] ||= limit | |
203 | - params[:per_page].to_i | |
204 | - end | |
205 | - | |
206 | 211 | def make_timestamp_with_parameters_and_method(params, method) |
207 | 212 | timestamp = nil |
208 | 213 | if params[:timestamp] |
... | ... | @@ -236,17 +241,17 @@ require_relative '../../find_by_contents' |
236 | 241 | def select_filtered_collection_of(object, method, params) |
237 | 242 | conditions = make_conditions_with_parameter(params) |
238 | 243 | order = make_order_with_parameters(object,method,params) |
239 | - page_number = make_page_number_with_parameters(params) | |
240 | - per_page = make_per_page_with_parameters(params) | |
241 | 244 | timestamp = make_timestamp_with_parameters_and_method(params, method) |
242 | 245 | |
243 | 246 | objects = object.send(method) |
244 | 247 | objects = by_reference(objects, params) |
245 | 248 | objects = by_categories(objects, params) |
246 | 249 | |
247 | - objects = objects.where(conditions).where(timestamp).page(page_number).per_page(per_page).reorder(order) | |
250 | + objects = objects.where(conditions).where(timestamp).reorder(order) | |
248 | 251 | |
249 | - objects | |
252 | + params[:page] ||= 1 | |
253 | + params[:per_page] ||= limit | |
254 | + paginate(objects) | |
250 | 255 | end |
251 | 256 | |
252 | 257 | def authenticate! | ... | ... |
lib/noosfero/api/session.rb
... | ... | @@ -24,6 +24,14 @@ module Noosfero |
24 | 24 | present user, :with => Entities::UserLogin, :current_person => current_person |
25 | 25 | end |
26 | 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 | + | |
27 | 35 | # Create user. |
28 | 36 | # |
29 | 37 | # Parameters: | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +module Noosfero | |
2 | + module API | |
3 | + module V1 | |
4 | + class Activities < Grape::API | |
5 | + before { authenticate! } | |
6 | + | |
7 | + resource :profiles do | |
8 | + | |
9 | + get ':id/activities' do | |
10 | + profile = environment.profiles | |
11 | + profile = profile.visible_for_person(current_person) if profile.respond_to?(:visible_for_person) | |
12 | + profile = profile.find_by_id(params[:id]) | |
13 | + activities = profile.activities.map(&:activity) | |
14 | + present activities, :with => Entities::Activity, :current_person => current_person | |
15 | + end | |
16 | + end | |
17 | + end | |
18 | + end | |
19 | + end | |
20 | +end | ... | ... |
lib/noosfero/api/v1/articles.rb
... | ... | @@ -5,8 +5,11 @@ module Noosfero |
5 | 5 | |
6 | 6 | ARTICLE_TYPES = Article.descendants.map{|a| a.to_s} |
7 | 7 | |
8 | + MAX_PER_PAGE = 50 | |
9 | + | |
8 | 10 | resource :articles do |
9 | 11 | |
12 | + paginate max_per_page: MAX_PER_PAGE | |
10 | 13 | # Collect articles |
11 | 14 | # |
12 | 15 | # Parameters: |
... | ... | @@ -49,7 +52,7 @@ module Noosfero |
49 | 52 | article = environment.articles.find(params[:id]) |
50 | 53 | return forbidden! unless article.allow_edit?(current_person) |
51 | 54 | article.update_attributes!(params[:article]) |
52 | - present article, :with => Entities::Article, :fields => params[:fields] | |
55 | + present_partial article, :with => Entities::Article | |
53 | 56 | end |
54 | 57 | |
55 | 58 | desc 'Report a abuse and/or violent content in a article by id' do |
... | ... | @@ -93,7 +96,7 @@ module Noosfero |
93 | 96 | end |
94 | 97 | #FIXME refactor this method |
95 | 98 | get 'voted_by_me' do |
96 | - present_articles(current_person.votes.collect(&:voteable)) | |
99 | + present_articles(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable)) | |
97 | 100 | end |
98 | 101 | |
99 | 102 | desc 'Perform a vote on a article by id' do |
... | ... | @@ -108,8 +111,12 @@ module Noosfero |
108 | 111 | # FIXME verify allowed values |
109 | 112 | render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) |
110 | 113 | article = find_article(environment.articles, params[:id]) |
111 | - vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | |
112 | - {:vote => vote.save} | |
114 | + begin | |
115 | + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) | |
116 | + {:vote => vote.save!} | |
117 | + rescue ActiveRecord::RecordInvalid => e | |
118 | + render_api_error!(e.message, 400) | |
119 | + end | |
113 | 120 | end |
114 | 121 | |
115 | 122 | desc "Returns the total followers for the article" do |
... | ... | @@ -123,6 +130,11 @@ module Noosfero |
123 | 130 | {:total_followers => total} |
124 | 131 | end |
125 | 132 | |
133 | + desc "Return the articles followed by me" | |
134 | + get 'followed_by_me' do | |
135 | + present_articles_for_asset(current_person, 'following_articles') | |
136 | + end | |
137 | + | |
126 | 138 | desc "Add a follower for the article" do |
127 | 139 | detail 'Add the current user identified by private token, like a follower of a article' |
128 | 140 | params Noosfero::API::Entities::UserLogin.documentation |
... | ... | @@ -150,6 +162,7 @@ module Noosfero |
150 | 162 | named 'ArticleChildren' |
151 | 163 | end |
152 | 164 | |
165 | + paginate per_page: MAX_PER_PAGE, max_per_page: MAX_PER_PAGE | |
153 | 166 | get ':id/children' do |
154 | 167 | article = find_article(environment.articles, params[:id]) |
155 | 168 | |
... | ... | @@ -177,7 +190,7 @@ module Noosfero |
177 | 190 | article = find_article(environment.articles, params[:id]) |
178 | 191 | child = find_article(article.children, params[:child_id]) |
179 | 192 | child.hit |
180 | - present child, :with => Entities::Article, :fields => params[:fields] | |
193 | + present_partial child, :with => Entities::Article | |
181 | 194 | end |
182 | 195 | |
183 | 196 | desc 'Suggest a article to another profile' do |
... | ... | @@ -200,7 +213,7 @@ module Noosfero |
200 | 213 | unless suggest_article.save |
201 | 214 | render_api_errors!(suggest_article.article_object.errors.full_messages) |
202 | 215 | end |
203 | - present suggest_article, :with => Entities::Task, :fields => params[:fields] | |
216 | + present_partial suggest_article, :with => Entities::Task | |
204 | 217 | end |
205 | 218 | |
206 | 219 | # Example Request: |
... | ... | @@ -231,12 +244,21 @@ module Noosfero |
231 | 244 | if !article.save |
232 | 245 | render_api_errors!(article.errors.full_messages) |
233 | 246 | end |
234 | - present article, :with => Entities::Article, :fields => params[:fields] | |
247 | + present_partial article, :with => Entities::Article | |
235 | 248 | end |
236 | 249 | |
237 | 250 | end |
238 | 251 | |
239 | - kinds = %w[community person enterprise] | |
252 | + resource :profiles do | |
253 | + get ':id/home_page' do | |
254 | + profiles = environment.profiles | |
255 | + profiles = profiles.visible_for_person(current_person) | |
256 | + profile = profiles.find_by_id(params[:id]) | |
257 | + present_partial profile.home_page, :with => Entities::Article | |
258 | + end | |
259 | + end | |
260 | + | |
261 | + kinds = %w[profile community person enterprise] | |
240 | 262 | kinds.each do |kind| |
241 | 263 | resource kind.pluralize.to_sym do |
242 | 264 | segment "/:#{kind}_id" do |
... | ... | @@ -258,7 +280,7 @@ module Noosfero |
258 | 280 | article = forbidden! |
259 | 281 | end |
260 | 282 | |
261 | - present article, :with => Entities::Article, :fields => params[:fields] | |
283 | + present_partial article, :with => Entities::Article | |
262 | 284 | else |
263 | 285 | |
264 | 286 | present_articles_for_asset(profile) | ... | ... |
... | ... | @@ -0,0 +1,28 @@ |
1 | +module Noosfero | |
2 | + module API | |
3 | + module V1 | |
4 | + | |
5 | + class Boxes < Grape::API | |
6 | + | |
7 | + kinds = %w[profile community person enterprise] | |
8 | + kinds.each do |kind| | |
9 | + | |
10 | + resource kind.pluralize.to_sym do | |
11 | + | |
12 | + segment "/:#{kind}_id" do | |
13 | + resource :boxes do | |
14 | + get do | |
15 | + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) | |
16 | + present profile.boxes, :with => Entities::Box | |
17 | + end | |
18 | + end | |
19 | + end | |
20 | + | |
21 | + end | |
22 | + | |
23 | + end | |
24 | + end | |
25 | + | |
26 | + end | |
27 | + end | |
28 | +end | ... | ... |
lib/noosfero/api/v1/comments.rb
... | ... | @@ -31,7 +31,12 @@ module Noosfero |
31 | 31 | post ":id/comments" do |
32 | 32 | article = find_article(environment.articles, params[:id]) |
33 | 33 | options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article) |
34 | - present Comment.create(options), :with => Entities::Comment, :current_person => current_person | |
34 | + begin | |
35 | + comment = Comment.create!(options) | |
36 | + rescue ActiveRecord::RecordInvalid => e | |
37 | + render_api_error!(e.message, 400) | |
38 | + end | |
39 | + present comment, :with => Entities::Comment, :current_person => current_person | |
35 | 40 | end |
36 | 41 | end |
37 | 42 | ... | ... |
lib/noosfero/api/v1/people.rb
... | ... | @@ -4,9 +4,12 @@ module Noosfero |
4 | 4 | class People < Grape::API |
5 | 5 | before { authenticate! } |
6 | 6 | |
7 | + MAX_PER_PAGE = 50 | |
8 | + | |
7 | 9 | desc 'API Root' |
8 | 10 | |
9 | 11 | resource :people do |
12 | + paginate max_per_page: MAX_PER_PAGE | |
10 | 13 | |
11 | 14 | # -- A note about privacy -- |
12 | 15 | # We wold find people by location, but we must test if the related |
... | ... | @@ -33,12 +36,12 @@ module Noosfero |
33 | 36 | get do |
34 | 37 | people = select_filtered_collection_of(environment, 'people', params) |
35 | 38 | people = people.visible_for_person(current_person) |
36 | - present people, :with => Entities::Person, :current_person => current_person | |
39 | + present_partial people, :with => Entities::Person, :current_person => current_person | |
37 | 40 | end |
38 | 41 | |
39 | 42 | desc "Return the logged user information" |
40 | 43 | get "/me" do |
41 | - present current_person, :with => Entities::Person, :current_person => current_person | |
44 | + present_partial current_person, :with => Entities::Person, :current_person => current_person | |
42 | 45 | end |
43 | 46 | |
44 | 47 | desc "Return the person information" |
... | ... | @@ -105,6 +108,19 @@ module Noosfero |
105 | 108 | present output |
106 | 109 | end |
107 | 110 | end |
111 | + | |
112 | + resource :profiles do | |
113 | + segment '/:profile_id' do | |
114 | + resource :members do | |
115 | + paginate max_per_page: MAX_PER_PAGE | |
116 | + get do | |
117 | + profile = environment.profiles.find_by_id(params[:profile_id]) | |
118 | + members = select_filtered_collection_of(profile, 'members', params) | |
119 | + present members, :with => Entities::Person, :current_person => current_person | |
120 | + end | |
121 | + end | |
122 | + end | |
123 | + end | |
108 | 124 | end |
109 | 125 | end |
110 | 126 | end | ... | ... |
... | ... | @@ -0,0 +1,26 @@ |
1 | +module Noosfero | |
2 | + module API | |
3 | + module V1 | |
4 | + class Profiles < Grape::API | |
5 | + before { authenticate! } | |
6 | + | |
7 | + resource :profiles do | |
8 | + | |
9 | + get do | |
10 | + profiles = select_filtered_collection_of(environment, 'profiles', params) | |
11 | + profiles = profiles.visible_for_person(current_person) | |
12 | + profiles = profiles.by_location(params) # Must be the last. May return Exception obj. | |
13 | + present profiles, :with => Entities::Profile, :current_person => current_person | |
14 | + end | |
15 | + | |
16 | + get ':id' do | |
17 | + profiles = environment.profiles | |
18 | + profiles = profiles.visible_for_person(current_person) | |
19 | + profile = profiles.find_by_id(params[:id]) | |
20 | + present profile, :with => Entities::Profile, :current_person => current_person | |
21 | + end | |
22 | + end | |
23 | + end | |
24 | + end | |
25 | + end | |
26 | +end | ... | ... |
lib/noosfero/api/v1/search.rb
... | ... | @@ -5,6 +5,7 @@ module Noosfero |
5 | 5 | |
6 | 6 | resource :search do |
7 | 7 | resource :article do |
8 | + paginate max_per_page: 200 | |
8 | 9 | get do |
9 | 10 | # Security checks |
10 | 11 | sanitize_params_hash(params) |
... | ... | @@ -15,24 +16,19 @@ module Noosfero |
15 | 16 | profile = environment.profiles.find(params[:profile_id]) if params[:profile_id] |
16 | 17 | scope = profile.nil? ? environment.articles.is_public : profile.articles.is_public |
17 | 18 | scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article') |
18 | - scope = scope.where(:parent_id => params[:parent_id]) if params[:parent_id].present? | |
19 | + scope = scope.where(make_conditions_with_parameter(params)) | |
19 | 20 | scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present? |
21 | + scope = scope.where('articles.children_count > 0') if params[:has_children].present? | |
20 | 22 | query = params[:query] || "" |
21 | 23 | order = "more_recent" |
22 | 24 | |
23 | 25 | options = {:filter => order, :template_id => params[:template_id]} |
24 | 26 | |
25 | - paginate_options = params.select{|k,v| [:page, :per_page].include?(k.to_sym)}.symbolize_keys | |
26 | - paginate_options.each_pair{|k,v| v=v.to_i} | |
27 | - paginate_options[:page]=1 if !paginate_options.keys.include?(:page) | |
28 | - | |
29 | - search_result = find_by_contents(asset, context, scope, query, paginate_options, options) | |
27 | + search_result = find_by_contents(asset, context, scope, query, {:page => 1}, options) | |
30 | 28 | |
31 | 29 | articles = search_result[:results] |
32 | 30 | |
33 | - result = present_articles(articles) | |
34 | - | |
35 | - result | |
31 | + present_articles(articles) | |
36 | 32 | end |
37 | 33 | end |
38 | 34 | end | ... | ... |
lib/noosfero/api/v1/tasks.rb
... | ... | @@ -20,13 +20,13 @@ module Noosfero |
20 | 20 | get do |
21 | 21 | tasks = select_filtered_collection_of(environment, 'tasks', params) |
22 | 22 | tasks = tasks.select {|t| current_person.has_permission?(t.permission, environment)} |
23 | - present tasks, :with => Entities::Task, :fields => params[:fields] | |
23 | + present_partial tasks, :with => Entities::Task | |
24 | 24 | end |
25 | 25 | |
26 | 26 | desc "Return the task id" |
27 | 27 | get ':id' do |
28 | 28 | task = find_task(environment, params[:id]) |
29 | - present task, :with => Entities::Task, :fields => params[:fields] | |
29 | + present_partial task, :with => Entities::Task | |
30 | 30 | end |
31 | 31 | end |
32 | 32 | ... | ... |
... | ... | @@ -0,0 +1,22 @@ |
1 | +require_relative 'test_helper' | |
2 | + | |
3 | +class ActivitiesTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + login_api | |
7 | + end | |
8 | + | |
9 | + should 'get activity from profile' do | |
10 | + person = fast_create(Person) | |
11 | + organization = fast_create(Organization) | |
12 | + assert_difference 'organization.activities_count' do | |
13 | + ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => organization | |
14 | + organization.reload | |
15 | + end | |
16 | + get "/api/v1/profiles/#{organization.id}/activities?#{params.to_query}" | |
17 | + json = JSON.parse(last_response.body) | |
18 | + assert 1, json["activities"].count | |
19 | + assert_equal organization.activities.map(&:activity).first.id, json["activities"].first["id"] | |
20 | + end | |
21 | + | |
22 | +end | ... | ... |
test/unit/api/articles_test.rb
... | ... | @@ -13,6 +13,16 @@ class ArticlesTest < ActiveSupport::TestCase |
13 | 13 | assert_includes json["articles"].map { |a| a["id"] }, article.id |
14 | 14 | end |
15 | 15 | |
16 | + should 'get profile homepage' do | |
17 | + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | |
18 | + person.home_page=article | |
19 | + person.save! | |
20 | + | |
21 | + get "/api/v1/profiles/#{person.id}/home_page?#{params.to_query}" | |
22 | + json = JSON.parse(last_response.body) | |
23 | + assert_equal article.id, json["article"]["id"] | |
24 | + end | |
25 | + | |
16 | 26 | should 'not list forbidden article when listing articles' do |
17 | 27 | person = fast_create(Person) |
18 | 28 | article = fast_create(Article, :profile_id => person.id, :name => "Some thing", :published => false) |
... | ... | @@ -74,6 +84,16 @@ class ArticlesTest < ActiveSupport::TestCase |
74 | 84 | assert_equal 1, json['total_followers'] |
75 | 85 | end |
76 | 86 | |
87 | + should 'list articles followed by me' do | |
88 | + article1 = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | |
89 | + fast_create(Article, :profile_id => user.person.id, :name => "Some other thing") | |
90 | + article1.person_followers << @person | |
91 | + get "/api/v1/articles/followed_by_me?#{params.to_query}" | |
92 | + json = JSON.parse(last_response.body) | |
93 | + assert_equal [article1.id], json['articles'].map { |a| a['id'] } | |
94 | + end | |
95 | + | |
96 | + | |
77 | 97 | should 'list article children' do |
78 | 98 | article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") |
79 | 99 | child1 = fast_create(Article, :parent_id => article.id, :profile_id => user.person.id, :name => "Some thing") |
... | ... | @@ -148,6 +168,33 @@ class ArticlesTest < ActiveSupport::TestCase |
148 | 168 | end |
149 | 169 | end |
150 | 170 | |
171 | + should 'not perform a vote twice in same article' do | |
172 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
173 | + @params[:value] = 1 | |
174 | + ## Perform a vote twice in API should compute only one vote | |
175 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
176 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
177 | + | |
178 | + total = article.votes_total | |
179 | + | |
180 | + assert_equal 1, total | |
181 | + end | |
182 | + | |
183 | + should 'not perform a vote in favor and against a proposal' do | |
184 | + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") | |
185 | + @params[:value] = 1 | |
186 | + ## Perform a vote in favor a proposal | |
187 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
188 | + json = JSON.parse(last_response.body) | |
189 | + assert_equal 201, last_response.status | |
190 | + ## Perform a vote against a proposal | |
191 | + @params[:value] = -1 | |
192 | + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" | |
193 | + json = JSON.parse(last_response.body) | |
194 | + ## The api should not allow to save this vote | |
195 | + assert_equal 400, last_response.status | |
196 | + end | |
197 | + | |
151 | 198 | should "update body of article created by me" do |
152 | 199 | new_value = "Another body" |
153 | 200 | params[:article] = {:body => new_value} |
... | ... | @@ -606,4 +653,15 @@ class ArticlesTest < ActiveSupport::TestCase |
606 | 653 | assert_equal json['articles'].count, 2 |
607 | 654 | end |
608 | 655 | |
656 | + ARTICLE_ATTRIBUTES = %w(votes_count comments_count) | |
657 | + | |
658 | + ARTICLE_ATTRIBUTES.map do |attribute| | |
659 | + | |
660 | + define_method "test_should_expose_#{attribute}_attribute_in_article_enpoints" do | |
661 | + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") | |
662 | + get "/api/v1/articles/#{article.id}?#{params.to_query}" | |
663 | + json = JSON.parse(last_response.body) | |
664 | + assert_not_nil json['article'][attribute] | |
665 | + end | |
666 | + end | |
609 | 667 | end | ... | ... |
... | ... | @@ -0,0 +1,20 @@ |
1 | +require_relative 'test_helper' | |
2 | + | |
3 | +class BoxesTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + login_api | |
7 | + end | |
8 | + | |
9 | + kinds= %w[Profile Community Person Enterprise] | |
10 | + kinds.each do |kind| | |
11 | + should "get_boxes_from_#{kind.downcase.pluralize}" do | |
12 | + profile_obj = fast_create(kind.constantize) | |
13 | + box = fast_create(Box, :owner_id => profile_obj.id, :owner_type => "Profile") | |
14 | + get "/api/v1/#{kind.downcase.pluralize}/#{profile_obj.id}/boxes?#{params.to_query}" | |
15 | + json = JSON.parse(last_response.body) | |
16 | + assert_equal box.id, json["boxes"].first["id"] | |
17 | + end | |
18 | + end | |
19 | + | |
20 | +end | ... | ... |
test/unit/api/helpers_test.rb
... | ... | @@ -25,6 +25,15 @@ class APIHelpersTest < ActiveSupport::TestCase |
25 | 25 | assert_equal user, current_user |
26 | 26 | end |
27 | 27 | |
28 | + should 'get the current user even with expired token' do | |
29 | + user = create_user('someuser') | |
30 | + user.generate_private_token! | |
31 | + user.private_token_generated_at = DateTime.now.prev_year | |
32 | + user.save | |
33 | + self.params = {:private_token => user.private_token} | |
34 | + assert_equal user, current_user | |
35 | + end | |
36 | + | |
28 | 37 | should 'get the person of current user' do |
29 | 38 | user = create_user('someuser') |
30 | 39 | user.generate_private_token! |
... | ... | @@ -192,6 +201,26 @@ class APIHelpersTest < ActiveSupport::TestCase |
192 | 201 | filter_disabled_plugins_endpoints |
193 | 202 | end |
194 | 203 | |
204 | + should 'not touch in options when no fields parameter is passed' do | |
205 | + model = mock | |
206 | + expects(:present).with(model, {}) | |
207 | + present_partial(model, {}) | |
208 | + end | |
209 | + | |
210 | + should 'fallback to array when fields parameter is not a json when calling present partial' do | |
211 | + model = mock | |
212 | + params[:fields] = 'name' | |
213 | + expects(:present).with(model, {:only => ['name']}) | |
214 | + present_partial(model, {}) | |
215 | + end | |
216 | + | |
217 | + should 'accept json as fields parameter when calling present partial' do | |
218 | + model = mock | |
219 | + params[:fields] = {only: [:name, {user: [:login]}]}.to_json | |
220 | + expects(:present).with(model, {:only => ['name', {'user' => ['login']}]}) | |
221 | + present_partial(model, {}) | |
222 | + end | |
223 | + | |
195 | 224 | protected |
196 | 225 | |
197 | 226 | def error!(info, status) | ... | ... |
test/unit/api/people_test.rb
... | ... | @@ -15,6 +15,19 @@ class PeopleTest < ActiveSupport::TestCase |
15 | 15 | assert_equivalent [person1.id, person2.id, person.id], json['people'].map {|c| c['id']} |
16 | 16 | end |
17 | 17 | |
18 | + should 'list all members of a community' do | |
19 | + person1 = fast_create(Person) | |
20 | + person2 = fast_create(Person) | |
21 | + community = fast_create(Community) | |
22 | + community.add_member(person1) | |
23 | + community.add_member(person2) | |
24 | + | |
25 | + get "/api/v1/profiles/#{community.id}/members?#{params.to_query}" | |
26 | + json = JSON.parse(last_response.body) | |
27 | + assert_equal 2, json["people"].count | |
28 | + assert_equivalent [person1.id,person2.id], json["people"].map{|p| p["id"]} | |
29 | + end | |
30 | + | |
18 | 31 | should 'not list invisible people' do |
19 | 32 | invisible_person = fast_create(Person, :visible => false) |
20 | 33 | |
... | ... | @@ -47,12 +60,34 @@ class PeopleTest < ActiveSupport::TestCase |
47 | 60 | assert_equal some_person.id, json['person']['id'] |
48 | 61 | end |
49 | 62 | |
63 | + should 'people endpoint filter by fields parameter' do | |
64 | + get "/api/v1/people?#{params.to_query}&fields=name" | |
65 | + json = JSON.parse(last_response.body) | |
66 | + expected = {'people' => [{'name' => person.name}]} | |
67 | + assert_equal expected, json | |
68 | + end | |
69 | + | |
70 | + should 'people endpoint filter by fields parameter with hierarchy' do | |
71 | + fields = {only: [:name, {user: [:login]}]}.to_json | |
72 | + get "/api/v1/people?#{params.to_query}&fields=#{fields}" | |
73 | + json = JSON.parse(last_response.body) | |
74 | + expected = {'people' => [{'name' => person.name, 'user' => {'login' => 'testapi'}}]} | |
75 | + assert_equal expected, json | |
76 | + end | |
77 | + | |
50 | 78 | should 'get logged person' do |
51 | 79 | get "/api/v1/people/me?#{params.to_query}" |
52 | 80 | json = JSON.parse(last_response.body) |
53 | 81 | assert_equal person.id, json['person']['id'] |
54 | 82 | end |
55 | 83 | |
84 | + should 'me endpoint filter by fields parameter' do | |
85 | + get "/api/v1/people/me?#{params.to_query}&fields=name" | |
86 | + json = JSON.parse(last_response.body) | |
87 | + expected = {'person' => {'name' => person.name}} | |
88 | + assert_equal expected, json | |
89 | + end | |
90 | + | |
56 | 91 | should 'not get invisible person' do |
57 | 92 | person = fast_create(Person, :visible => false) |
58 | 93 | |
... | ... | @@ -205,4 +240,19 @@ class PeopleTest < ActiveSupport::TestCase |
205 | 240 | assert_equal "www.blog.org", json['person']['additional_data']['Custom Blog'] |
206 | 241 | end |
207 | 242 | |
243 | + PERSON_ATTRIBUTES = %w(vote_count comments_count articles_count) | |
244 | + | |
245 | + PERSON_ATTRIBUTES.map do |attribute| | |
246 | + define_method "test_should_not_expose_#{attribute}_attribute_in_person_enpoint_if_field_parameter_does_not_contain_the_attribute" do | |
247 | + get "/api/v1/people/me?#{params.to_query}&fields=name" | |
248 | + json = JSON.parse(last_response.body) | |
249 | + assert_nil json['person'][attribute] | |
250 | + end | |
251 | + | |
252 | + define_method "test_should_expose_#{attribute}_attribute_in_person_enpoints_if_field_parameter_is_passed" do | |
253 | + get "/api/v1/people/me?#{params.to_query}&fields=#{attribute}" | |
254 | + json = JSON.parse(last_response.body) | |
255 | + assert_not_nil json['person'][attribute] | |
256 | + end | |
257 | + end | |
208 | 258 | end | ... | ... |
... | ... | @@ -0,0 +1,32 @@ |
1 | +require_relative 'test_helper' | |
2 | + | |
3 | +class ProfilesTest < ActiveSupport::TestCase | |
4 | + | |
5 | + def setup | |
6 | + Profile.delete_all | |
7 | + login_api | |
8 | + end | |
9 | + | |
10 | + should 'list all profiles' do | |
11 | + person1 = fast_create(Person) | |
12 | + person2 = fast_create(Person) | |
13 | + community = fast_create(Community) | |
14 | + get "/api/v1/profiles?#{params.to_query}" | |
15 | + json = JSON.parse(last_response.body) | |
16 | + assert_equivalent [person.id, person1.id, person2.id, community.id], json.map {|p| p['id']} | |
17 | + end | |
18 | + | |
19 | + should 'get person from profile id' do | |
20 | + some_person = fast_create(Person) | |
21 | + get "/api/v1/profiles/#{some_person.id}?#{params.to_query}" | |
22 | + json = JSON.parse(last_response.body) | |
23 | + assert_equal some_person.id, json['id'] | |
24 | + end | |
25 | + | |
26 | + should 'get community from profile id' do | |
27 | + community = fast_create(Community) | |
28 | + get "/api/v1/profiles/#{community.id}?#{params.to_query}" | |
29 | + json = JSON.parse(last_response.body) | |
30 | + assert_equal community.id, json['id'] | |
31 | + end | |
32 | +end | ... | ... |
test/unit/api/search_test.rb
... | ... | @@ -23,6 +23,16 @@ class SearchTest < ActiveSupport::TestCase |
23 | 23 | assert_not_empty json['articles'] |
24 | 24 | end |
25 | 25 | |
26 | + should 'list only articles that has children' do | |
27 | + article = fast_create(Article, :profile_id => person.id) | |
28 | + parent = create(Article, :profile_id => person.id, :name => 'parent article') | |
29 | + child = create(Article, :profile_id => person.id, :parent_id => parent.id, :name => 'child article') | |
30 | + | |
31 | + get "/api/v1/search/article?has_children=true" | |
32 | + json = JSON.parse(last_response.body) | |
33 | + assert_equal parent.id, json['articles'].first['id'] | |
34 | + end | |
35 | + | |
26 | 36 | should 'invalid search string articles' do |
27 | 37 | fast_create(Article, :profile_id => person.id, :name => 'some article') |
28 | 38 | get "/api/v1/search/article?query=test" | ... | ... |
test/unit/api/session_test.rb
... | ... | @@ -182,4 +182,14 @@ class SessionTest < ActiveSupport::TestCase |
182 | 182 | assert_equal 404, last_response.status |
183 | 183 | end |
184 | 184 | |
185 | + should 'not return private token when the registered user is inactive' do | |
186 | + params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" } | |
187 | + post "/api/v1/register?#{params.to_query}" | |
188 | + assert_equal 201, last_response.status | |
189 | + json = JSON.parse(last_response.body) | |
190 | + assert !User['newuserapi'].activated? | |
191 | + assert !json['user']['activated'] | |
192 | + assert !json['user']['private_token'].present? | |
193 | + end | |
194 | + | |
185 | 195 | end | ... | ... |