diff --git a/Gemfile b/Gemfile index db34d9e..5e28783 100644 --- a/Gemfile +++ b/Gemfile @@ -34,10 +34,11 @@ gem 'slim' # API dependencies gem 'grape', '~> 0.12' -gem 'grape-entity' +gem 'grape-entity', '0.4.8' gem 'grape_logging' gem 'rack-cors' gem 'rack-contrib' +gem 'api-pagination', '~> 4.1.1' # asset pipeline gem 'uglifier', '>= 1.0.3' diff --git a/app/models/profile.rb b/app/models/profile.rb index 70ad351..220f812 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -388,6 +388,10 @@ class Profile < ActiveRecord::Base !profiles.exists? end + def self.visible_for_person(person) + self.all + end + validates_presence_of :identifier, :name validates_length_of :nickname, :maximum => 16, :allow_nil => true validate :valid_template diff --git a/lib/noosfero/api/api.rb b/lib/noosfero/api/api.rb index 621be69..6af42de 100644 --- a/lib/noosfero/api/api.rb +++ b/lib/noosfero/api/api.rb @@ -52,6 +52,9 @@ module Noosfero mount V1::Environments mount V1::Search mount V1::Contacts + mount V1::Boxes + mount V1::Profiles + mount V1::Activities mount Session diff --git a/lib/noosfero/api/entities.rb b/lib/noosfero/api/entities.rb index 9b5d180..ded22ad 100644 --- a/lib/noosfero/api/entities.rb +++ b/lib/noosfero/api/entities.rb @@ -79,6 +79,18 @@ module Noosfero expose :parent_id end + class Block < Entity + root 'blocks', 'block' + expose :id, :type, :settings, :position, :enabled + expose :mirror, :mirror_block_id, :title + end + + class Box < Entity + root 'boxes', 'box' + expose :id, :position + expose :blocks, :using => Block + end + class Profile < Entity expose :identifier, :name, :id expose :created_at, :format_with => :timestamp @@ -99,6 +111,7 @@ module Noosfero end expose :image, :using => Image expose :region, :using => Region + expose :type end class UserBasic < Entity @@ -109,6 +122,16 @@ module Noosfero class Person < Profile root 'people', 'person' expose :user, :using => UserBasic, documentation: {type: 'User', desc: 'The user data of a person' } + expose :vote_count + expose :comments_count do |person, options| + person.comments.count + end + expose :following_articles_count do |person, options| + person.following_articles.count + end + expose :articles_count do |person, options| + person.articles.count + end end class Enterprise < Profile @@ -149,6 +172,8 @@ module Noosfero expose :slug, :documentation => {:type => "String", :desc => "Trimmed and parsed name of a article"} expose :path expose :followers_count + expose :votes_count + expose :comments_count end class Article < ArticleBase @@ -189,7 +214,7 @@ module Noosfero class UserLogin < User root 'users', 'user' - expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'} + expose :private_token, documentation: {type: 'String', desc: 'A valid authentication code for post/delete api actions'}, if: lambda {|object, options| object.activated? } end class Task < Entity @@ -207,7 +232,15 @@ module Noosfero expose :name end - + class Activity < Entity + root 'activities', 'activity' + expose :id, :params, :verb, :created_at, :updated_at, :comments_count, :visible + expose :user, :using => Profile + expose :target do |activity, opts| + type_map = {Profile => ::Profile, ArticleBase => ::Article}.find {|h| activity.target.kind_of?(h.last)} + type_map.first.represent(activity.target) unless type_map.nil? + end + end end end end diff --git a/lib/noosfero/api/entity.rb b/lib/noosfero/api/entity.rb index 767a379..51b55ab 100644 --- a/lib/noosfero/api/entity.rb +++ b/lib/noosfero/api/entity.rb @@ -22,18 +22,4 @@ class Noosfero::API::Entity < Grape::Entity end end - def self.fields_condition(fields) - lambda do |object, options| - return true if options[:fields].blank? - fields.map { |field| options[:fields].include?(field.to_s)}.grep(true).present? - end - end - - def self.expose(*args, &block) - hash = args.last.is_a?(Hash) ? args.pop : {} - hash.merge!({:if => fields_condition(args)}) if hash[:if].blank? - args << hash - super - end - end diff --git a/lib/noosfero/api/helpers.rb b/lib/noosfero/api/helpers.rb index dd2cb5d..e5c985a 100644 --- a/lib/noosfero/api/helpers.rb +++ b/lib/noosfero/api/helpers.rb @@ -5,7 +5,7 @@ require_relative '../../find_by_contents' module API module APIHelpers PRIVATE_TOKEN_PARAM = :private_token - DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id] + DEFAULT_ALLOWED_PARAMETERS = [:parent_id, :from, :until, :content_type, :author_id, :identifier] include SanitizeParams include Noosfero::Plugin::HotSpot @@ -38,6 +38,20 @@ require_relative '../../find_by_contents' @environment end + def present_partial(model, options) + if(params[:fields].present?) + begin + fields = JSON.parse(params[:fields]) + if fields.present? + options.merge!(fields.symbolize_keys.slice(:only, :except)) + end + rescue + options[:only] = Array.wrap(params[:fields]) + end + end + present model, options + end + include FindByContents #################################################################### @@ -87,7 +101,7 @@ require_relative '../../find_by_contents' def post_article(asset, params) return forbidden! unless current_person.can_post_content?(asset) - klass_type= params[:content_type].nil? ? 'TinyMceArticle' : params[:content_type] + klass_type= params[:content_type].nil? ? TinyMceArticle.name : params[:content_type] return forbidden! unless ARTICLE_TYPES.include?(klass_type) article = klass_type.constantize.new(params[:article]) @@ -98,12 +112,12 @@ require_relative '../../find_by_contents' if !article.save render_api_errors!(article.errors.full_messages) end - present article, :with => Entities::Article, :fields => params[:fields] + present_partial article, :with => Entities::Article end def present_article(asset) article = find_article(asset.articles, params[:id]) - present article, :with => Entities::Article, :fields => params[:fields] + present_partial article, :with => Entities::Article end def present_articles_for_asset(asset, method = 'articles') @@ -112,7 +126,7 @@ require_relative '../../find_by_contents' end def present_articles(articles) - present articles, :with => Entities::Article, :fields => params[:fields] + present_partial paginate(articles), :with => Entities::Article end def find_articles(asset, method = 'articles') @@ -142,19 +156,19 @@ require_relative '../../find_by_contents' if !task.save render_api_errors!(task.errors.full_messages) end - present task, :with => Entities::Task, :fields => params[:fields] + present_partial task, :with => Entities::Task end def present_task(asset) task = find_task(asset, params[:id]) - present task, :with => Entities::Task, :fields => params[:fields] + present_partial task, :with => Entities::Task end def present_tasks(asset) tasks = select_filtered_collection_of(asset, 'tasks', params) tasks = tasks.select {|t| current_person.has_permission?(t.permission, asset)} return forbidden! if tasks.empty? && !current_person.has_permission?(:perform_task, asset) - present tasks, :with => Entities::Task, :fields => params[:fields] + present_partial tasks, :with => Entities::Task end def make_conditions_with_parameter(params = {}) @@ -194,15 +208,6 @@ require_relative '../../find_by_contents' return order end - def make_page_number_with_parameters(params) - params[:page] || 1 - end - - def make_per_page_with_parameters(params) - params[:per_page] ||= limit - params[:per_page].to_i - end - def make_timestamp_with_parameters_and_method(params, method) timestamp = nil if params[:timestamp] @@ -236,17 +241,17 @@ require_relative '../../find_by_contents' def select_filtered_collection_of(object, method, params) conditions = make_conditions_with_parameter(params) order = make_order_with_parameters(object,method,params) - page_number = make_page_number_with_parameters(params) - per_page = make_per_page_with_parameters(params) timestamp = make_timestamp_with_parameters_and_method(params, method) objects = object.send(method) objects = by_reference(objects, params) objects = by_categories(objects, params) - objects = objects.where(conditions).where(timestamp).page(page_number).per_page(per_page).reorder(order) + objects = objects.where(conditions).where(timestamp).reorder(order) - objects + params[:page] ||= 1 + params[:per_page] ||= limit + paginate(objects) end def authenticate! diff --git a/lib/noosfero/api/session.rb b/lib/noosfero/api/session.rb index 879875f..21cab29 100644 --- a/lib/noosfero/api/session.rb +++ b/lib/noosfero/api/session.rb @@ -24,6 +24,14 @@ module Noosfero present user, :with => Entities::UserLogin, :current_person => current_person end + post "/login_from_cookie" do + return unauthorized! if cookies[:auth_token].blank? + user = User.where(remember_token: cookies[:auth_token]).first + return unauthorized! unless user && user.activated? + @current_user = user + present user, :with => Entities::UserLogin, :current_person => current_person + end + # Create user. # # Parameters: diff --git a/lib/noosfero/api/v1/activities.rb b/lib/noosfero/api/v1/activities.rb new file mode 100644 index 0000000..092318b --- /dev/null +++ b/lib/noosfero/api/v1/activities.rb @@ -0,0 +1,20 @@ +module Noosfero + module API + module V1 + class Activities < Grape::API + before { authenticate! } + + resource :profiles do + + get ':id/activities' do + profile = environment.profiles + profile = profile.visible_for_person(current_person) if profile.respond_to?(:visible_for_person) + profile = profile.find_by_id(params[:id]) + activities = profile.activities.map(&:activity) + present activities, :with => Entities::Activity, :current_person => current_person + end + end + end + end + end +end diff --git a/lib/noosfero/api/v1/articles.rb b/lib/noosfero/api/v1/articles.rb index f7711cd..3b243e3 100644 --- a/lib/noosfero/api/v1/articles.rb +++ b/lib/noosfero/api/v1/articles.rb @@ -5,8 +5,11 @@ module Noosfero ARTICLE_TYPES = Article.descendants.map{|a| a.to_s} + MAX_PER_PAGE = 50 + resource :articles do + paginate max_per_page: MAX_PER_PAGE # Collect articles # # Parameters: @@ -49,7 +52,7 @@ module Noosfero article = environment.articles.find(params[:id]) return forbidden! unless article.allow_edit?(current_person) article.update_attributes!(params[:article]) - present article, :with => Entities::Article, :fields => params[:fields] + present_partial article, :with => Entities::Article end desc 'Report a abuse and/or violent content in a article by id' do @@ -93,7 +96,7 @@ module Noosfero end #FIXME refactor this method get 'voted_by_me' do - present_articles(current_person.votes.collect(&:voteable)) + present_articles(current_person.votes.where(:voteable_type => 'Article').collect(&:voteable)) end desc 'Perform a vote on a article by id' do @@ -108,8 +111,12 @@ module Noosfero # FIXME verify allowed values render_api_error!('Vote value not allowed', 400) unless [-1, 1].include?(value) article = find_article(environment.articles, params[:id]) - vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) - {:vote => vote.save} + begin + vote = Vote.new(:voteable => article, :voter => current_person, :vote => value) + {:vote => vote.save!} + rescue ActiveRecord::RecordInvalid => e + render_api_error!(e.message, 400) + end end desc "Returns the total followers for the article" do @@ -123,6 +130,11 @@ module Noosfero {:total_followers => total} end + desc "Return the articles followed by me" + get 'followed_by_me' do + present_articles_for_asset(current_person, 'following_articles') + end + desc "Add a follower for the article" do detail 'Add the current user identified by private token, like a follower of a article' params Noosfero::API::Entities::UserLogin.documentation @@ -150,6 +162,7 @@ module Noosfero named 'ArticleChildren' end + paginate per_page: MAX_PER_PAGE, max_per_page: MAX_PER_PAGE get ':id/children' do article = find_article(environment.articles, params[:id]) @@ -177,7 +190,7 @@ module Noosfero article = find_article(environment.articles, params[:id]) child = find_article(article.children, params[:child_id]) child.hit - present child, :with => Entities::Article, :fields => params[:fields] + present_partial child, :with => Entities::Article end desc 'Suggest a article to another profile' do @@ -200,7 +213,7 @@ module Noosfero unless suggest_article.save render_api_errors!(suggest_article.article_object.errors.full_messages) end - present suggest_article, :with => Entities::Task, :fields => params[:fields] + present_partial suggest_article, :with => Entities::Task end # Example Request: @@ -231,12 +244,21 @@ module Noosfero if !article.save render_api_errors!(article.errors.full_messages) end - present article, :with => Entities::Article, :fields => params[:fields] + present_partial article, :with => Entities::Article end end - kinds = %w[community person enterprise] + resource :profiles do + get ':id/home_page' do + profiles = environment.profiles + profiles = profiles.visible_for_person(current_person) + profile = profiles.find_by_id(params[:id]) + present_partial profile.home_page, :with => Entities::Article + end + end + + kinds = %w[profile community person enterprise] kinds.each do |kind| resource kind.pluralize.to_sym do segment "/:#{kind}_id" do @@ -258,7 +280,7 @@ module Noosfero article = forbidden! end - present article, :with => Entities::Article, :fields => params[:fields] + present_partial article, :with => Entities::Article else present_articles_for_asset(profile) diff --git a/lib/noosfero/api/v1/boxes.rb b/lib/noosfero/api/v1/boxes.rb new file mode 100644 index 0000000..27a21b7 --- /dev/null +++ b/lib/noosfero/api/v1/boxes.rb @@ -0,0 +1,28 @@ +module Noosfero + module API + module V1 + + class Boxes < Grape::API + + kinds = %w[profile community person enterprise] + kinds.each do |kind| + + resource kind.pluralize.to_sym do + + segment "/:#{kind}_id" do + resource :boxes do + get do + profile = environment.send(kind.pluralize).find(params["#{kind}_id"]) + present profile.boxes, :with => Entities::Box + end + end + end + + end + + end + end + + end + end +end diff --git a/lib/noosfero/api/v1/comments.rb b/lib/noosfero/api/v1/comments.rb index e64c65a..3510c42 100644 --- a/lib/noosfero/api/v1/comments.rb +++ b/lib/noosfero/api/v1/comments.rb @@ -31,7 +31,12 @@ module Noosfero post ":id/comments" do article = find_article(environment.articles, params[:id]) options = params.select { |key,v| !['id','private_token'].include?(key) }.merge(:author => current_person, :source => article) - present Comment.create(options), :with => Entities::Comment, :current_person => current_person + begin + comment = Comment.create!(options) + rescue ActiveRecord::RecordInvalid => e + render_api_error!(e.message, 400) + end + present comment, :with => Entities::Comment, :current_person => current_person end end diff --git a/lib/noosfero/api/v1/people.rb b/lib/noosfero/api/v1/people.rb index f6d21a3..8179c66 100644 --- a/lib/noosfero/api/v1/people.rb +++ b/lib/noosfero/api/v1/people.rb @@ -4,9 +4,12 @@ module Noosfero class People < Grape::API before { authenticate! } + MAX_PER_PAGE = 50 + desc 'API Root' resource :people do + paginate max_per_page: MAX_PER_PAGE # -- A note about privacy -- # We wold find people by location, but we must test if the related @@ -33,12 +36,12 @@ module Noosfero get do people = select_filtered_collection_of(environment, 'people', params) people = people.visible_for_person(current_person) - present people, :with => Entities::Person, :current_person => current_person + present_partial people, :with => Entities::Person, :current_person => current_person end desc "Return the logged user information" get "/me" do - present current_person, :with => Entities::Person, :current_person => current_person + present_partial current_person, :with => Entities::Person, :current_person => current_person end desc "Return the person information" @@ -105,6 +108,19 @@ module Noosfero present output end end + + resource :profiles do + segment '/:profile_id' do + resource :members do + paginate max_per_page: MAX_PER_PAGE + get do + profile = environment.profiles.find_by_id(params[:profile_id]) + members = select_filtered_collection_of(profile, 'members', params) + present members, :with => Entities::Person, :current_person => current_person + end + end + end + end end end end diff --git a/lib/noosfero/api/v1/profiles.rb b/lib/noosfero/api/v1/profiles.rb new file mode 100644 index 0000000..302fd7a --- /dev/null +++ b/lib/noosfero/api/v1/profiles.rb @@ -0,0 +1,26 @@ +module Noosfero + module API + module V1 + class Profiles < Grape::API + before { authenticate! } + + resource :profiles do + + get do + profiles = select_filtered_collection_of(environment, 'profiles', params) + profiles = profiles.visible_for_person(current_person) + profiles = profiles.by_location(params) # Must be the last. May return Exception obj. + present profiles, :with => Entities::Profile, :current_person => current_person + end + + get ':id' do + profiles = environment.profiles + profiles = profiles.visible_for_person(current_person) + profile = profiles.find_by_id(params[:id]) + present profile, :with => Entities::Profile, :current_person => current_person + end + end + end + end + end +end diff --git a/lib/noosfero/api/v1/search.rb b/lib/noosfero/api/v1/search.rb index 58a70fc..4601093 100644 --- a/lib/noosfero/api/v1/search.rb +++ b/lib/noosfero/api/v1/search.rb @@ -5,6 +5,7 @@ module Noosfero resource :search do resource :article do + paginate max_per_page: 200 get do # Security checks sanitize_params_hash(params) @@ -15,24 +16,19 @@ module Noosfero profile = environment.profiles.find(params[:profile_id]) if params[:profile_id] scope = profile.nil? ? environment.articles.is_public : profile.articles.is_public scope = scope.where(:type => params[:type]) if params[:type] && !(params[:type] == 'Article') - scope = scope.where(:parent_id => params[:parent_id]) if params[:parent_id].present? + scope = scope.where(make_conditions_with_parameter(params)) scope = scope.joins(:categories).where(:categories => {:id => params[:category_ids]}) if params[:category_ids].present? + scope = scope.where('articles.children_count > 0') if params[:has_children].present? query = params[:query] || "" order = "more_recent" options = {:filter => order, :template_id => params[:template_id]} - paginate_options = params.select{|k,v| [:page, :per_page].include?(k.to_sym)}.symbolize_keys - paginate_options.each_pair{|k,v| v=v.to_i} - paginate_options[:page]=1 if !paginate_options.keys.include?(:page) - - search_result = find_by_contents(asset, context, scope, query, paginate_options, options) + search_result = find_by_contents(asset, context, scope, query, {:page => 1}, options) articles = search_result[:results] - result = present_articles(articles) - - result + present_articles(articles) end end end diff --git a/lib/noosfero/api/v1/tasks.rb b/lib/noosfero/api/v1/tasks.rb index feec86e..23d6f4a 100644 --- a/lib/noosfero/api/v1/tasks.rb +++ b/lib/noosfero/api/v1/tasks.rb @@ -20,13 +20,13 @@ module Noosfero get do tasks = select_filtered_collection_of(environment, 'tasks', params) tasks = tasks.select {|t| current_person.has_permission?(t.permission, environment)} - present tasks, :with => Entities::Task, :fields => params[:fields] + present_partial tasks, :with => Entities::Task end desc "Return the task id" get ':id' do task = find_task(environment, params[:id]) - present task, :with => Entities::Task, :fields => params[:fields] + present_partial task, :with => Entities::Task end end diff --git a/test/unit/api/activities_test.rb b/test/unit/api/activities_test.rb new file mode 100644 index 0000000..b06e14b --- /dev/null +++ b/test/unit/api/activities_test.rb @@ -0,0 +1,22 @@ +require_relative 'test_helper' + +class ActivitiesTest < ActiveSupport::TestCase + + def setup + login_api + end + + should 'get activity from profile' do + person = fast_create(Person) + organization = fast_create(Organization) + assert_difference 'organization.activities_count' do + ActionTracker::Record.create! :verb => :leave_scrap, :user => person, :target => organization + organization.reload + end + get "/api/v1/profiles/#{organization.id}/activities?#{params.to_query}" + json = JSON.parse(last_response.body) + assert 1, json["activities"].count + assert_equal organization.activities.map(&:activity).first.id, json["activities"].first["id"] + end + +end diff --git a/test/unit/api/articles_test.rb b/test/unit/api/articles_test.rb index a85c375..dbe6c3d 100644 --- a/test/unit/api/articles_test.rb +++ b/test/unit/api/articles_test.rb @@ -13,6 +13,16 @@ class ArticlesTest < ActiveSupport::TestCase assert_includes json["articles"].map { |a| a["id"] }, article.id end + should 'get profile homepage' do + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") + person.home_page=article + person.save! + + get "/api/v1/profiles/#{person.id}/home_page?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal article.id, json["article"]["id"] + end + should 'not list forbidden article when listing articles' do person = fast_create(Person) article = fast_create(Article, :profile_id => person.id, :name => "Some thing", :published => false) @@ -74,6 +84,16 @@ class ArticlesTest < ActiveSupport::TestCase assert_equal 1, json['total_followers'] end + should 'list articles followed by me' do + article1 = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") + fast_create(Article, :profile_id => user.person.id, :name => "Some other thing") + article1.person_followers << @person + get "/api/v1/articles/followed_by_me?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal [article1.id], json['articles'].map { |a| a['id'] } + end + + should 'list article children' do article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") child1 = fast_create(Article, :parent_id => article.id, :profile_id => user.person.id, :name => "Some thing") @@ -148,6 +168,33 @@ class ArticlesTest < ActiveSupport::TestCase end end + should 'not perform a vote twice in same article' do + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") + @params[:value] = 1 + ## Perform a vote twice in API should compute only one vote + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" + + total = article.votes_total + + assert_equal 1, total + end + + should 'not perform a vote in favor and against a proposal' do + article = fast_create(Article, :profile_id => @person.id, :name => "Some thing") + @params[:value] = 1 + ## Perform a vote in favor a proposal + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal 201, last_response.status + ## Perform a vote against a proposal + @params[:value] = -1 + post "/api/v1/articles/#{article.id}/vote?#{params.to_query}" + json = JSON.parse(last_response.body) + ## The api should not allow to save this vote + assert_equal 400, last_response.status + end + should "update body of article created by me" do new_value = "Another body" params[:article] = {:body => new_value} @@ -606,4 +653,15 @@ class ArticlesTest < ActiveSupport::TestCase assert_equal json['articles'].count, 2 end + ARTICLE_ATTRIBUTES = %w(votes_count comments_count) + + ARTICLE_ATTRIBUTES.map do |attribute| + + define_method "test_should_expose_#{attribute}_attribute_in_article_enpoints" do + article = fast_create(Article, :profile_id => user.person.id, :name => "Some thing") + get "/api/v1/articles/#{article.id}?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_not_nil json['article'][attribute] + end + end end diff --git a/test/unit/api/boxes_test.rb b/test/unit/api/boxes_test.rb new file mode 100644 index 0000000..a8e83bb --- /dev/null +++ b/test/unit/api/boxes_test.rb @@ -0,0 +1,20 @@ +require_relative 'test_helper' + +class BoxesTest < ActiveSupport::TestCase + + def setup + login_api + end + + kinds= %w[Profile Community Person Enterprise] + kinds.each do |kind| + should "get_boxes_from_#{kind.downcase.pluralize}" do + profile_obj = fast_create(kind.constantize) + box = fast_create(Box, :owner_id => profile_obj.id, :owner_type => "Profile") + get "/api/v1/#{kind.downcase.pluralize}/#{profile_obj.id}/boxes?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal box.id, json["boxes"].first["id"] + end + end + +end diff --git a/test/unit/api/helpers_test.rb b/test/unit/api/helpers_test.rb index f1f9c33..daa9398 100644 --- a/test/unit/api/helpers_test.rb +++ b/test/unit/api/helpers_test.rb @@ -25,6 +25,15 @@ class APIHelpersTest < ActiveSupport::TestCase assert_equal user, current_user end + should 'get the current user even with expired token' do + user = create_user('someuser') + user.generate_private_token! + user.private_token_generated_at = DateTime.now.prev_year + user.save + self.params = {:private_token => user.private_token} + assert_equal user, current_user + end + should 'get the person of current user' do user = create_user('someuser') user.generate_private_token! @@ -192,6 +201,26 @@ class APIHelpersTest < ActiveSupport::TestCase filter_disabled_plugins_endpoints end + should 'not touch in options when no fields parameter is passed' do + model = mock + expects(:present).with(model, {}) + present_partial(model, {}) + end + + should 'fallback to array when fields parameter is not a json when calling present partial' do + model = mock + params[:fields] = 'name' + expects(:present).with(model, {:only => ['name']}) + present_partial(model, {}) + end + + should 'accept json as fields parameter when calling present partial' do + model = mock + params[:fields] = {only: [:name, {user: [:login]}]}.to_json + expects(:present).with(model, {:only => ['name', {'user' => ['login']}]}) + present_partial(model, {}) + end + protected def error!(info, status) diff --git a/test/unit/api/people_test.rb b/test/unit/api/people_test.rb index d197310..73cc16b 100644 --- a/test/unit/api/people_test.rb +++ b/test/unit/api/people_test.rb @@ -15,6 +15,19 @@ class PeopleTest < ActiveSupport::TestCase assert_equivalent [person1.id, person2.id, person.id], json['people'].map {|c| c['id']} end + should 'list all members of a community' do + person1 = fast_create(Person) + person2 = fast_create(Person) + community = fast_create(Community) + community.add_member(person1) + community.add_member(person2) + + get "/api/v1/profiles/#{community.id}/members?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal 2, json["people"].count + assert_equivalent [person1.id,person2.id], json["people"].map{|p| p["id"]} + end + should 'not list invisible people' do invisible_person = fast_create(Person, :visible => false) @@ -47,12 +60,34 @@ class PeopleTest < ActiveSupport::TestCase assert_equal some_person.id, json['person']['id'] end + should 'people endpoint filter by fields parameter' do + get "/api/v1/people?#{params.to_query}&fields=name" + json = JSON.parse(last_response.body) + expected = {'people' => [{'name' => person.name}]} + assert_equal expected, json + end + + should 'people endpoint filter by fields parameter with hierarchy' do + fields = {only: [:name, {user: [:login]}]}.to_json + get "/api/v1/people?#{params.to_query}&fields=#{fields}" + json = JSON.parse(last_response.body) + expected = {'people' => [{'name' => person.name, 'user' => {'login' => 'testapi'}}]} + assert_equal expected, json + end + should 'get logged person' do get "/api/v1/people/me?#{params.to_query}" json = JSON.parse(last_response.body) assert_equal person.id, json['person']['id'] end + should 'me endpoint filter by fields parameter' do + get "/api/v1/people/me?#{params.to_query}&fields=name" + json = JSON.parse(last_response.body) + expected = {'person' => {'name' => person.name}} + assert_equal expected, json + end + should 'not get invisible person' do person = fast_create(Person, :visible => false) @@ -205,4 +240,19 @@ class PeopleTest < ActiveSupport::TestCase assert_equal "www.blog.org", json['person']['additional_data']['Custom Blog'] end + PERSON_ATTRIBUTES = %w(vote_count comments_count articles_count) + + PERSON_ATTRIBUTES.map do |attribute| + define_method "test_should_not_expose_#{attribute}_attribute_in_person_enpoint_if_field_parameter_does_not_contain_the_attribute" do + get "/api/v1/people/me?#{params.to_query}&fields=name" + json = JSON.parse(last_response.body) + assert_nil json['person'][attribute] + end + + define_method "test_should_expose_#{attribute}_attribute_in_person_enpoints_if_field_parameter_is_passed" do + get "/api/v1/people/me?#{params.to_query}&fields=#{attribute}" + json = JSON.parse(last_response.body) + assert_not_nil json['person'][attribute] + end + end end diff --git a/test/unit/api/profiles_test.rb b/test/unit/api/profiles_test.rb new file mode 100644 index 0000000..c58bc14 --- /dev/null +++ b/test/unit/api/profiles_test.rb @@ -0,0 +1,32 @@ +require_relative 'test_helper' + +class ProfilesTest < ActiveSupport::TestCase + + def setup + Profile.delete_all + login_api + end + + should 'list all profiles' do + person1 = fast_create(Person) + person2 = fast_create(Person) + community = fast_create(Community) + get "/api/v1/profiles?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equivalent [person.id, person1.id, person2.id, community.id], json.map {|p| p['id']} + end + + should 'get person from profile id' do + some_person = fast_create(Person) + get "/api/v1/profiles/#{some_person.id}?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal some_person.id, json['id'] + end + + should 'get community from profile id' do + community = fast_create(Community) + get "/api/v1/profiles/#{community.id}?#{params.to_query}" + json = JSON.parse(last_response.body) + assert_equal community.id, json['id'] + end +end diff --git a/test/unit/api/search_test.rb b/test/unit/api/search_test.rb index 69c7a18..1f90a47 100644 --- a/test/unit/api/search_test.rb +++ b/test/unit/api/search_test.rb @@ -23,6 +23,16 @@ class SearchTest < ActiveSupport::TestCase assert_not_empty json['articles'] end + should 'list only articles that has children' do + article = fast_create(Article, :profile_id => person.id) + parent = create(Article, :profile_id => person.id, :name => 'parent article') + child = create(Article, :profile_id => person.id, :parent_id => parent.id, :name => 'child article') + + get "/api/v1/search/article?has_children=true" + json = JSON.parse(last_response.body) + assert_equal parent.id, json['articles'].first['id'] + end + should 'invalid search string articles' do fast_create(Article, :profile_id => person.id, :name => 'some article') get "/api/v1/search/article?query=test" diff --git a/test/unit/api/session_test.rb b/test/unit/api/session_test.rb index 0ed75ae..a054649 100644 --- a/test/unit/api/session_test.rb +++ b/test/unit/api/session_test.rb @@ -182,4 +182,14 @@ class SessionTest < ActiveSupport::TestCase assert_equal 404, last_response.status end + should 'not return private token when the registered user is inactive' do + params = {:login => "newuserapi", :password => "newuserapi", :password_confirmation => "newuserapi", :email => "newuserapi@email.com" } + post "/api/v1/register?#{params.to_query}" + assert_equal 201, last_response.status + json = JSON.parse(last_response.body) + assert !User['newuserapi'].activated? + assert !json['user']['activated'] + assert !json['user']['private_token'].present? + end + end -- libgit2 0.21.2