From f07912ebddefc39f27af6e4591f46394029f708a Mon Sep 17 00:00:00 2001 From: Hank Grabowski Date: Sun, 30 Dec 2018 11:34:53 -0500 Subject: [PATCH] API Branch Final Cleanup Before PR --- app/controllers/api/v1/aspects_controller.rb | 13 +- app/controllers/api/v1/comments_controller.rb | 16 +- app/controllers/api/v1/contacts_controller.rb | 10 +- .../api/v1/conversations_controller.rb | 34 ++-- app/controllers/api/v1/likes_controller.rb | 16 +- app/controllers/api/v1/messages_controller.rb | 4 +- .../api/v1/notifications_controller.rb | 1 + app/controllers/api/v1/photos_controller.rb | 16 +- app/controllers/api/v1/posts_controller.rb | 28 +++- app/controllers/api/v1/reshares_controller.rb | 4 +- app/controllers/api/v1/search_controller.rb | 43 +++-- .../api/v1/tag_followings_controller.rb | 2 +- app/controllers/api/v1/users_controller.rb | 13 +- app/presenters/aspect_membership_presenter.rb | 3 +- app/presenters/contact_presenter.rb | 8 +- app/presenters/notification_presenter.rb | 9 +- app/presenters/person_presenter.rb | 1 + app/presenters/post_interaction_presenter.rb | 1 + app/services/aspects_membership_service.rb | 1 + app/services/photo_service.rb | 46 +++-- app/services/post_service.rb | 1 + app/services/tag_following_service.rb | 2 +- lib/api/paging/index_paginator.rb | 4 + lib/api/paging/rest_paged_response_builder.rb | 3 + lib/api/paging/rest_paginator_builder.rb | 3 + lib/api/paging/time_paginator.rb | 6 + .../authorizations_controller_spec.rb | 2 +- .../token_endpoint_controller_spec.rb | 3 +- .../openid_connect/user_applications_spec.rb | 2 +- spec/factories.rb | 4 +- .../api/aspects_controller_spec.rb | 70 ++++---- .../api/comments_controller_spec.rb | 108 +++++++++--- .../api/contacts_controller_spec.rb | 30 +++- .../api/conversations_controller_spec.rb | 158 ++++++++++++++---- spec/integration/api/likes_controller_spec.rb | 109 ++++++++---- .../api/messages_controller_spec.rb | 65 +++++-- .../api/notifications_controller_spec.rb | 31 ++-- .../integration/api/photos_controller_spec.rb | 43 ++--- .../api/post_interactions_controller_spec.rb | 33 ++-- spec/integration/api/posts_controller_spec.rb | 147 ++++++++++------ .../api/reshares_controller_spec.rb | 15 +- .../integration/api/search_controller_spec.rb | 11 +- .../api/streams_controller_spec.rb | 69 ++++---- .../api/tag_followings_controller_spec.rb | 17 +- spec/integration/api/users_controller_spec.rb | 67 +++++--- spec/lib/api/paging/index_paginator_spec.rb | 2 +- spec/lib/api/paging/time_paginator_spec.rb | 2 +- .../api/openid_connect/id_token_spec.rb | 2 +- .../presenters/notification_presenter_spec.rb | 8 + spec/services/photo_service_spec.rb | 28 ++-- 50 files changed, 859 insertions(+), 455 deletions(-) diff --git a/app/controllers/api/v1/aspects_controller.rb b/app/controllers/api/v1/aspects_controller.rb index dd09ea497..6ce5b9a47 100644 --- a/app/controllers/api/v1/aspects_controller.rb +++ b/app/controllers/api/v1/aspects_controller.rb @@ -14,14 +14,14 @@ module Api def index aspects_query = current_user.aspects aspects_page = index_pager(aspects_query).response - aspects_page[:data] = aspects_page[:data].map {|a| AspectPresenter.new(a).as_api_json(false) } + aspects_page[:data] = aspects_page[:data].map {|a| aspect_as_json(a, false) } render json: aspects_page end def show aspect = current_user.aspects.where(id: params[:id]).first if aspect - render json: AspectPresenter.new(aspect).as_api_json(true) + render json: aspect_as_json(aspect, true) else render json: I18n.t("api.endpoint_errors.aspects.not_found"), status: :not_found end @@ -31,7 +31,7 @@ module Api params.require(%i[name chat_enabled]) aspect = current_user.aspects.build(name: params[:name], chat_enabled: params[:chat_enabled]) if aspect&.save - render json: AspectPresenter.new(aspect).as_api_json(true) + render json: aspect_as_json(aspect, true) else render json: I18n.t("api.endpoint_errors.aspects.cant_create"), status: :unprocessable_entity end @@ -45,7 +45,7 @@ module Api if !aspect render json: I18n.t("api.endpoint_errors.aspects.cant_update"), status: :not_found elsif aspect.update!(aspect_params(true)) - render json: AspectPresenter.new(aspect).as_api_json(true) + render json: aspect_as_json(aspect, true) else render json: I18n.t("api.endpoint_errors.aspects.cant_update"), status: :unprocessable_entity end @@ -67,8 +67,13 @@ module Api def aspect_params(allow_order=false) parameters = params.permit(:name, :chat_enabled) parameters[:order_id] = params[:order] if params.has_key?(:order) && allow_order + parameters end + + def aspect_as_json(aspect, as_full) + AspectPresenter.new(aspect).as_api_json(as_full) + end end end end diff --git a/app/controllers/api/v1/comments_controller.rb b/app/controllers/api/v1/comments_controller.rb index d147a664d..e614a97ce 100644 --- a/app/controllers/api/v1/comments_controller.rb +++ b/app/controllers/api/v1/comments_controller.rb @@ -3,8 +3,8 @@ module Api module V1 class CommentsController < Api::V1::BaseController - before_action do - require_access_token %w[interactions public:read] + before_action except: %i[create destroy] do + require_access_token %w[public:read] end before_action only: %i[create destroy] do @@ -20,18 +20,19 @@ module Api end def create - @comment = comment_service.create(params[:post_id], params[:body]) - comment = comment_as_json(@comment) + find_post + comment = comment_service.create(params.require(:post_id), params.require(:body)) rescue ActiveRecord::RecordNotFound render json: I18n.t("api.endpoint_errors.posts.post_not_found"), status: :not_found else - render json: comment, status: :created + render json: comment_as_json(comment), status: :created end def index find_post - comments_query = comment_service.find_for_post(params[:post_id]) + comments_query = comment_service.find_for_post(params.require(:post_id)) params[:after] = Time.utc(1900).iso8601 if params.permit(:before, :after).empty? + comments_page = time_pager(comments_query).response comments_page[:data] = comments_page[:data].map {|x| comment_as_json(x) } render json: comments_page @@ -39,7 +40,7 @@ module Api def destroy find_post - if comment_and_post_validate(params[:post_id], params[:id]) + if comment_and_post_validate(params.require(:post_id), params[:id]) comment_service.destroy!(params[:id]) head :no_content end @@ -52,6 +53,7 @@ module Api post_guid = params.require(:post_id) comment_guid = params.require(:comment_id) return unless comment_and_post_validate(post_guid, comment_guid) + reason = params.require(:reason) comment = comment_service.find!(comment_guid) report = current_user.reports.new( diff --git a/app/controllers/api/v1/contacts_controller.rb b/app/controllers/api/v1/contacts_controller.rb index 2a1f1bda3..7d3bac3c9 100644 --- a/app/controllers/api/v1/contacts_controller.rb +++ b/app/controllers/api/v1/contacts_controller.rb @@ -18,7 +18,7 @@ module Api end def index - contacts_query = aspects_membership_service.contacts_in_aspect(params[:aspect_id]) + contacts_query = aspects_membership_service.contacts_in_aspect(params.require(:aspect_id)) contacts_page = index_pager(contacts_query).response contacts_page[:data] = contacts_page[:data].map do |c| ContactPresenter.new(c, current_user).as_api_json_without_contact @@ -27,9 +27,10 @@ module Api end def create - aspect_id = params[:aspect_id] - person = Person.find_by(guid: params[:person_guid]) + aspect_id = params.require(:aspect_id) + person = Person.find_by(guid: params.require(:person_guid)) aspect_membership = aspects_membership_service.create(aspect_id, person.id) if person.present? + if aspect_membership head :no_content else @@ -40,9 +41,10 @@ module Api end def destroy - aspect_id = params[:aspect_id] + aspect_id = params.require(:aspect_id) person = Person.find_by(guid: params[:id]) result = aspects_membership_service.destroy_by_ids(aspect_id, person.id) if person.present? + if result && result[:success] head :no_content else diff --git a/app/controllers/api/v1/conversations_controller.rb b/app/controllers/api/v1/conversations_controller.rb index e25863c9a..2a8f58bd7 100644 --- a/app/controllers/api/v1/conversations_controller.rb +++ b/app/controllers/api/v1/conversations_controller.rb @@ -14,10 +14,11 @@ module Api end def index - params.permit(:only_after, :only_unread) mapped_params = {} mapped_params[:only_after] = params[:only_after] if params.has_key?(:only_after) + mapped_params[:unread] = params[:only_unread] if params.has_key?(:only_unread) + conversations_query = conversation_service.all_for_user(mapped_params) conversations_page = pager(conversations_query, "conversations.created_at").response conversations_page[:data] = conversations_page[:data].map {|x| conversation_as_json(x) } @@ -31,34 +32,27 @@ module Api def create params.require(%i[subject body recipients]) - recipient_ids = params[:recipients].map {|p| Person.find_from_guid_or_username(id: p).id } - conversation = conversation_service.build( - params[:subject], - params[:body], - recipient_ids - ) - raise ActiveRecord::RecordInvalid unless conversation.participants.length == (recipient_ids.length + 1) - conversation.save! - Diaspora::Federation::Dispatcher.defer_dispatch( - current_user, - conversation - ) + recipients = recipient_ids + conversation = conversation_service.build(params[:subject], params[:body], recipients) + raise ActiveRecord::RecordInvalid unless conversation_valid?(conversation, recipients) + conversation.save! + Diaspora::Federation::Dispatcher.defer_dispatch(current_user, conversation) render json: conversation_as_json(conversation), status: :created rescue ActiveRecord::RecordInvalid, ActionController::ParameterMissing, ActiveRecord::RecordNotFound render json: I18n.t("api.endpoint_errors.conversations.cant_process"), status: :unprocessable_entity end def destroy - vis = conversation_service.get_visibility(params[:id]) - vis.destroy! + conversation = conversation_service.get_visibility(params[:id]) + conversation.destroy! head :no_content end private def conversation_service - ConversationService.new(current_user) + @conversation_service ||= ConversationService.new(current_user) end def conversation_as_json(conversation) @@ -68,6 +62,14 @@ module Api def pager(query, sort_field) Api::Paging::RestPaginatorBuilder.new(query, request).time_pager(params, sort_field) end + + def recipient_ids + params[:recipients].map {|p| Person.find_from_guid_or_username(id: p).id } + end + + def conversation_valid?(conversation, recipients) + conversation.participants.length == (recipients.length + 1) + end end end end diff --git a/app/controllers/api/v1/likes_controller.rb b/app/controllers/api/v1/likes_controller.rb index a9e48c4fe..d71bc9e0d 100644 --- a/app/controllers/api/v1/likes_controller.rb +++ b/app/controllers/api/v1/likes_controller.rb @@ -4,7 +4,11 @@ module Api module V1 class LikesController < Api::V1::BaseController before_action do - require_access_token %w[interactions public:read] + require_access_token %w[public:read] + end + + before_action only: %i[create destroy] do + require_access_token %w[interactions] end rescue_from ActiveRecord::RecordNotFound do @@ -16,8 +20,9 @@ module Api end def show - post = post_service.find!(params[:post_id]) + post = post_service.find!(params.require(:post_id)) raise ActiveRecord::RecordInvalid unless post.public? || private_read? + likes_query = like_service.find_for_post(params[:post_id]) likes_page = index_pager(likes_query).response likes_page[:data] = likes_page[:data].map {|x| like_json(x) } @@ -25,20 +30,23 @@ module Api end def create - post = post_service.find!(params[:post_id]) + post = post_service.find!(params.require(:post_id)) raise ActiveRecord::RecordInvalid unless post.public? || private_modify? + like_service.create(params[:post_id]) rescue ActiveRecord::RecordInvalid => e return render json: I18n.t("api.endpoint_errors.likes.like_exists"), status: :unprocessable_entity if e.message == "Validation failed: Target has already been taken" + raise else head :no_content end def destroy - post = post_service.find!(params[:post_id]) + post = post_service.find!(params.require(:post_id)) raise ActiveRecord::RecordInvalid unless post.public? || private_modify? + success = like_service.unlike_post(params[:post_id]) if success head :no_content diff --git a/app/controllers/api/v1/messages_controller.rb b/app/controllers/api/v1/messages_controller.rb index b7a085743..309c1c8cf 100644 --- a/app/controllers/api/v1/messages_controller.rb +++ b/app/controllers/api/v1/messages_controller.rb @@ -12,7 +12,7 @@ module Api end def create - conversation = conversation_service.find!(params[:conversation_id]) + conversation = conversation_service.find!(params.require(:conversation_id)) text = params.require(:body) message = current_user.build_message(conversation, text: text) message.save! @@ -23,7 +23,7 @@ module Api end def index - conversation = conversation_service.find!(params[:conversation_id]) + conversation = conversation_service.find!(params.require(:conversation_id)) conversation.set_read(current_user) messages_page = index_pager(conversation.messages).response messages_page[:data] = messages_page[:data].map {|x| message_json(x) } diff --git a/app/controllers/api/v1/notifications_controller.rb b/app/controllers/api/v1/notifications_controller.rb index cd710f9b0..3003cf05c 100644 --- a/app/controllers/api/v1/notifications_controller.rb +++ b/app/controllers/api/v1/notifications_controller.rb @@ -23,6 +23,7 @@ module Api def index after_date = Date.iso8601(params[:only_after]) if params.has_key?(:only_after) + notifications_query = service.index(params[:only_unread], after_date) notifications_page = time_pager(notifications_query).response notifications_page[:data] = notifications_page[:data].map do |note| diff --git a/app/controllers/api/v1/photos_controller.rb b/app/controllers/api/v1/photos_controller.rb index 8b8cdbc9f..b4790bc5c 100644 --- a/app/controllers/api/v1/photos_controller.rb +++ b/app/controllers/api/v1/photos_controller.rb @@ -22,25 +22,29 @@ module Api current_user.photos.where(public: true) end photos_page = time_pager(query).response - photos_page[:data] = photos_page[:data].map {|photo| PhotoPresenter.new(photo).as_api_json(true) } + photos_page[:data] = photos_page[:data].map {|photo| photo_json(photo) } render json: photos_page end def show photo = photo_service.visible_photo(params.require(:id)) raise ActiveRecord::RecordNotFound unless photo + raise ActiveRecord::RecordNotFound unless photo.public? || private_read? - render json: PhotoPresenter.new(photo).as_api_json(true) + + render json: photo_json(photo) end def create image = params.require(:image) public_photo = params.has_key?(:aspect_ids) raise RuntimeError unless public_photo || private_modify? + base_params = params.permit(:aspect_ids, :pending, :set_profile_photo) photo = photo_service.create_from_params_and_file(base_params, image) raise RuntimeError unless photo - render json: PhotoPresenter.new(photo).as_api_json(true) + + render json: photo_json(photo) rescue CarrierWave::IntegrityError, ActionController::ParameterMissing, RuntimeError render json: I18n.t("api.endpoint_errors.photos.failed_create"), status: :unprocessable_entity end @@ -48,7 +52,9 @@ module Api def destroy photo = current_user.photos.where(guid: params[:id]).first raise ActiveRecord::RecordNotFound unless photo + raise ActiveRecord::RecordNotFound unless photo.public? || private_modify? + if current_user.retract(photo) head :no_content else @@ -61,6 +67,10 @@ module Api def photo_service @photo_service ||= PhotoService.new(current_user) end + + def photo_json(photo) + PhotoPresenter.new(photo).as_api_json(true) + end end end end diff --git a/app/controllers/api/v1/posts_controller.rb b/app/controllers/api/v1/posts_controller.rb index 707d61dc7..32ac25807 100644 --- a/app/controllers/api/v1/posts_controller.rb +++ b/app/controllers/api/v1/posts_controller.rb @@ -20,14 +20,15 @@ module Api def show post = post_service.find!(params[:id]) raise ActiveRecord::RecordNotFound unless post.public? || private_read? + render json: post_as_json(post) end def create - raise StandardError unless params.require(:public) || private_modify? - status_service = StatusMessageCreationService.new(current_user) creation_params = normalized_create_params - @status_message = status_service.create(creation_params) + raise StandardError unless creation_params[:public] || private_modify? + + @status_message = creation_service.create(creation_params) render json: PostPresenter.new(@status_message, current_user).as_api_response rescue StandardError render json: I18n.t("api.endpoint_errors.posts.failed_create"), status: :unprocessable_entity @@ -40,6 +41,8 @@ module Api render json: I18n.t("api.endpoint_errors.posts.failed_delete"), status: :forbidden end + private + def normalized_create_params mapped_parameters = { status_message: { @@ -54,8 +57,6 @@ module Api mapped_parameters end - private - def add_location_params(mapped_parameters) return unless params.has_key?(:location) location = params.require(:location) @@ -65,20 +66,27 @@ module Api def add_photo_ids(mapped_parameters) return unless params.has_key?(:photos) + photo_guids = params[:photos] return if photo_guids.empty? - photo_ids = photo_guids.map {|guid| Photo.find_by!(guid: guid) } - raise InvalidArgument if photo_ids.length != photo_guids.length - mapped_parameters[:photos] = photo_ids + + photos = photo_guids.map {|guid| Photo.find_by!(guid: guid) } + .select {|p| p.author_id == current_user.person.id && p.pending } + raise InvalidArgument if photos.length != photo_guids.length + + mapped_parameters[:photos] = photos end def add_poll_params(mapped_parameters) return unless params.has_key?(:poll) + poll_data = params.require(:poll) question = poll_data[:question] answers = poll_data[:poll_answers] raise InvalidArgument if question.blank? + raise InvalidArgument if answers.empty? + answers.each do |a| raise InvalidArgument if a.blank? end @@ -94,6 +102,10 @@ module Api @post_service ||= PostService.new(current_user) end + def creation_service + @creation_service ||= StatusMessageCreationService.new(current_user) + end + def post_as_json(post) PostPresenter.new(post).as_api_response end diff --git a/app/controllers/api/v1/reshares_controller.rb b/app/controllers/api/v1/reshares_controller.rb index 546d58716..da3c3d881 100644 --- a/app/controllers/api/v1/reshares_controller.rb +++ b/app/controllers/api/v1/reshares_controller.rb @@ -20,7 +20,7 @@ module Api end def show - reshares_query = reshare_service.find_for_post(params[:post_id]) + reshares_query = reshare_service.find_for_post(params.require(:post_id)) reshares_page = index_pager(reshares_query).response reshares_page[:data] = reshares_page[:data].map do |r| { @@ -32,7 +32,7 @@ module Api end def create - reshare = reshare_service.create(params[:post_id]) + reshare = reshare_service.create(params.require(:post_id)) rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid, RuntimeError render plain: I18n.t("reshares.create.error"), status: :unprocessable_entity else diff --git a/app/controllers/api/v1/search_controller.rb b/app/controllers/api/v1/search_controller.rb index 0d7b34c0f..e9663ff75 100644 --- a/app/controllers/api/v1/search_controller.rb +++ b/app/controllers/api/v1/search_controller.rb @@ -12,30 +12,12 @@ module Api end def user_index - parameters = params.permit(:tag, :name_or_handle) - raise RuntimeError if parameters.keys.length != 1 - people_query = if params.has_key?(:tag) - Person.profile_tagged_with(params[:tag]) - else - connected_only = !private_read? - Person.search( - params[:name_or_handle], - current_user, - only_contacts: connected_only, - mutual: connected_only - ) - end user_page = index_pager(people_query).response user_page[:data] = user_page[:data].map {|p| PersonPresenter.new(p).as_api_json } render json: user_page end def post_index - posts_query = if private_read? - Stream::Tag.new(current_user, params.require(:tag)).posts - else - Stream::Tag.new(nil, params.require(:tag)).posts - end posts_page = time_pager(posts_query, "posts.created_at", "created_at").response posts_page[:data] = posts_page[:data].map {|post| PostPresenter.new(post).as_api_response } render json: posts_page @@ -46,6 +28,31 @@ module Api def time_pager(query, query_time_field, data_time_field) Api::Paging::RestPaginatorBuilder.new(query, request).time_pager(params, query_time_field, data_time_field) end + + def people_query + parameters = params.permit(:tag, :name_or_handle) + raise RuntimeError if parameters.keys.length != 1 + + if params.has_key?(:tag) + Person.profile_tagged_with(params[:tag]) + else + connected_only = !private_read? + Person.search( + params[:name_or_handle], + current_user, + only_contacts: connected_only, + mutual: connected_only + ) + end + end + + def posts_query + if private_read? + Stream::Tag.new(current_user, params.require(:tag)).posts + else + Stream::Tag.new(nil, params.require(:tag)).posts + end + end end end end diff --git a/app/controllers/api/v1/tag_followings_controller.rb b/app/controllers/api/v1/tag_followings_controller.rb index f2181972d..d1a714586 100755 --- a/app/controllers/api/v1/tag_followings_controller.rb +++ b/app/controllers/api/v1/tag_followings_controller.rb @@ -30,7 +30,7 @@ module Api private def tag_followings_service - TagFollowingService.new(current_user) + @tag_followings_service ||= TagFollowingService.new(current_user) end end end diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index 9d44e7518..f407cfd86 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -37,7 +37,6 @@ module Api end def update - raise RuntimeError if params.has_key?(:id) params_to_update = profile_update_params if params_to_update && current_user.update_profile(params_to_update) render json: PersonPresenter.new(current_user.person, current_user).profile_hash_as_api_json @@ -49,12 +48,12 @@ module Api end def contacts - if params[:user_id] != current_user.guid + if params.require(:user_id) != current_user.guid render json: I18n.t("api.endpoint_errors.users.not_found"), status: :not_found return end - contacts_query = AspectsMembershipService.new(current_user).all_contacts + contacts_query = aspects_service.all_contacts contacts_page = index_pager(contacts_query).response contacts_page[:data] = contacts_page[:data].map {|c| PersonPresenter.new(c.person).as_api_json } render json: contacts_page @@ -83,7 +82,13 @@ module Api private + def aspects_service + @aspects_service ||= AspectsMembershipService.new(current_user) + end + def profile_update_params + raise RuntimeError if params.has_key?(:id) + updates = params.permit(:bio, :birthday, :gender, :location, :first_name, :last_name, :searchable, :show_profile_info, :nsfw, :tags).to_h || {} if updates.has_key?(:show_profile_info) @@ -96,7 +101,9 @@ module Api def process_tags_updates(updates) return unless params.has_key?(:tags) + raise RuntimeError if params[:tags].length > Profile::MAX_TAGS + tags = params[:tags].map {|tag| "#" + normalize_tag_name(tag) }.join(" ") updates[:tag_string] = tags updates.delete(:tags) diff --git a/app/presenters/aspect_membership_presenter.rb b/app/presenters/aspect_membership_presenter.rb index 6d19a9099..210919c33 100644 --- a/app/presenters/aspect_membership_presenter.rb +++ b/app/presenters/aspect_membership_presenter.rb @@ -6,7 +6,8 @@ class AspectMembershipPresenter < BasePresenter end def base_hash - { id: @membership.id, + { + id: @membership.id, aspect: AspectPresenter.new(@membership.aspect).as_json, } end diff --git a/app/presenters/contact_presenter.rb b/app/presenters/contact_presenter.rb index d3cf1e545..d826ee191 100644 --- a/app/presenters/contact_presenter.rb +++ b/app/presenters/contact_presenter.rb @@ -2,15 +2,16 @@ class ContactPresenter < BasePresenter def base_hash - { id: id, + { + id: id, person_id: person_id } end def full_hash - base_hash.merge({ + base_hash.merge( aspect_memberships: aspect_memberships.map{ |membership| AspectMembershipPresenter.new(membership).base_hash } - }) + ) end def full_hash_with_person @@ -20,6 +21,7 @@ class ContactPresenter < BasePresenter def as_api_json_without_contact PersonPresenter.new(person, current_user).as_api_json end + private def person_without_contact diff --git a/app/presenters/notification_presenter.rb b/app/presenters/notification_presenter.rb index 492b9a647..34407e2c7 100644 --- a/app/presenters/notification_presenter.rb +++ b/app/presenters/notification_presenter.rb @@ -3,7 +3,7 @@ class NotificationPresenter < BasePresenter def as_api_json(include_target=true) data = base_hash - data = data.merge(target: target_json) if include_target && target + data = data.merge(target: target_json) if include_target && linked_object data end @@ -20,10 +20,9 @@ class NotificationPresenter < BasePresenter end def target_json - { - guid: target.guid, - author: PersonPresenter.new(target.author).as_api_json - } + json = {guid: linked_object.guid} + json[:author] = PersonPresenter.new(linked_object.author).as_api_json if linked_object.author + json end def creators_json diff --git a/app/presenters/person_presenter.rb b/app/presenters/person_presenter.rb index 4227b272b..70f260362 100644 --- a/app/presenters/person_presenter.rb +++ b/app/presenters/person_presenter.rb @@ -101,6 +101,7 @@ class PersonPresenter < BasePresenter def aspects_detailed return [] unless current_user_person_contact + aspects_for_person = current_user.aspects_with_person(@presentable) aspects_for_person.map {|a| AspectPresenter.new(a).as_api_json(false) } end diff --git a/app/presenters/post_interaction_presenter.rb b/app/presenters/post_interaction_presenter.rb index e1a80afed..00475703f 100644 --- a/app/presenters/post_interaction_presenter.rb +++ b/app/presenters/post_interaction_presenter.rb @@ -30,6 +30,7 @@ class PostInteractionPresenter def participations return @post.participations.none unless @current_user + @post.participations.where(author: @current_user.person) end diff --git a/app/services/aspects_membership_service.rb b/app/services/aspects_membership_service.rb index 38f026052..bbd7be9a4 100644 --- a/app/services/aspects_membership_service.rb +++ b/app/services/aspects_membership_service.rb @@ -53,6 +53,7 @@ class AspectsMembershipService def destroy(aspect, contact) raise ActiveRecord::RecordNotFound unless aspect.present? && contact.present? + raise Diaspora::NotMine unless @user.mine?(aspect) && @user.mine?(contact) membership = contact.aspect_memberships.where(aspect_id: aspect.id).first diff --git a/app/services/photo_service.rb b/app/services/photo_service.rb index 3fa51a143..c2d331bb3 100644 --- a/app/services/photo_service.rb +++ b/app/services/photo_service.rb @@ -12,28 +12,16 @@ class PhotoService def create_from_params_and_file(base_params, uploaded_file) photo_params = build_params(base_params) - raise RuntimeError if @deny_raw_files && !confirm_uploaded_file_settings(uploaded_file) + photo_params[:user_file] = uploaded_file + photo = @user.build_post(:photo, photo_params) + raise RuntimeError unless photo.save - @photo = @user.build_post(:photo, photo_params) - raise RuntimeError unless @photo.save - unless @photo.pending - unless @photo.public? - aspects = @user.aspects_from_ids(photo_params[:aspect_ids]) - @user.add_to_streams(@photo, aspects) - end - @user.dispatch_post(@photo, to: photo_params[:aspect_ids]) - end + send_messages(photo, photo_params) + update_profile_photo(photo) if photo_params[:set_profile_photo] - if photo_params[:set_profile_photo] - profile_params = {image_url: @photo.url(:thumb_large), - image_url_medium: @photo.url(:thumb_medium), - image_url_small: @photo.url(:thumb_small)} - @user.update_profile(profile_params) - end - - @photo + photo end private @@ -53,7 +41,29 @@ class PhotoService return false end return false if uploaded_file.original_filename.empty? + return false if uploaded_file.content_type.empty? + true end + + def send_messages(photo, photo_params) + send_to_streams(photo, photo_params) unless photo.pending && photo.public? + + @user.dispatch_post(photo, to: photo_params[:aspect_ids]) unless photo.pending + end + + def update_profile_photo(photo) + profile_params = { + image_url: photo.url(:thumb_large), + image_url_medium: photo.url(:thumb_medium), + image_url_small: photo.url(:thumb_small) + } + @user.update_profile(profile_params) + end + + def send_to_streams(photo, photo_params) + aspects = @user.aspects_from_ids(photo_params[:aspect_ids]) + @user.add_to_streams(photo, aspects) + end end diff --git a/app/services/post_service.rb b/app/services/post_service.rb index 34b4f5ab4..aff0c1024 100644 --- a/app/services/post_service.rb +++ b/app/services/post_service.rb @@ -42,6 +42,7 @@ class PostService find_public!(post_id) end raise Diaspora::NotMine unless post.author == user.person + user.retract(post) end diff --git a/app/services/tag_following_service.rb b/app/services/tag_following_service.rb index eb38dd92a..2bc34fe60 100644 --- a/app/services/tag_following_service.rb +++ b/app/services/tag_following_service.rb @@ -11,8 +11,8 @@ class TagFollowingService tag = ActsAsTaggableOn::Tag.find_or_create_by(name: name_normalized) tag_following = @user.tag_followings.new(tag_id: tag.id) - raise "Can't process tag entity" unless tag_following.save + tag end diff --git a/lib/api/paging/index_paginator.rb b/lib/api/paging/index_paginator.rb index a9518fb8d..8dc5108e0 100644 --- a/lib/api/paging/index_paginator.rb +++ b/lib/api/paging/index_paginator.rb @@ -19,14 +19,18 @@ module Api def next_page(for_url=true) page_data return nil if for_url && @current_page == @max_page + return "page=#{@current_page + 1}" if for_url + IndexPaginator.new(@query_base, @current_page + 1, @limit) end def previous_page(for_url=true) page_data return nil if for_url && @current_page == 1 + return "page=#{@current_page - 1}" if for_url + IndexPaginator.new(@query_base, @current_page - 1, @limit) end diff --git a/lib/api/paging/rest_paged_response_builder.rb b/lib/api/paging/rest_paged_response_builder.rb index 95ab7c059..727a0180b 100644 --- a/lib/api/paging/rest_paged_response_builder.rb +++ b/lib/api/paging/rest_paged_response_builder.rb @@ -28,8 +28,10 @@ module Api previous_page = @pager.previous_page links = {} links[:previous] = link_builder(previous_page) if previous_page + next_page = @pager.next_page links[:next] = link_builder(next_page) if next_page + links end @@ -40,6 +42,7 @@ module Api def filtered_original_parameters @pager.filter_parameters(@query_parameters) return "" if @query_parameters.empty? + @query_parameters.map {|k, v| "#{k}=#{v}" }.join("&") + "&" end end diff --git a/lib/api/paging/rest_paginator_builder.rb b/lib/api/paging/rest_paginator_builder.rb index 24cda8311..08a6096d8 100644 --- a/lib/api/paging/rest_paginator_builder.rb +++ b/lib/api/paging/rest_paginator_builder.rb @@ -57,7 +57,9 @@ module Api def time_settings(params) time_params = params.permit("before", "after") time_params["before"] = (Time.current + 1.year).iso8601 if time_params.empty? && @allow_default_page + raise "Missing time parameters for query building" if time_params.empty? + if time_params["before"] is_descending = true current_time = Time.iso8601(time_params["before"]) @@ -71,6 +73,7 @@ module Api def limit_settings(params) requested_limit = params["per_page"] return @default_limit unless requested_limit + requested_limit = [1, requested_limit].max [requested_limit, MAX_LIMIT].min end diff --git a/lib/api/paging/time_paginator.rb b/lib/api/paging/time_paginator.rb index 9ec696473..e9293aa32 100644 --- a/lib/api/paging/time_paginator.rb +++ b/lib/api/paging/time_paginator.rb @@ -25,17 +25,21 @@ module Api def page_data return @data if @data + @data = @query_base.where([@time_query_string, @current_time.iso8601(3)]).limit(@limit).order(@sort_string) time_data = @data.map {|d| d[@data_time_field] }.sort @min_time = time_data.first @max_time = time_data.last + 0.001.seconds if time_data.last + @data end def next_page(for_url=true) page_data return nil unless next_time + return next_page_as_query_parameter if for_url + TimePaginator.new( query_base: @query_base, query_time_field: @query_time_field, @@ -49,7 +53,9 @@ module Api def previous_page(for_url=true) page_data return nil unless previous_time + return previous_page_as_query_parameter if for_url + TimePaginator.new( query_base: @query_base, query_time_field: @query_time_field, diff --git a/spec/controllers/api/openid_connect/authorizations_controller_spec.rb b/spec/controllers/api/openid_connect/authorizations_controller_spec.rb index a62966306..06637b028 100644 --- a/spec/controllers/api/openid_connect/authorizations_controller_spec.rb +++ b/spec/controllers/api/openid_connect/authorizations_controller_spec.rb @@ -444,7 +444,7 @@ describe Api::OpenidConnect::AuthorizationsController, type: :request do describe "#destroy" do context "with existent authorization" do it "removes the authorization" do - auth_with_read = FactoryGirl.create(:auth_with_profile_only, o_auth_application: client) + auth_with_read = FactoryGirl.create(:auth_with_default_scopes, o_auth_application: client) delete api_openid_connect_authorization_path(auth_with_read.id) expect(Api::OpenidConnect::Authorization.find_by(id: auth_with_read.id)).to be_nil end diff --git a/spec/controllers/api/openid_connect/token_endpoint_controller_spec.rb b/spec/controllers/api/openid_connect/token_endpoint_controller_spec.rb index 5d9d28803..9eec6d41c 100644 --- a/spec/controllers/api/openid_connect/token_endpoint_controller_spec.rb +++ b/spec/controllers/api/openid_connect/token_endpoint_controller_spec.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true describe Api::OpenidConnect::TokenEndpointController, type: :controller, suppress_csrf_verification: :none do - let(:auth) { FactoryGirl.create(:auth_with_profile_only) } + let(:auth) { FactoryGirl.create(:auth_with_default_scopes) } describe "#create" do it "returns 200 on success" do @@ -24,7 +24,6 @@ describe Api::OpenidConnect::TokenEndpointController, type: :controller, suppres client_secret: auth.o_auth_application.client_secret } expect(response.code).to eq("200") - puts response.body end end end diff --git a/spec/controllers/api/openid_connect/user_applications_spec.rb b/spec/controllers/api/openid_connect/user_applications_spec.rb index d9edab4b7..1c40b2c16 100644 --- a/spec/controllers/api/openid_connect/user_applications_spec.rb +++ b/spec/controllers/api/openid_connect/user_applications_spec.rb @@ -4,7 +4,7 @@ describe Api::OpenidConnect::UserApplicationsController, type: :controller do before do @app = FactoryGirl.create(:o_auth_application_with_xss) @user = FactoryGirl.create :user - FactoryGirl.create :auth_with_profile_only, user: @user, o_auth_application: @app + FactoryGirl.create :auth_with_default_scopes, user: @user, o_auth_application: @app sign_in @user, scope: :user end diff --git a/spec/factories.rb b/spec/factories.rb index 2a0920905..fe03527a8 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -403,10 +403,10 @@ FactoryGirl.define do redirect_uris %w(http://localhost:3000/) end - factory :auth_with_profile_only, class: Api::OpenidConnect::Authorization do + factory :auth_with_default_scopes, class: Api::OpenidConnect::Authorization do o_auth_application user - scopes %w[openid profile] + scopes %w[openid public:read] after(:build) {|m| m.redirect_uri = m.o_auth_application.redirect_uris[0] } diff --git a/spec/integration/api/aspects_controller_spec.rb b/spec/integration/api/aspects_controller_spec.rb index d6427caac..094e591f1 100644 --- a/spec/integration/api/aspects_controller_spec.rb +++ b/spec/integration/api/aspects_controller_spec.rb @@ -5,25 +5,26 @@ require "spec_helper" describe Api::V1::AspectsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid contacts:read contacts:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid contacts:read] ) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @aspect1 = auth.user.aspects.create(name: "first aspect") @@ -46,20 +47,22 @@ describe Api::V1::AspectsController do end end - it "fails if token doesn't have contacts:read" do - get( - api_v1_aspects_path, - params: {access_token: access_token_profile_only} - ) - expect(response.status).to eq(403) - end + context "without impromper credentials" do + it "fails if token doesn't have contacts:read" do + get( + api_v1_aspects_path, + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end - it "fails if invalid token" do - get( - api_v1_aspects_path, - params: {access_token: "999_999_999"} - ) - expect(response.status).to eq(401) + it "fails if invalid token" do + get( + api_v1_aspects_path, + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end end end @@ -90,21 +93,19 @@ describe Api::V1::AspectsController do end end - context "without contacts:read in token" do - it "fails to return with error" do + context "without impromper credentials" do + it "fails without contacts:read in token" do get( api_v1_aspect_path(@aspect2.id), - params: {access_token: access_token_profile_only} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(403) end - end - context "when not logged in" do - it "fails to return with error" do + it "fails when not logged in" do get( api_v1_aspect_path(@aspect2.id), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -165,7 +166,7 @@ describe Api::V1::AspectsController do it "fails when not logged in" do post( api_v1_aspects_path, - params: {name: "new_name", chat_enabled: true, access_token: "999_999_999"} + params: {name: "new_name", chat_enabled: true, access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -186,17 +187,17 @@ describe Api::V1::AspectsController do it "updates full aspect" do new_name = "NewAspectName" new_chat = @aspect2.chat_enabled - order = @aspect2.order_id + 1 + new_order = @aspect2.order_id + 1 patch( api_v1_aspect_path(@aspect2.id), - params: {name: new_name, chat_enabled: new_chat, order: order, access_token: access_token} + params: {name: new_name, chat_enabled: new_chat, order: new_order, access_token: access_token} ) expect(response.status).to eq(200) aspect = JSON.parse(response.body) expect(aspect["name"]).to eq(new_name) expect(aspect["chat_enabled"]).to eq(new_chat) - expect(aspect["order"]).to eq(order) + expect(aspect["order"]).to eq(new_order) expect(aspect["id"]).to eq(@aspect2.id) end @@ -227,15 +228,15 @@ describe Api::V1::AspectsController do end it "updates order only" do - order = @aspect2.order_id + 1 + new_order = @aspect2.order_id + 1 patch( api_v1_aspect_path(@aspect2.id), - params: {order: order, access_token: access_token} + params: {order: new_order, access_token: access_token} ) expect(response.status).to eq(200) aspect = JSON.parse(response.body) - expect(aspect["order"]).to eq(order) + expect(aspect["order"]).to eq(new_order) expect(aspect["id"]).to eq(@aspect2.id) end @@ -279,7 +280,7 @@ describe Api::V1::AspectsController do it "fails when not logged in" do patch( api_v1_aspect_path(@aspect2.id), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -302,6 +303,7 @@ describe Api::V1::AspectsController do params: {access_token: access_token} ) expect(response.status).to eq(204) + expect(auth.user.aspects.find_by(id: @aspect2.id)).to be_nil end end @@ -320,7 +322,7 @@ describe Api::V1::AspectsController do it "fails when not logged in" do delete( api_v1_aspect_path(@aspect2.id), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end diff --git a/spec/integration/api/comments_controller_spec.rb b/spec/integration/api/comments_controller_spec.rb index 67a8ec5d5..cdae54439 100644 --- a/spec/integration/api/comments_controller_spec.rb +++ b/spec/integration/api/comments_controller_spec.rb @@ -5,20 +5,26 @@ require "spec_helper" describe Api::V1::CommentsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, - scopes: %w[openid public:read public:modify private:read private:modify interactions] + :auth_with_default_scopes, + scopes: %w[openid public:read public:modify private:read interactions] ) } let(:auth_public_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify interactions] ) } + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) + } + let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_public_only) { auth_public_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @status = alice.post( @@ -58,7 +64,6 @@ describe Api::V1::CommentsController do api_v1_post_comments_path(post_id: @status.guid), params: {body: comment_text, access_token: access_token} ) - expect(response.status).to eq(201) comment = response_body(response) confirm_comment_format(comment, auth.user, comment_text) @@ -86,6 +91,33 @@ describe Api::V1::CommentsController do expect(response.status).to eq(422) end end + + context "with improper credentials" do + it "fails on private post without private:read" do + post( + api_v1_post_comments_path(post_id: @private_post.guid), + params: {body: "comment text", access_token: access_token_public_only} + ) + expect(response.status).to eq(404) + expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) + end + + it "fails without interactions scope" do + post( + api_v1_post_comments_path(post_id: @status.guid), + params: {body: "comment text", access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails without valid token" do + post( + api_v1_post_comments_path(post_id: @status.guid), + params: {body: "comment text", access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end describe "#read" do @@ -100,7 +132,7 @@ describe Api::V1::CommentsController do it "retrieves related comments" do get( api_v1_post_comments_path(post_id: @status.guid), - params: {access_token: access_token} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(200) comments = response_body_data(response) @@ -121,8 +153,8 @@ describe Api::V1::CommentsController do end end - context "can't see comment on limited post without private:read token" do - it "fails" do + context "improper credentials" do + it "fails on private post without private:read" do get( api_v1_post_comments_path(post_id: @private_post.guid), params: {access_token: access_token_public_only} @@ -130,6 +162,14 @@ describe Api::V1::CommentsController do expect(response.status).to eq(404) expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) end + + it "fails without valid token" do + get( + api_v1_post_comments_path(post_id: @status.guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end end end @@ -209,8 +249,10 @@ describe Api::V1::CommentsController do expect(response.status).to eq(403) expect(response.body).to eq(I18n.t("api.endpoint_errors.comments.no_delete")) end + end - it "fails at deleting your comment on post without private:modify token" do + context "improper credentials" do + it "fails at deleting your comment on post without private:read token" do delete( api_v1_post_comment_path( post_id: @private_post.guid, @@ -220,6 +262,14 @@ describe Api::V1::CommentsController do ) expect(response.status).to eq(404) end + + it "fails without valid token" do + get( + api_v1_post_comments_path(post_id: @status.guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end end end @@ -299,23 +349,6 @@ describe Api::V1::CommentsController do end end - context "lack of private permissions on private post" do - it "fails at reporting comment" do - post( - api_v1_post_comment_report_path( - post_id: @private_post.guid, - comment_id: @comment_on_private_post.guid - ), - params: { - reason: "bad comment", - access_token: access_token_public_only - } - ) - expect(response.status).to eq(404) - expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) - end - end - context "mismatched post-to-comment ID" do it "fails at reporting comment" do post( @@ -361,6 +394,31 @@ describe Api::V1::CommentsController do expect(response.body).to eq(I18n.t("api.endpoint_errors.comments.duplicate_report")) end end + + context "improper credentials" do + it "fails on private post without private:read" do + post( + api_v1_post_comment_report_path( + post_id: @private_post.guid, + comment_id: @comment_on_private_post.guid + ), + params: { + reason: "bad comment", + access_token: access_token_public_only + } + ) + expect(response.status).to eq(404) + expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) + end + + it "fails without valid token" do + get( + api_v1_post_comments_path(post_id: @status.guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end def comment_service(user=auth.user) diff --git a/spec/integration/api/contacts_controller_spec.rb b/spec/integration/api/contacts_controller_spec.rb index a85198e21..fc48b7294 100644 --- a/spec/integration/api/contacts_controller_spec.rb +++ b/spec/integration/api/contacts_controller_spec.rb @@ -5,25 +5,26 @@ require "spec_helper" describe Api::V1::ContactsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid contacts:read contacts:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid contacts:read] ) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @aspect1 = auth.user.aspects.create(name: "generic") @@ -79,10 +80,19 @@ describe Api::V1::ContactsController do end context "improper credentials" do + it "fails without contacts:read" do + aspect = auth_minimum_scopes.user.aspects.create(name: "new aspect") + get( + api_v1_aspect_contacts_path(aspect.id), + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + it "fails when not logged in" do get( api_v1_aspect_contacts_path(@aspect2.id), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -146,7 +156,7 @@ describe Api::V1::ContactsController do it "fails when not logged in" do post( api_v1_aspect_contacts_path(@aspect2.id), - params: {person_guid: alice.guid, access_token: "999_999_999"} + params: {person_guid: alice.guid, access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -221,14 +231,16 @@ describe Api::V1::ContactsController do it "fails when not logged in" do delete( api_v1_aspect_contact_path(@aspect2.id, alice.guid), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end it "fails when only read only token" do + aspect = auth_read_only.user.aspects.create(name: "new") + aspects_membership_service(auth_read_only.user).create(aspect.id, alice.person.id) delete( - api_v1_aspect_contact_path(@aspect2.id, alice.guid), + api_v1_aspect_contact_path(aspect.id, alice.guid), params: {access_token: access_token_read_only} ) expect(response.status).to eq(403) diff --git a/spec/integration/api/conversations_controller_spec.rb b/spec/integration/api/conversations_controller_spec.rb index 1e80308c1..ea2c71dc9 100644 --- a/spec/integration/api/conversations_controller_spec.rb +++ b/spec/integration/api/conversations_controller_spec.rb @@ -5,7 +5,7 @@ require "spec_helper" describe Api::V1::ConversationsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid conversations] ) } @@ -14,21 +14,25 @@ describe Api::V1::ConversationsController do FactoryGirl.create(:auth_with_all_scopes) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_participant) { auth_participant.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } - + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do auth.user.aspects.create(name: "first") - auth.user.share_with alice.person, auth.user.aspects[0] - alice.share_with auth.user.person, alice.aspects[0] + auth.user.share_with(alice.person, auth.user.aspects[0]) + alice.share_with(auth.user.person, alice.aspects[0]) auth.user.disconnected_by(eve) + auth_minimum_scopes.user.aspects.create(name: "first") + auth_minimum_scopes.user.share_with(alice.person, auth_minimum_scopes.user.aspects[0]) + alice.share_with(auth_minimum_scopes.user.person, alice.aspects[0]) + @conversation_request = { subject: "new conversation", body: "first message", @@ -41,8 +45,8 @@ describe Api::V1::ConversationsController do context "with valid data" do it "creates the conversation" do post api_v1_conversations_path, params: @conversation_request - expect(response.status).to eq 201 - conversation = JSON.parse(response.body) + expect(response.status).to eq(201) + conversation = response_body(response) confirm_conversation_format(conversation, @conversation_request, [auth.user, alice]) end end @@ -50,7 +54,7 @@ describe Api::V1::ConversationsController do context "without valid data" do it "fails with empty body" do post api_v1_conversations_path, params: {access_token: access_token} - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.cant_process")) end @@ -61,7 +65,7 @@ describe Api::V1::ConversationsController do access_token: access_token } post api_v1_conversations_path, params: incomplete_conversation - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.cant_process")) end @@ -72,7 +76,7 @@ describe Api::V1::ConversationsController do access_token: access_token } post api_v1_conversations_path, params: incomplete_conversation - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.cant_process")) end @@ -83,7 +87,7 @@ describe Api::V1::ConversationsController do access_token: access_token } post api_v1_conversations_path, params: incomplete_conversation - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.cant_process")) end @@ -95,7 +99,7 @@ describe Api::V1::ConversationsController do access_token: access_token } post api_v1_conversations_path, params: incomplete_conversation - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.cant_process")) end @@ -107,21 +111,45 @@ describe Api::V1::ConversationsController do access_token: access_token } post api_v1_conversations_path, params: incomplete_conversation - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.cant_process")) end end + + context "with improper credentials" do + it "fails without conversation scope" do + conversation_request = { + subject: "new conversation", + body: "first message", + recipients: [alice.guid], + access_token: access_token_minimum_scopes + } + post api_v1_conversations_path, params: conversation_request + expect(response.status).to eq(403) + end + + it "fails without valid token" do + conversation_request = { + subject: "new conversation", + body: "first message", + recipients: [alice.guid], + access_token: invalid_token + } + post api_v1_conversations_path, params: conversation_request + expect(response.status).to eq(401) + end + end end describe "#index" do before do post api_v1_conversations_path, params: @conversation_request - @read_conversation_guid = JSON.parse(response.body)["guid"] + @read_conversation_guid = response_body(response)["guid"] @read_conversation = conversation_service.find!(@read_conversation_guid) post api_v1_conversations_path, params: @conversation_request sleep(1) post api_v1_conversations_path, params: @conversation_request - @conversation_guid = JSON.parse(response.body)["guid"] + @conversation_guid = response_body(response)["guid"] @conversation = conversation_service.find!(@conversation_guid) @conversation.conversation_visibilities[0].unread = 1 @conversation.conversation_visibilities[0].save! @@ -132,9 +160,9 @@ describe Api::V1::ConversationsController do it "returns all the user conversations" do get api_v1_conversations_path, params: {access_token: access_token} - expect(response.status).to eq 200 + expect(response.status).to eq(200) returned_conversations = response_body_data(response) - expect(returned_conversations.length).to eq 3 + expect(returned_conversations.length).to eq(3) actual_conversation = returned_conversations.select {|c| c["guid"] == @read_conversation_guid }[0] confirm_conversation_format(actual_conversation, @read_conversation, [auth.user, alice]) end @@ -144,8 +172,8 @@ describe Api::V1::ConversationsController do api_v1_conversations_path, params: {only_unread: true, access_token: access_token} ) - expect(response.status).to eq 200 - expect(response_body_data(response).length).to eq 2 + expect(response.status).to eq(200) + expect(response_body_data(response).length).to eq(2) end it "returns all the user conversations after a given date" do @@ -153,27 +181,44 @@ describe Api::V1::ConversationsController do api_v1_conversations_path, params: {only_after: @date, access_token: access_token} ) - expect(response.status).to eq 200 - expect(response_body_data(response).length).to eq 1 + expect(response.status).to eq(200) + expect(response_body_data(response).length).to eq(1) + end + + context "with improper credentials" do + it "fails without conversation scope" do + get( + api_v1_conversations_path, + params: {only_after: @date, access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails without valid token" do + get( + api_v1_conversations_path, + params: {only_after: @date, access_token: invalid_token} + ) + expect(response.status).to eq(401) + end end end describe "#show" do - context "valid conversation ID" do - before do - post api_v1_conversations_path, params: @conversation_request - @conversation_guid = JSON.parse(response.body)["guid"] - @conversation = conversation_service.find!(@conversation_guid) - end + before do + post api_v1_conversations_path, params: @conversation_request + @conversation_guid = response_body(response)["guid"] + @conversation = conversation_service.find!(@conversation_guid) + end + context "valid conversation ID" do it "returns the corresponding conversation" do - conversation_guid = JSON.parse(response.body)["guid"] get( - api_v1_conversation_path(conversation_guid), + api_v1_conversation_path(@conversation_guid), params: {access_token: access_token} ) - expect(response.status).to eq 200 - conversation = JSON.parse(response.body) + expect(response.status).to eq(200) + conversation = response_body(response) confirm_conversation_format(conversation, @conversation, [auth.user, alice]) end end @@ -181,13 +226,32 @@ describe Api::V1::ConversationsController do context "non existing conversation ID" do it "returns a not found error (404)" do get( - api_v1_conversation_path(42), + api_v1_conversation_path(-1), params: {access_token: access_token} ) - expect(response.status).to eq 404 + expect(response.status).to eq(404) expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.not_found")) end end + + context "with improper credentials" do + it "fails without conversation scope" do + get( + api_v1_conversation_path(@conversation_guid), + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails without valid token" do + conversation_guid = response_body(response)["guid"] + get( + api_v1_conversation_path(conversation_guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end describe "#destroy " do @@ -205,7 +269,7 @@ describe Api::V1::ConversationsController do access_token: access_token } post api_v1_conversations_path, params: @conversation_request - @conversation_guid = JSON.parse(response.body)["guid"] + @conversation_guid = response_body(response)["guid"] end context "destroy" do @@ -264,6 +328,24 @@ describe Api::V1::ConversationsController do expect(response.body).to eq(I18n.t("api.endpoint_errors.conversations.not_found")) end end + + context "with improper credentials" do + it "fails without conversation scope" do + delete( + api_v1_conversation_path(@conversation_guid), + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails without valid token" do + delete( + api_v1_conversation_path(@conversation_guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end def conversation_service @@ -272,6 +354,10 @@ describe Api::V1::ConversationsController do private + def response_body(response) + JSON.parse(response.body) + end + def response_body_data(response) JSON.parse(response.body)["data"] end diff --git a/spec/integration/api/likes_controller_spec.rb b/spec/integration/api/likes_controller_spec.rb index 439bb82f4..9a17934ed 100644 --- a/spec/integration/api/likes_controller_spec.rb +++ b/spec/integration/api/likes_controller_spec.rb @@ -5,25 +5,26 @@ require "spec_helper" describe Api::V1::LikesController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify private:read private:modify interactions] ) } let(:auth_public_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify interactions] ) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_public_only) { auth_public_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @status = auth.user.post( @@ -48,7 +49,7 @@ describe Api::V1::LikesController do it "succeeds in getting empty likes" do get( api_v1_post_likes_path(post_id: @status.guid), - params: {access_token: access_token} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(200) likes = response_body_data(response) @@ -61,7 +62,7 @@ describe Api::V1::LikesController do like_service(alice).create(@status.guid) get( api_v1_post_likes_path(post_id: @status.guid), - params: {access_token: access_token} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(200) likes = response_body_data(response) @@ -83,14 +84,24 @@ describe Api::V1::LikesController do end end - context "without private:read scope in token" do - it "fails at getting likes" do + context "with improper credentials" do + context "without private:read scope in token" do + it "fails at getting likes" do + get( + api_v1_post_likes_path(post_id: @private_status.guid), + params: {access_token: access_token_public_only} + ) + expect(response.status).to eq(422) + expect(response.body).to eq(I18n.t("api.endpoint_errors.likes.user_not_allowed_to_like")) + end + end + + it "fails without valid token" do get( api_v1_post_likes_path(post_id: @private_status.guid), - params: {access_token: access_token_public_only} + params: {access_token: invalid_token} ) - expect(response.status).to eq(422) - expect(response.body).to eq(I18n.t("api.endpoint_errors.likes.user_not_allowed_to_like")) + expect(response.status).to eq(401) end end end @@ -126,15 +137,6 @@ describe Api::V1::LikesController do expect(likes.length).to eq(1) expect(likes[0].author.id).to eq(auth.user.person.id) end - - it "fails in liking private post without private:modify" do - post( - api_v1_post_likes_path(post_id: @private_status.guid), - params: {access_token: access_token_public_only} - ) - expect(response.status).to eq(422) - expect(response.body).to eq(I18n.t("api.endpoint_errors.likes.user_not_allowed_to_like")) - end end context "with wrong post id" do @@ -147,6 +149,32 @@ describe Api::V1::LikesController do expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) end end + + context "with improper credentials" do + it "fails in liking private post without private:read" do + post( + api_v1_post_likes_path(post_id: @private_status.guid), + params: {access_token: access_token_public_only} + ) + expect(response.status).to eq(422) + end + + it "fails in liking post without interactions" do + post( + api_v1_post_likes_path(post_id: @private_status.guid), + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails without valid token" do + get( + api_v1_post_likes_path(post_id: @private_status.guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end describe "#delete" do @@ -182,16 +210,6 @@ describe Api::V1::LikesController do likes = like_service.find_for_post(@status.guid) expect(likes.length).to eq(0) end - - it "fails at unliking private post without private:modify" do - like_service(auth_public_only.user).create(@private_status.guid) - delete( - api_v1_post_likes_path(post_id: @private_status.guid), - params: {access_token: access_token} - ) - expect(response.status).to eq(404) - expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) - end end context "with wrong post id" do @@ -204,6 +222,35 @@ describe Api::V1::LikesController do expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) end end + + context "with improper credentials" do + it "fails at unliking private post without private:read" do + like_service(auth_public_only.user).create(@private_status.guid) + delete( + api_v1_post_likes_path(post_id: @private_status.guid), + params: {access_token: access_token} + ) + expect(response.status).to eq(404) + expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) + end + + it "fails in unliking post without interactions" do + like_service(auth_minimum_scopes.user).create(@status.guid) + delete( + api_v1_post_likes_path(post_id: @status.guid), + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails without valid token" do + get( + api_v1_post_likes_path(post_id: @private_status.guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end private diff --git a/spec/integration/api/messages_controller_spec.rb b/spec/integration/api/messages_controller_spec.rb index 74c72d4c8..e64735cda 100644 --- a/spec/integration/api/messages_controller_spec.rb +++ b/spec/integration/api/messages_controller_spec.rb @@ -5,18 +5,27 @@ require "spec_helper" describe Api::V1::MessagesController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid conversations] ) } + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) + } + let!(:access_token) { auth.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do auth.user.seed_aspects - auth.user.share_with bob.person, auth.user.aspects[1] - auth.user.share_with alice.person, auth.user.aspects[1] + auth.user.share_with(bob.person, auth.user.aspects[0]) + auth.user.share_with(alice.person, auth.user.aspects[0]) + auth.user.share_with(auth_minimum_scopes.user.person, auth.user.aspects[0]) alice.share_with auth.user.person, alice.aspects[0] + auth_minimum_scopes.user.seed_aspects + auth_minimum_scopes.user.share_with(auth.user.person, auth_minimum_scopes.user.aspects[0]) @conversation = { subject: "new conversation", @@ -40,7 +49,7 @@ describe Api::V1::MessagesController do api_v1_conversation_messages_path(@conversation_guid), params: {body: @message_text, access_token: access_token} ) - expect(response.status).to eq 201 + expect(response.status).to eq(201) message = JSON.parse(response.body) confirm_message_format(message, @message_text, auth.user) @@ -50,7 +59,7 @@ describe Api::V1::MessagesController do params: {access_token: access_token} ) messages = response_body_data(response) - expect(messages.length).to eq 2 + expect(messages.length).to eq(2) confirm_message_format(messages[1], @message_text, auth.user) end end @@ -61,7 +70,7 @@ describe Api::V1::MessagesController do api_v1_conversation_messages_path(@conversation_guid), params: {access_token: access_token} ) - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq I18n.t("api.endpoint_errors.conversations.cant_process") end @@ -70,7 +79,7 @@ describe Api::V1::MessagesController do api_v1_conversation_messages_path(@conversation_guid), params: {body: "", access_token: access_token} ) - expect(response.status).to eq 422 + expect(response.status).to eq(422) expect(response.body).to eq I18n.t("api.endpoint_errors.conversations.cant_process") end end @@ -81,10 +90,28 @@ describe Api::V1::MessagesController do api_v1_conversation_messages_path(42), params: {access_token: access_token} ) - expect(response.status).to eq 404 + expect(response.status).to eq(404) expect(response.body).to eq I18n.t("api.endpoint_errors.conversations.not_found") end end + + context "improper credentials" do + it "fails without conversation token" do + post( + api_v1_conversation_messages_path(@conversation_guid), + params: {body: @message_text, access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails when not logged in" do + post( + api_v1_conversation_messages_path(@conversation_guid), + params: {body: @message_text, access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end describe "#index " do @@ -99,14 +126,32 @@ describe Api::V1::MessagesController do api_v1_conversation_messages_path(@conversation_guid), params: {access_token: access_token} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) messages = response_body_data(response) - expect(messages.length).to eq 1 + expect(messages.length).to eq(1) confirm_message_format(messages[0], "first message", auth.user) conversation = get_conversation(@conversation_guid) expect(conversation[:read]).to be_truthy end + + context "improper credentials" do + it "fails without conversation token" do + get( + api_v1_conversation_messages_path(@conversation_guid), + params: {access_token: access_token_minimum_scopes} + ) + expect(response.status).to eq(403) + end + + it "fails when not logged in" do + get( + api_v1_conversation_messages_path(@conversation_guid), + params: {access_token: invalid_token} + ) + expect(response.status).to eq(401) + end + end end end diff --git a/spec/integration/api/notifications_controller_spec.rb b/spec/integration/api/notifications_controller_spec.rb index 41ad16945..fe02dc91b 100644 --- a/spec/integration/api/notifications_controller_spec.rb +++ b/spec/integration/api/notifications_controller_spec.rb @@ -7,21 +7,26 @@ describe Api::V1::NotificationsController do FactoryGirl.create(:auth_with_all_scopes) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } before do @post = auth.user.post( :status_message, text: "This is a status message", - public: true, - to: "all" + public: true + ) + + @mentioned_post = alice.post( + :status_message, + text: "This is a status message mentioning @{#{auth.user.diaspora_handle}}" ) @notification = FactoryGirl.create(:notification, recipient: auth.user, target: @post) + @mentioned = FactoryGirl.create(:notification_mentioned_in_comment, recipient: auth.user, target: @post) end describe "#index" do @@ -33,8 +38,8 @@ describe Api::V1::NotificationsController do ) expect(response.status).to eq(200) notification = response_body_data(response) - expect(notification.length).to eq(1) - confirm_notification_format(notification[0], @notification, "also_commented", nil) + expect(notification.length).to eq(2) + confirm_notification_format(notification[1], @notification, "also_commented", nil) end it "with proper credentials and unread only" do @@ -44,7 +49,7 @@ describe Api::V1::NotificationsController do ) expect(response.status).to eq(200) notification = response_body_data(response) - expect(notification.length).to eq(1) + expect(notification.length).to eq(2) @notification.set_read_state(true) get( api_v1_notifications_path, @@ -52,7 +57,7 @@ describe Api::V1::NotificationsController do ) expect(response.status).to eq(200) notification = response_body_data(response) - expect(notification.length).to eq(0) + expect(notification.length).to eq(1) end it "with proper credentials and after certain date" do @@ -62,7 +67,7 @@ describe Api::V1::NotificationsController do ) expect(response.status).to eq(200) notification = response_body_data(response) - expect(notification.length).to eq(1) + expect(notification.length).to eq(2) @notification.set_read_state(true) get( api_v1_notifications_path, @@ -87,7 +92,7 @@ describe Api::V1::NotificationsController do it "with insufficient credentials" do get( api_v1_notifications_path, - params: {access_token: access_token_profile_only} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(403) end @@ -145,7 +150,7 @@ describe Api::V1::NotificationsController do it "with insufficient credentials" do get( api_v1_notification_path(@notification.guid), - params: {access_token: access_token_profile_only} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(403) end @@ -200,7 +205,7 @@ describe Api::V1::NotificationsController do it "with insufficient credentials" do patch( api_v1_notification_path(@notification.guid), - params: {access_token: access_token_profile_only} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(403) end diff --git a/spec/integration/api/photos_controller_spec.rb b/spec/integration/api/photos_controller_spec.rb index a3cf78466..dc3ddf68e 100644 --- a/spec/integration/api/photos_controller_spec.rb +++ b/spec/integration/api/photos_controller_spec.rb @@ -5,41 +5,42 @@ require "spec_helper" describe Api::V1::PhotosController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify private:read private:modify] ) } let(:auth_public_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read private:read] ) } let(:auth_public_only_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read] ) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_public_only) { auth_public_only.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } let!(:access_token_public_only_read_only) { auth_public_only_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do alice_private_spec = alice.aspects.create(name: "private aspect") @@ -73,7 +74,7 @@ describe Api::V1::PhotosController do params: {access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) expect(photo.has_key?("post")).to be_falsey confirm_photo_format(photo, @user_photo1, auth.user) end @@ -84,7 +85,7 @@ describe Api::V1::PhotosController do params: {access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) expect(photo.has_key?("post")).to be_truthy confirm_photo_format(photo, @user_photo2, auth.user) end @@ -95,7 +96,7 @@ describe Api::V1::PhotosController do params: {access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) confirm_photo_format(photo, @alice_public_photo, alice) end end @@ -131,7 +132,7 @@ describe Api::V1::PhotosController do it "with invalid access token" do delete( api_v1_photo_path(@user_photo1.guid), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -172,7 +173,7 @@ describe Api::V1::PhotosController do it "with invalid access token" do delete( api_v1_photos_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -194,7 +195,7 @@ describe Api::V1::PhotosController do params: {image: @encoded_photo, access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) ref_photo = auth.user.photos.reload.find_by(guid: photo["guid"]) expect(ref_photo.pending).to be_falsey confirm_photo_format(photo, ref_photo, auth.user) @@ -206,7 +207,7 @@ describe Api::V1::PhotosController do params: {image: @encoded_photo, pending: false, access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) expect(photo.has_key?("post")).to be_falsey ref_photo = auth.user.photos.reload.find_by(guid: photo["guid"]) expect(ref_photo.pending).to be_falsey @@ -217,7 +218,7 @@ describe Api::V1::PhotosController do params: {image: @encoded_photo, pending: true, access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) ref_photo = auth.user.photos.reload.find_by(guid: photo["guid"]) expect(ref_photo.pending).to be_truthy end @@ -228,7 +229,7 @@ describe Api::V1::PhotosController do params: {image: @encoded_photo, set_profile_photo: true, access_token: access_token} ) expect(response.status).to eq(200) - photo = JSON.parse(response.body) + photo = response_body(response) expect(auth.user.reload.person.profile.image_url_small).to eq(photo["sizes"]["small"]) end end @@ -272,7 +273,7 @@ describe Api::V1::PhotosController do it "with invalid access token" do post( api_v1_photos_path, - params: {image: @encoded_photo, access_token: "999_999_999"} + params: {image: @encoded_photo, access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -330,7 +331,7 @@ describe Api::V1::PhotosController do it "with invalid access token" do delete( api_v1_photo_path(@user_photo1.guid), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -353,8 +354,12 @@ describe Api::V1::PhotosController do end end + def response_body(response) + JSON.parse(response.body) + end + def response_body_data(response) - JSON.parse(response.body)["data"] + response_body(response)["data"] end # rubocop:disable Metrics/AbcSize diff --git a/spec/integration/api/post_interactions_controller_spec.rb b/spec/integration/api/post_interactions_controller_spec.rb index 86d662904..0cbef3b5f 100644 --- a/spec/integration/api/post_interactions_controller_spec.rb +++ b/spec/integration/api/post_interactions_controller_spec.rb @@ -5,25 +5,26 @@ require "spec_helper" describe Api::V1::PostInteractionsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify private:read private:modify interactions] ) } let(:auth_public_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify interactions] ) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_public_only) { auth_public_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @status = alice.post( @@ -36,7 +37,7 @@ describe Api::V1::PostInteractionsController do alice_shared_aspect = alice.aspects.create(name: "shared aspect") alice.share_with(auth_public_only.user.person, alice_shared_aspect) alice.share_with(auth.user.person, alice_shared_aspect) - alice.share_with(auth_profile_only.user.person, alice_shared_aspect) + alice.share_with(auth_minimum_scopes.user.person, alice_shared_aspect) @shared_post = alice.post(:status_message, text: "to aspect only", public: false, to: alice_shared_aspect.id) end @@ -89,7 +90,7 @@ describe Api::V1::PostInteractionsController do post( api_v1_post_subscribe_path(@status.guid), params: { - access_token: access_token_profile_only + access_token: access_token_minimum_scopes } ) expect(response.status).to eq(403) @@ -109,7 +110,7 @@ describe Api::V1::PostInteractionsController do post( api_v1_post_subscribe_path(@status.guid), params: { - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) @@ -148,7 +149,7 @@ describe Api::V1::PostInteractionsController do post( api_v1_post_hide_path(@status.guid), params: { - access_token: access_token_profile_only + access_token: access_token_minimum_scopes } ) expect(response.status).to eq(403) @@ -168,7 +169,7 @@ describe Api::V1::PostInteractionsController do post( api_v1_post_hide_path(@status.guid), params: { - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) @@ -234,7 +235,7 @@ describe Api::V1::PostInteractionsController do post( api_v1_post_mute_path(@status.guid), params: { - access_token: access_token_profile_only + access_token: access_token_minimum_scopes } ) expect(response.status).to eq(403) @@ -254,7 +255,7 @@ describe Api::V1::PostInteractionsController do post( api_v1_post_mute_path(@status.guid), params: { - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) @@ -327,7 +328,7 @@ describe Api::V1::PostInteractionsController do api_v1_post_report_path(@status.guid), params: { reason: "My reason", - access_token: access_token_profile_only + access_token: access_token_minimum_scopes } ) expect(response.status).to eq(403) @@ -349,7 +350,7 @@ describe Api::V1::PostInteractionsController do api_v1_post_report_path(@status.guid), params: { reason: "My reason", - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) @@ -427,7 +428,7 @@ describe Api::V1::PostInteractionsController do api_v1_post_vote_path(@poll_post.guid), params: { poll_answer_id: @poll_answer.id, - access_token: access_token_profile_only + access_token: access_token_minimum_scopes } ) expect(response.status).to eq(403) @@ -449,7 +450,7 @@ describe Api::V1::PostInteractionsController do api_v1_post_vote_path(@poll_post.guid), params: { poll_answer_id: @poll_answer.id, - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) diff --git a/spec/integration/api/posts_controller_spec.rb b/spec/integration/api/posts_controller_spec.rb index 61b96ecc7..3463a3f46 100644 --- a/spec/integration/api/posts_controller_spec.rb +++ b/spec/integration/api/posts_controller_spec.rb @@ -5,51 +5,47 @@ require "spec_helper" describe Api::V1::PostsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify private:read private:modify] ) } let(:auth_public_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read private:read] ) } let(:auth_public_only_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read] ) } - let(:auth_profile_only) { FactoryGirl.create(:auth_with_profile_only) } + let(:auth_minimum_scopes) { FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_public_only) { auth_public_only.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } let!(:access_token_public_only_read_only) { auth_public_only_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } - let(:alice_aspect) { alice.aspects.first } - - let(:alice_photo1) { - alice.build_post(:photo, pending: true, user_file: File.open(photo_fixture_name), to: alice_aspect.id).tap(&:save!) - } - - let(:alice_photo2) { - alice.build_post(:photo, pending: true, user_file: File.open(photo_fixture_name), to: alice_aspect.id).tap(&:save!) - } - - let(:alice_photo_ids) { [alice_photo1.id.to_s, alice_photo2.id.to_s] } - let(:alice_photo_guids) { [alice_photo1.guid, alice_photo2.guid] } + before do + @alice_aspect = alice.aspects.first + @alice_photo1 = alice.post(:photo, pending: true, user_file: File.open(photo_fixture_name), to: @alice_aspect.id) + @alice_photo2 = alice.post(:photo, pending: true, user_file: File.open(photo_fixture_name), to: @alice_aspect.id) + @alice_photo_ids = [@alice_photo1.id.to_s, @alice_photo2.id.to_s] + @alice_photo_guids = [@alice_photo1.guid, @alice_photo2.guid] + end describe "#show" do before do @@ -82,7 +78,7 @@ describe Api::V1::PostsController do location_params = {location_address: "somewhere", location_coords: "1,2"} merged_params = base_params.merge(location_params) merged_params = merged_params.merge(poll_params) - merged_params = merged_params.merge(photos: alice_photo_ids) + merged_params = merged_params.merge(photos: @alice_photo_ids) status_message = StatusMessageCreationService.new(alice).create(merged_params) get( @@ -164,28 +160,35 @@ describe Api::V1::PostsController do expect(response.body).to eq(I18n.t("api.endpoint_errors.posts.post_not_found")) end end + + context "access with invalid token" do + it "fails" do + get( + api_v1_post_path(@status.guid), + params: { + access_token: invalid_token + } + ) + expect(response.status).to eq(401) + end + end end describe "#create" do - let(:user_photo1) { - auth.user.build_post(:photo, pending: true, - user_file: File.open(photo_fixture_name), to: "all").tap(&:save!) - } - let(:user_photo2) { - auth.user.build_post(:photo, pending: true, - user_file: File.open(photo_fixture_name), to: "all").tap(&:save!) - } - - let(:user_photo_ids) { [user_photo1.id.to_s, user_photo2.id.to_s] } - let(:user_photo_guids) { [user_photo1.guid, user_photo2.guid] } + before do + @user_photo1 = auth.user.post(:photo, pending: true, user_file: File.open(photo_fixture_name), public: true) + @user_photo2 = auth.user.post(:photo, pending: true, user_file: File.open(photo_fixture_name), public: true) + @user_photo3 = auth.user.post(:photo, pending: false, user_file: File.open(photo_fixture_name), public: true) + @user_photo_ids = [@user_photo1.id.to_s, @user_photo2.id.to_s] + @user_photo_guids = [@user_photo1.guid, @user_photo2.guid] + end context "when given read-write access token" do it "creates a public post" do post_for_ref_only = auth.user.post( :status_message, text: "Hello this is a public post!", - public: true, - to: "all" + public: true ) post( @@ -242,9 +245,6 @@ describe Api::V1::PostsController do context "with fully populated post" do it "creates with photos" do message_text = "Post with photos" - base_params = {status_message: {text: message_text}, public: true} - merged_params = base_params.merge(photos: user_photo_ids) - post_for_ref_only = StatusMessageCreationService.new(auth.user).create(merged_params) post( api_v1_posts_path, @@ -252,11 +252,20 @@ describe Api::V1::PostsController do access_token: access_token, body: message_text, public: true, - photos: user_photo_guids + photos: @user_photo_guids } ) expect(response.status).to eq(200) post = response_body(response) + + @user_photo1[:pending] = true + @user_photo1.save + @user_photo2[:pending] = true + @user_photo2.save + base_params = {status_message: {text: message_text}, public: true} + merged_params = base_params.merge(photos: @user_photo_ids) + post_for_ref_only = StatusMessageCreationService.new(auth.user).create(merged_params) + confirm_post_format(post, auth.user, post_for_ref_only) end @@ -269,15 +278,28 @@ describe Api::V1::PostsController do access_token: access_token, body: message_text, public: true, - photos: alice_photo_guids + photos: @alice_photo_guids } ) - expect(response.status).to eq(200) - post = JSON.parse(response.body) - expect(post["photos"].empty?).to be_truthy + expect(response.status).to eq(422) end - it "fails to add bad guid" do + it "fails to add non-pending photos" do + message_text = "Post with photos" + + post( + api_v1_posts_path, + params: { + access_token: access_token, + body: message_text, + public: true, + photos: [@user_photo3.guid] + } + ) + expect(response.status).to eq(422) + end + + it "fails to add bad photo guids" do message_text = "Post with photos" post( @@ -434,17 +456,6 @@ describe Api::V1::PostsController do end end - # TODO: Add when doing reshares endpoint - xcontext "when reshared" do - it "creates post with identical fields plus root" do - raise NotImplementedError - end - - it "fails to reshare post user can't see" do - raise NotImplementedError - end - end - context "when given missing format" do it "fails when no body" do post( @@ -517,8 +528,8 @@ describe Api::V1::PostsController do end end - context "when given read only access token" do - it "doesn't create the post" do + context "improper credentials" do + it "fails without modify token" do post( api_v1_posts_path, params: { @@ -529,6 +540,18 @@ describe Api::V1::PostsController do ) expect(response.status).to eq(403) end + + it "fails without invalid token" do + post( + api_v1_posts_path, + params: { + access_token: invalid_token, + status_message: {text: "Hello this is a post!"}, + public: true + } + ) + expect(response.status).to eq(401) + end end end @@ -565,6 +588,22 @@ describe Api::V1::PostsController do end end + context "when given invalid token" do + it "doesn't delete the post" do + @status = auth.user.post( + :status_message, + text: "hello", + public: true + ) + delete( + api_v1_post_path(@status.guid), + params: {access_token: invalid_token} + ) + + expect(response.status).to eq(401) + end + end + context "when post is private but no private:modify scope in token" do it "doesn't delete the post" do aspect = auth_public_only.user.aspects.create(name: "new aspect") diff --git a/spec/integration/api/reshares_controller_spec.rb b/spec/integration/api/reshares_controller_spec.rb index d8be142e7..f605e749d 100644 --- a/spec/integration/api/reshares_controller_spec.rb +++ b/spec/integration/api/reshares_controller_spec.rb @@ -11,13 +11,14 @@ describe Api::V1::ResharesController do FactoryGirl.create(:auth_with_read_scopes) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @user_post = auth.user.post( @@ -102,7 +103,7 @@ describe Api::V1::ResharesController do get( api_v1_post_reshares_path(@user_post.id), params: { - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) @@ -190,7 +191,7 @@ describe Api::V1::ResharesController do post( api_v1_post_reshares_path(@eve_post.id), params: { - access_token: "999_999_999" + access_token: invalid_token } ) expect(response.status).to eq(401) @@ -200,10 +201,10 @@ describe Api::V1::ResharesController do post( api_v1_post_reshares_path(@eve_post.id), params: { - access_token: auth_read_only + access_token: access_token_read_only } ) - expect(response.status).to eq(401) + expect(response.status).to eq(403) end end end diff --git a/spec/integration/api/search_controller_spec.rb b/spec/integration/api/search_controller_spec.rb index 883f8e22a..252d3478e 100644 --- a/spec/integration/api/search_controller_spec.rb +++ b/spec/integration/api/search_controller_spec.rb @@ -5,21 +5,21 @@ require "spec_helper" describe Api::V1::SearchController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify private:read private:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read private:read] ) } let(:auth_public_only_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read] ) } @@ -27,6 +27,7 @@ describe Api::V1::SearchController do let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } let!(:access_token_public_only_read_only) { auth_public_only_read_only.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } describe "#user_index" do before do @@ -137,7 +138,7 @@ describe Api::V1::SearchController do it "fails with bad credentials" do get( "/api/v1/search/users", - params: {tag: "tag1", access_token: "999_999_999"} + params: {tag: "tag1", access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -208,7 +209,7 @@ describe Api::V1::SearchController do it "fails with bad credentials" do get( "/api/v1/search/users", - params: {tag: "tag1", access_token: "999_999_999"} + params: {tag: "tag1", access_token: invalid_token} ) expect(response.status).to eq(401) end diff --git a/spec/integration/api/streams_controller_spec.rb b/spec/integration/api/streams_controller_spec.rb index 32a01056a..883ca2c9f 100644 --- a/spec/integration/api/streams_controller_spec.rb +++ b/spec/integration/api/streams_controller_spec.rb @@ -5,21 +5,21 @@ require "spec_helper" describe Api::V1::StreamsController do let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read private:read contacts:read tags:read] ) } let(:auth_public_only_tags) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read tags:read] ) } let(:auth_public_only_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read] ) } @@ -27,6 +27,7 @@ describe Api::V1::StreamsController do let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } let!(:access_token_public_only_tags) { auth_public_only_tags.create_access_token.to_s } let!(:access_token_public_only_read_only) { auth_public_only_read_only.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @aspect = auth_read_only.user.aspects.create(name: "new aspect") @@ -76,7 +77,7 @@ describe Api::V1::StreamsController do api_v1_aspects_stream_path(aspect_ids: JSON.generate([@aspect.id])), params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) expect(post.length).to eq 3 json_post = post.select {|p| p["guid"] == @status.guid }.first @@ -88,9 +89,9 @@ describe Api::V1::StreamsController do api_v1_aspects_stream_path, params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 3 + expect(post.length).to eq(3) json_post = post.select {|p| p["guid"] == @status.guid }.first confirm_post_format(json_post, auth_read_only.user, @status) end @@ -114,7 +115,7 @@ describe Api::V1::StreamsController do it "fails with invalid credentials" do get( api_v1_aspects_stream_path(a_ids: [@aspect.id]), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -164,9 +165,9 @@ describe Api::V1::StreamsController do api_v1_activity_stream_path, params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 2 + expect(post.length).to eq(2) json_post = post.select {|p| p["guid"] == @status.guid }.first confirm_post_format(json_post, auth_read_only.user, @status) end @@ -184,7 +185,7 @@ describe Api::V1::StreamsController do it "fails with invalid credentials" do get( api_v1_activity_stream_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -196,9 +197,9 @@ describe Api::V1::StreamsController do api_v1_stream_path, params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 3 + expect(post.length).to eq(3) json_post = post.select {|p| p["guid"] == @status.guid }.first confirm_post_format(json_post, auth_read_only.user, @status) end @@ -208,17 +209,17 @@ describe Api::V1::StreamsController do api_v1_stream_path, params: {access_token: access_token_public_only_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 1 + expect(post.length).to eq(1) end it "fails with invalid credentials" do get( api_v1_stream_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) - expect(response.status).to eq 401 + expect(response.status).to eq(401) end end @@ -228,9 +229,9 @@ describe Api::V1::StreamsController do api_v1_commented_stream_path, params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 2 + expect(post.length).to eq(2) end it "public posts only expected" do @@ -238,17 +239,17 @@ describe Api::V1::StreamsController do api_v1_commented_stream_path, params: {access_token: access_token_public_only_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 1 + expect(post.length).to eq(1) end it "fails with invalid credentials" do get( api_v1_commented_stream_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) - expect(response.status).to eq 401 + expect(response.status).to eq(401) end end @@ -258,9 +259,9 @@ describe Api::V1::StreamsController do api_v1_mentions_stream_path, params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 2 + expect(post.length).to eq(2) end it "public posts only expected" do @@ -268,17 +269,17 @@ describe Api::V1::StreamsController do api_v1_mentions_stream_path, params: {access_token: access_token_public_only_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 1 + expect(post.length).to eq(1) end it "fails with invalid credentials" do get( api_v1_mentions_stream_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) - expect(response.status).to eq 401 + expect(response.status).to eq(401) end end @@ -288,9 +289,9 @@ describe Api::V1::StreamsController do api_v1_liked_stream_path, params: {access_token: access_token_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 2 + expect(post.length).to eq(2) json_post = post.select {|p| p["guid"] == @status.guid }.first confirm_post_format(json_post, auth_read_only.user, @status) end @@ -300,17 +301,17 @@ describe Api::V1::StreamsController do api_v1_liked_stream_path, params: {access_token: access_token_public_only_read_only} ) - expect(response.status).to eq 200 + expect(response.status).to eq(200) post = response_body_data(response) - expect(post.length).to eq 1 + expect(post.length).to eq(1) end it "fails with invalid credentials" do get( api_v1_liked_stream_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) - expect(response.status).to eq 401 + expect(response.status).to eq(401) end end diff --git a/spec/integration/api/tag_followings_controller_spec.rb b/spec/integration/api/tag_followings_controller_spec.rb index eb26c4257..9f6e3ebb9 100755 --- a/spec/integration/api/tag_followings_controller_spec.rb +++ b/spec/integration/api/tag_followings_controller_spec.rb @@ -5,22 +5,23 @@ require "spec_helper" describe Api::V1::TagFollowingsController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid tags:read tags:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid tags:read] ) } - let(:auth_profile_only) { FactoryGirl.create(:auth_with_profile_only) } + let(:auth_minimum_scopes) { FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } before do @expected_tags = %w[tag1 tag2 tag3] @@ -84,7 +85,7 @@ describe Api::V1::TagFollowingsController do it "invalid token" do post( api_v1_tag_followings_path, - params: {name: "tag4", access_token: "999_999_999"} + params: {name: "tag4", access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -109,7 +110,7 @@ describe Api::V1::TagFollowingsController do it "insufficient scopes in token" do get( api_v1_tag_followings_path, - params: {access_token: access_token_profile_only} + params: {access_token: access_token_minimum_scopes} ) expect(response.status).to eq(403) end @@ -117,7 +118,7 @@ describe Api::V1::TagFollowingsController do it "invalid token" do get( api_v1_tag_followings_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -173,7 +174,7 @@ describe Api::V1::TagFollowingsController do it "invalid token" do delete( api_v1_tag_following_path("tag1"), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end diff --git a/spec/integration/api/users_controller_spec.rb b/spec/integration/api/users_controller_spec.rb index e76adfd2a..ccca37bd1 100644 --- a/spec/integration/api/users_controller_spec.rb +++ b/spec/integration/api/users_controller_spec.rb @@ -11,40 +11,41 @@ describe Api::V1::UsersController do let(:auth) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: full_scopes ) } let(:auth_public_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read public:modify] ) } let(:auth_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read private:read contacts:read profile] ) } let(:auth_public_only_read_only) { FactoryGirl.create( - :auth_with_profile_only, + :auth_with_default_scopes, scopes: %w[openid public:read] ) } - let(:auth_profile_only) { - FactoryGirl.create(:auth_with_profile_only) + let(:auth_minimum_scopes) { + FactoryGirl.create(:auth_with_default_scopes) } let!(:access_token) { auth.create_access_token.to_s } let!(:access_token_public_only) { auth_public_only.create_access_token.to_s } let!(:access_token_read_only) { auth_read_only.create_access_token.to_s } let!(:access_token_public_only_read_only) { auth_public_only_read_only.create_access_token.to_s } - let!(:access_token_profile_only) { auth_profile_only.create_access_token.to_s } + let!(:access_token_minimum_scopes) { auth_minimum_scopes.create_access_token.to_s } + let(:invalid_token) { SecureRandom.hex(9) } describe "#show" do context "Current User" do @@ -53,7 +54,7 @@ describe Api::V1::UsersController do api_v1_user_path, params: {access_token: access_token} ) - user = JSON.parse(response.body) + user = response_body(response) expect(response.status).to eq(200) expect(user["guid"]).to eq(auth.user.guid) confirm_self_data_format(user) @@ -62,7 +63,7 @@ describe Api::V1::UsersController do it "fails if invalid token" do get( api_v1_user_path, - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -76,7 +77,7 @@ describe Api::V1::UsersController do "/api/v1/users/#{alice.guid}", params: {access_token: access_token} ) - user = JSON.parse(response.body) + user = response_body(response) expect(response.status).to eq(200) expect(user["guid"]).to eq(alice.person.guid) confirm_public_profile_hash(user) @@ -91,7 +92,7 @@ describe Api::V1::UsersController do "/api/v1/users/#{alice.guid}", params: {access_token: access_token} ) - user = JSON.parse(response.body) + user = response_body(response) expect(response.status).to eq(200) expect(user["guid"]).to eq(alice.person.guid) confirm_public_profile_hash(user) @@ -104,7 +105,7 @@ describe Api::V1::UsersController do "/api/v1/users/#{eve.guid}", params: {access_token: access_token} ) - user = JSON.parse(response.body) + user = response_body(response) expect(response.status).to eq(200) expect(user["guid"]).to eq(eve.person.guid) confirm_private_profile_hash(user) @@ -115,7 +116,7 @@ describe Api::V1::UsersController do "/api/v1/users/#{eve.guid}", params: {access_token: access_token} ) - user = JSON.parse(response.body) + user = response_body(response) expect(response.status).to eq(200) expect(user["guid"]).to eq(eve.person.guid) confirm_public_profile_hash(user) @@ -124,7 +125,7 @@ describe Api::V1::UsersController do it "fails if invalid token" do get( "/api/v1/users/#{alice.guid}", - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -143,9 +144,9 @@ describe Api::V1::UsersController do get( "/api/v1/users/#{unsearchable_user.guid}", - params: {access_token: access_token_profile_only} + params: {access_token: access_token_minimum_scopes} ) - expect(response.status).to eq(404) + expect(response.status).to eq(403) end it "fails with invalid user GUID" do @@ -169,7 +170,7 @@ describe Api::V1::UsersController do params: {location: new_location, bio: new_bio, access_token: access_token} ) expect(response.status).to eq(200) - user = JSON.parse(response.body) + user = response_body(response) confirm_self_data_format(user) expect(user["bio"]).to eq(new_bio) expect(user["location"]).to eq(new_location) @@ -208,7 +209,7 @@ describe Api::V1::UsersController do } ) expect(response.status).to eq(200) - user = JSON.parse(response.body) + user = response_body(response) confirm_self_data_format(user) expect(user["bio"]).to eq(new_bio) expect(user["birthday"]).to eq(birthday_format(new_birthday)) @@ -246,7 +247,7 @@ describe Api::V1::UsersController do } ) expect(response.status).to eq(200) - user = JSON.parse(response.body) + user = response_body(response) expect(user["bio"]).to eq(new_bio) expect(user.has_key?("no_idea_what_field_this_is")).to be_falsey end @@ -263,7 +264,7 @@ describe Api::V1::UsersController do } ) expect(response.status).to eq(200) - user = JSON.parse(response.body) + user = response_body(response) expect(user["bio"]).to eq(new_bio) expect(user["guid"]).to eq(original_guid) end @@ -271,7 +272,11 @@ describe Api::V1::UsersController do it "fails if invalid token" do patch( api_v1_user_path, - params: {location: "New Location", bio: "New Bio", access_token: "999_999_999"} + params: { + location: "New Location", + bio: "New Bio", + access_token: invalid_token + } ) expect(response.status).to eq(401) end @@ -279,7 +284,11 @@ describe Api::V1::UsersController do it "fails if read only token" do patch( api_v1_user_path, - params: {location: "New Location", bio: "New Bio", access_token: access_token_read_only} + params: { + location: "New Location", + bio: "New Bio", + access_token: access_token_read_only + } ) expect(response.status).to eq(403) end @@ -337,7 +346,7 @@ describe Api::V1::UsersController do it "fails if invalid token" do get( api_v1_user_contacts_path(alice.guid), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -393,7 +402,7 @@ describe Api::V1::UsersController do params: {access_token: access_token} ) expect(response.status).to eq(200) - photos = JSON.parse(response.body) + photos = response_body(response) expect(photos.length).to eq(2) end end @@ -410,7 +419,7 @@ describe Api::V1::UsersController do it "fails if invalid token" do get( api_v1_user_photos_path(alice.guid), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -482,7 +491,7 @@ describe Api::V1::UsersController do it "fails if invalid token" do get( api_v1_user_posts_path(alice.person.guid), - params: {access_token: "999_999_999"} + params: {access_token: invalid_token} ) expect(response.status).to eq(401) end @@ -573,7 +582,11 @@ describe Api::V1::UsersController do end # rubocop:enable Metrics/AbcSize + def response_body(response) + JSON.parse(response.body) + end + def response_body_data(response) - JSON.parse(response.body)["data"] + response_body(response)["data"] end end diff --git a/spec/lib/api/paging/index_paginator_spec.rb b/spec/lib/api/paging/index_paginator_spec.rb index d49973df2..5c104ccaa 100644 --- a/spec/lib/api/paging/index_paginator_spec.rb +++ b/spec/lib/api/paging/index_paginator_spec.rb @@ -3,7 +3,7 @@ describe Api::Paging::IndexPaginator do before do (1..7).each do |i| - public = !(i == 1 || i == 6) + public = ![1, 6].include?(i) alice.post( :status_message, text: "Post #{i}", diff --git a/spec/lib/api/paging/time_paginator_spec.rb b/spec/lib/api/paging/time_paginator_spec.rb index 211645ea9..788b8ec7a 100644 --- a/spec/lib/api/paging/time_paginator_spec.rb +++ b/spec/lib/api/paging/time_paginator_spec.rb @@ -3,7 +3,7 @@ describe Api::Paging::TimePaginator do before do (1..7).each do |i| - public = !(i == 1 || i == 6) + public = ![1, 6].include?(i) alice.post( :status_message, text: "Post #{i}", diff --git a/spec/models/api/openid_connect/id_token_spec.rb b/spec/models/api/openid_connect/id_token_spec.rb index 4134007db..2409d78a6 100644 --- a/spec/models/api/openid_connect/id_token_spec.rb +++ b/spec/models/api/openid_connect/id_token_spec.rb @@ -2,7 +2,7 @@ describe Api::OpenidConnect::IdToken, type: :model do describe "#to_jwt" do - let(:auth) { FactoryGirl.create(:auth_with_profile_only) } + let(:auth) { FactoryGirl.create(:auth_with_default_scopes) } let(:id_token) { Api::OpenidConnect::IdToken.new(auth, "nonce") } describe "decoded data" do diff --git a/spec/presenters/notification_presenter_spec.rb b/spec/presenters/notification_presenter_spec.rb index 0902e420a..b981efe31 100644 --- a/spec/presenters/notification_presenter_spec.rb +++ b/spec/presenters/notification_presenter_spec.rb @@ -20,4 +20,12 @@ describe NotificationPresenter do json = NotificationPresenter.new(@notification).as_api_json(false) expect(json.has_key?(:target)).to be_falsey end + + it "Makes target on mentioned" do + mentioned_post = FactoryGirl.create(:status_message_in_aspect, author: alice.person, text: text_mentioning(bob)) + Notifications::MentionedInPost.notify(mentioned_post, [bob.id]) + notification = Notifications::MentionedInPost.last + json = NotificationPresenter.new(notification).as_api_json(true) + expect(json[:target][:guid]).to eq(mentioned_post.guid) + end end diff --git a/spec/services/photo_service_spec.rb b/spec/services/photo_service_spec.rb index 41a7187b1..2a4dba2e7 100644 --- a/spec/services/photo_service_spec.rb +++ b/spec/services/photo_service_spec.rb @@ -10,8 +10,8 @@ describe PhotoService do to: alice_eve_spec.id) @alice_bob_photo = alice.post(:photo, pending: false, user_file: File.open(photo_fixture_name), to: alice_bob_spec.id) - @alice_public_photo = alice.post(:photo, pending: false, user_file: File.open(photo_fixture_name), to: "all") - @bob_photo1 = bob.post(:photo, pending: true, user_file: File.open(photo_fixture_name), to: "all") + @alice_public_photo = alice.post(:photo, pending: false, user_file: File.open(photo_fixture_name), public: true) + @bob_photo1 = bob.post(:photo, pending: true, user_file: File.open(photo_fixture_name), public: true) end describe "visible_photo" do @@ -38,10 +38,7 @@ describe PhotoService do describe "create" do before do - @image_file = Rack::Test::UploadedFile.new( - Rails.root.join("spec", "fixtures", "button.png").to_s, - "image/png" - ) + @image_file = Rack::Test::UploadedFile.new(Rails.root.join("spec", "fixtures", "button.png").to_s, "image/png") end context "succeeds" do @@ -61,7 +58,7 @@ describe PhotoService do expect(photo.public?).to be_falsey end - it "accepts sets a user profile when requested" do + it "sets a user profile when requested" do original_profile_pic = bob.person.profile.image_url params = ActionController::Parameters.new(set_profile_photo: true) photo = photo_service.create_from_params_and_file(params, @image_file) @@ -79,10 +76,11 @@ describe PhotoService do it "allow raw file if explicitly allowing" do params = ActionController::Parameters.new - photo = PhotoService.new(bob, false).create_from_params_and_file(params, uploaded_photo) + photo = photo_service(bob, false).create_from_params_and_file(params, uploaded_photo) expect(photo).not_to be_nil end end + context "fails" do before do @params = ActionController::Parameters.new @@ -95,18 +93,12 @@ describe PhotoService do end it "file type isn't an image" do - text_file = Rack::Test::UploadedFile.new( - Rails.root.join("README.md").to_s, - "text/plain" - ) + text_file = Rack::Test::UploadedFile.new(Rails.root.join("README.md").to_s, "text/plain") expect { photo_service.create_from_params_and_file(@params, text_file) }.to raise_error CarrierWave::IntegrityError - text_file = Rack::Test::UploadedFile.new( - Rails.root.join("README.md").to_s, - "image/png" - ) + text_file = Rack::Test::UploadedFile.new(Rails.root.join("README.md").to_s, "image/png") expect { photo_service.create_from_params_and_file(@params, text_file) }.to raise_error CarrierWave::IntegrityError @@ -114,7 +106,7 @@ describe PhotoService do end end - def photo_service(user=bob) - PhotoService.new(user, true) + def photo_service(user=bob, deny_raw_files=true) + PhotoService.new(user, deny_raw_files) end end