diff --git a/app/controllers/api/v1/profiles_controller.rb b/app/controllers/api/v1/profiles_controller.rb index b92e186d..8997c83d 100644 --- a/app/controllers/api/v1/profiles_controller.rb +++ b/app/controllers/api/v1/profiles_controller.rb @@ -4,13 +4,15 @@ module API module V1 # Controller class that is responsible for handling profile requests. class ProfilesController < ApplicationController - before_action :set_profile, only: %i[show update] before_action :authorize_profile! + before_action :set_profile, except: %i[index create] + before_action :set_tag, only: %i[remove_tag] after_action :verify_authorized # GET /profiles or /profiles.json def index - render json: Profile.all, status: :ok + profiles = Profile.all + render json: profiles, status: :ok end # GET /profiles/:id or /profiles/:id.json @@ -37,16 +39,45 @@ def update end end - private + # POST /profiles/:id/add_tag or /profiles/:id/add_tag.json + def add_tag + tag = Tag.find_or_create_by(params[:tag]) + if tag_params.blank? + render json: { error: 'There was no tag data passed in so your profile could not be saved.' }, + status: :unprocessable_entity + else + if @profile.tags << tag + render json: @profile, status: :created + else + render json: @profile.errors, status: :unprocessable_entity + end + end + end def set_profile @profile = Profile.find_by(user_id: params[:user_id]) end + # DELETE /profiles/:profile_id/remove_tag/:id or /profiles/:profile_id/remove_tag/:id.json + def remove_tag + @profile.tags.destroy(@tag) + head 204 + end + + private + + def set_tag + @tag = Tag.find_by(name: params[:name]) + end + def profile_params params.permit(:surname, :name, :patronymic, :birthday, :phone, :about, :user_id) end + def tag_params + params.permit(:name) + end + def authorize_profile! authorize(@profile || Profile) end diff --git a/app/policies/profile_policy.rb b/app/policies/profile_policy.rb index 24ebbaa2..3a59597e 100644 --- a/app/policies/profile_policy.rb +++ b/app/policies/profile_policy.rb @@ -14,6 +14,14 @@ def update? owns_record? end + def add_tag? + update? + end + + def remove_tag? + update? + end + # Profile policy scope class Scope < Scope def resolve diff --git a/app/serializers/profile_serializer.rb b/app/serializers/profile_serializer.rb index ef06605b..d2a228ce 100644 --- a/app/serializers/profile_serializer.rb +++ b/app/serializers/profile_serializer.rb @@ -29,5 +29,5 @@ # Сlass responsible for serializing profile data class ProfileSerializer < ActiveModel::Serializer attributes :id, :surname, :name, :patronymic, - :birthday, :phone, :about + :birthday, :phone, :about, :tags end diff --git a/config/routes.rb b/config/routes.rb index 9eba3ef3..176f8eab 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,11 +19,16 @@ post :subscribe, to: 'user_subscriptions#subscribe' post :unsubscribe, to: 'user_subscriptions#unsubscribe' end + resources :likes, only: %i[create destroy index] resources :messages, except: %i[index, show] resources :conversations do post 'add_user/:user_id', to: 'conversations#add_user' delete 'delete_user/:user_id', to: 'conversations#delete_user' + get :profile, to: 'profiles#show' + put :profile, to: 'profiles#update' + post '/add_tag', to: 'profiles#add_tag' + delete '/remove_tag/:name', to: 'profiles#remove_tag' end get '/search_profile', to: 'search#search_profile' get '/search_conversation', to: 'search#search_conversation' diff --git a/spec/factories/tags.rb b/spec/factories/tags.rb index e12dfb73..a6cebcaf 100644 --- a/spec/factories/tags.rb +++ b/spec/factories/tags.rb @@ -15,6 +15,6 @@ # FactoryBot.define do factory :tag do - name { Faker::Hobby.unique.activity } + name { Faker::Hobby.unique.activity.downcase.gsub(' ','_') } end end diff --git a/spec/policies/profile_policy_spec.rb b/spec/policies/profile_policy_spec.rb index ff0cacc6..84771132 100644 --- a/spec/policies/profile_policy_spec.rb +++ b/spec/policies/profile_policy_spec.rb @@ -22,8 +22,8 @@ end end - permissions :update?, :edit?, :destroy? do - it "is not allowed to update and delete the instance that doesn't belong to him" do + permissions :update?, :edit?, :destroy?, :add_tag?, :remove_tag? do + it "is not allowed to update and delete the instance and that tags that doesn't belong to him" do expect(policy).not_to permit(user, record) end end @@ -33,7 +33,7 @@ let(:user) { create :user } let(:record) { user.profile } - permissions :update?, :edit? do + permissions :update?, :edit?, :add_tag?, :remove_tag? do it 'is allowed to update the instance' do expect(policy).to permit(user, record) end diff --git a/spec/requests/profiles_spec.rb b/spec/requests/profiles_spec.rb index 74f9adfc..14bf0f65 100644 --- a/spec/requests/profiles_spec.rb +++ b/spec/requests/profiles_spec.rb @@ -2,6 +2,7 @@ require 'rails_helper' +# rubocop:disable Metrics/BlockLength RSpec.describe 'Profiles', type: :request do let(:current_user) { FactoryBot.create(:user) } let(:auth_headers) { current_user.create_new_auth_token } @@ -182,4 +183,80 @@ end end end + + describe 'POST /api/v1/profiles/:id/add_tag' do + describe 'add tag to profile' do + let(:current_user_profile) { FactoryBot.create(:profile, user_id: current_user.id) } + let(:tag) { FactoryBot.create(:tag) } + + before { post "/api/v1/profiles/#{current_user_profile.id}/add_tag", params: { name: tag.name }, headers: auth_headers } + + context 'when user is authenticated' do + it 'creates profile tag' do + expect(response).to have_http_status(:created) + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + context 'with profile that is not current user\'s profile' do + let(:not_current_user_profile) { FactoryBot.create(:profile) } + let(:tag) { FactoryBot.create(:tag) } + + before { post "/api/v1/profiles/#{not_current_user_profile.id}/add_tag", params: { name: tag.name }, headers: auth_headers } + + it 'can\'t create profile tag' do + expect(response).to have_http_status(:forbidden) + end + end + end + + context 'when user is not authenticated' do + before { post "/api/v1/profiles/#{current_user_profile.id}/add_tag", params: { name: tag.name } } + + it 'have http status 401' do + expect(response).to have_http_status(:unauthorized) + end + end + end + end + + describe 'DELETE /api/v1/profiles/:profile_id/remove_tag/:name' do + describe 'delete tag from profile' do + let(:current_user_profile) { create :profile, user: current_user } + let(:tag) { FactoryBot.create(:tag) } + + before { delete "/api/v1/profiles/#{current_user_profile.id}/remove_tag/#{tag.name}", headers: auth_headers } + + context 'when user is authenticated' do + it 'returns no content' do + expect(response).to have_http_status(:no_content) + end + + it 'returns http success' do + expect(response).to have_http_status(:success) + end + + context 'with profile that is not current user\'s profile' do + let(:not_current_user_profile) { FactoryBot.create(:profile) } + + before { delete "/api/v1/profiles/#{not_current_user_profile.id}/remove_tag/#{tag.name}", headers: auth_headers } + + it 'can\'t delete profile tag' do + expect(response).to have_http_status(:forbidden) + end + end + end + + context 'when user is not authenticated' do + before { delete "/api/v1/profiles/#{current_user_profile.id}/remove_tag/#{tag.name}" } + + it 'have http status 401' do + expect(response).to have_http_status(:unauthorized) + end + end + end + end end +# rubocop:enable Metrics/BlockLength