diff --git a/app/controllers/api/v1/users/user_images_controller.rb b/app/controllers/api/v1/users/user_images_controller.rb index 87c38821b..c964e8b71 100644 --- a/app/controllers/api/v1/users/user_images_controller.rb +++ b/app/controllers/api/v1/users/user_images_controller.rb @@ -3,7 +3,7 @@ module Api module V1 module Users class UserImagesController < BaseController - before_action :set_user, only: [:show] + before_action :set_user, only: [:show, :create] before_action :set_user_image, only: [:show] api :GET, '/users/:user_id/images/:id', 'Show user image' @@ -17,7 +17,7 @@ def show api_render(@user_image) end - api :POST, '/users/images/', 'User images' + api :POST, '/users/:user_id/images/', 'User images' description 'Creates a user image' error code: 422, desc: 'Unprocessable entity' param :image, File, desc: 'Image (multipart/form-data)', required: true @@ -30,15 +30,14 @@ def show def create authorize(UserImage) - @user_image = UserImage.new(image: params[:image]) - @user_image.category = if user_image_params[:category].blank? - ActiveSupport::Deprecation.warn('Not setting an image category has been deprecated, please provide a "category" param.') # rubocop:disable Metrics/LineLength - @user_image.default_category - else - user_image_params[:category] - end + attributes = { + user: @user, + image: params[:image], + category: user_image_params[:category] + } + @user_image = UserImage.replace_image(**attributes) - if @user_image.save + if @user_image.valid? api_render(@user_image, status: :created) else api_render_errors(@user_image) diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index ab33e5575..b11a657d8 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -145,7 +145,7 @@ def create param :proficiency, UserLanguage::PROFICIENCY_RANGE.to_a, desc: 'Language proficiency' end param :company_id, Integer, desc: 'Company id for user' - param :user_image_one_time_token, String, desc: 'User image one time token' + param :user_image_one_time_token, String, desc: '_DEPRECATED_ User image one time token' param :current_status, User::STATUSES.keys, desc: 'Current status' param :at_und, User::AT_UND.keys, desc: 'AT-UND status' param :arrived_at, String, desc: 'Arrived at date' @@ -189,7 +189,35 @@ def destroy head :no_content end - api :GET, '/users/:id/matching_jobs', 'Show matching jobs for user' + api :POST, '/users/images/', 'User images' + description 'Creates a user image' + error code: 422, desc: 'Unprocessable entity' + param :image, File, desc: 'Image (multipart/form-data)', required: true + param :data, Hash, desc: 'Top level key', required: true do + param :attributes, Hash, desc: 'User image attributes', required: true do + param :category, UserImage::CATEGORIES.keys, desc: 'User image category', required: true # rubocop:disable Metrics/LineLength + end + end + example Doxxer.read_example(UserImage, method: :create) + def images + authorize(UserImage) + + @user_image = UserImage.new(image: params[:image]) + @user_image.category = if user_image_params[:category].blank? + ActiveSupport::Deprecation.warn('Not setting an image category has been deprecated, please provide a "category" param.') # rubocop:disable Metrics/LineLength + @user_image.default_category + else + user_image_params[:category] + end + + if @user_image.save + api_render(@user_image, status: :created) + else + api_render_errors(@user_image) + end + end + + api :GET, '/users/:id/matching-jobs', 'Show matching jobs for user' description 'Returns the matching jobs for user if the user is allowed.' error code: 401, desc: 'Unauthorized' error code: 404, desc: 'Not found' @@ -227,6 +255,10 @@ def set_user @user = User.find(params[:user_id]) end + def user_image_params + jsonapi_params.permit(:category) + end + def user_params whitelist = [ :first_name, :last_name, :email, :phone, :description, :job_experience, diff --git a/app/models/user_image.rb b/app/models/user_image.rb index 756c5b563..63146496b 100644 --- a/app/models/user_image.rb +++ b/app/models/user_image.rb @@ -35,6 +35,17 @@ class UserImage < ApplicationRecord # see https://github.com/rails/rails/issues/13971 enum category: CATEGORIES + def self.replace_image(user:, image:, category:) + new.tap do |user_image| + user_image.user = user + user_image.image = image + user_image.category = category + user_image.save + + find_by(user: user, category: category)&.destroy! if user_image.valid? + end + end + def self.find_by_one_time_tokens(tokens) valid_one_time_tokens.where(one_time_token: tokens) end diff --git a/app/policies/user_image_policy.rb b/app/policies/user_image_policy.rb index c57eb00eb..344b0e175 100644 --- a/app/policies/user_image_policy.rb +++ b/app/policies/user_image_policy.rb @@ -8,6 +8,10 @@ def create? true end + def images? + true + end + private def admin_or_self? diff --git a/config/routes.rb b/config/routes.rb index aaab70856..cdb9fd059 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -55,7 +55,7 @@ resources :user_skills, param: :user_skill_id, module: :users, path: :skills, only: [:index, :show, :create, :destroy] resources :user_languages, param: :user_language_id, module: :users, path: :languages, only: [:index, :show, :create, :destroy] resources :frilans_finans, path: 'frilans-finans', module: :users, only: [:create] - resources :user_images, module: :users, path: :images, only: [:show] + resources :user_images, module: :users, path: :images, only: [:show, :create] resources :ratings, module: :users, path: :ratings, only: [:index] end @@ -67,7 +67,8 @@ end resources :reset_password, path: 'reset-password', module: :users, only: [:create] resources :change_password, path: 'change-password', module: :users, only: [:create] - resources :user_images, module: :users, path: :images, only: [:create] + + post :images get :notifications get :statuses diff --git a/spec/controllers/users/user_images_controller_spec.rb b/spec/controllers/users/user_images_controller_spec.rb index 45893e587..56220ab97 100644 --- a/spec/controllers/users/user_images_controller_spec.rb +++ b/spec/controllers/users/user_images_controller_spec.rb @@ -3,9 +3,11 @@ RSpec.describe Api::V1::Users::UserImagesController, type: :controller do describe 'POST #create' do + let(:user) { FactoryGirl.create(:user) } let(:category) { UserImage::CATEGORIES.keys.last } - let(:valid_attributes) do + let(:valid_params) do { + user_id: user.to_param, image: TestImageFileReader.image, data: { attributes: { category: category } @@ -13,38 +15,37 @@ } end - let(:invalid_attributes) do - {} + let(:invalid_params) do + { user_id: user.to_param } end context 'with valid params' do it 'saves user image' do - post :create, params: valid_attributes + post :create, params: valid_params expect(assigns(:user_image)).to be_persisted end it 'returns 201 accepted status' do - post :create, params: valid_attributes + post :create, params: valid_params expect(response.status).to eq(201) end it 'assigns the user image category' do - post :create, params: valid_attributes + post :create, params: valid_params user_image = assigns(:user_image) expect(user_image.category).to eq(category.to_s) end - it 'assigns the default user image category if none given' do - attrs = valid_attributes.slice(:image) - post :create, params: attrs, headers: {} + it 'assigns the user image user' do + post :create, params: valid_params user_image = assigns(:user_image) - expect(user_image.category).to eq(user_image.default_category) + expect(user_image.user).to eq(user) end end context 'with invalid params' do it 'returns 422 accepted status' do - post :create, params: invalid_attributes + post :create, params: invalid_params expect(response.status).to eq(422) end end diff --git a/spec/controllers/users_controller_spec.rb b/spec/controllers/users_controller_spec.rb index 7b8956e16..91ebb75b6 100644 --- a/spec/controllers/users_controller_spec.rb +++ b/spec/controllers/users_controller_spec.rb @@ -356,6 +356,54 @@ end end + describe 'POST #images' do + let(:category) { UserImage::CATEGORIES.keys.last } + let(:valid_attributes) do + { + image: TestImageFileReader.image, + data: { + attributes: { category: category } + } + } + end + + let(:invalid_attributes) do + {} + end + + context 'with valid params' do + it 'saves user image' do + post :images, params: valid_attributes + expect(assigns(:user_image)).to be_persisted + end + + it 'returns 201 accepted status' do + post :images, params: valid_attributes + expect(response.status).to eq(201) + end + + it 'assigns the user image category' do + post :images, params: valid_attributes + user_image = assigns(:user_image) + expect(user_image.category).to eq(category.to_s) + end + + it 'assigns the default user image category if none given' do + attrs = valid_attributes.slice(:image) + post :images, params: attrs, headers: {} + user_image = assigns(:user_image) + expect(user_image.category).to eq(user_image.default_category) + end + end + + context 'with invalid params' do + it 'returns 422 accepted status' do + post :images, params: invalid_attributes + expect(response.status).to eq(422) + end + end + end + describe 'GET #matching_jobs' do it 'returns 200 status for admin user' do user = FactoryGirl.create(:user) diff --git a/spec/policies/user_image_policy_spec.rb b/spec/policies/user_image_policy_spec.rb index 1da2f30f9..c36789bc0 100644 --- a/spec/policies/user_image_policy_spec.rb +++ b/spec/policies/user_image_policy_spec.rb @@ -38,12 +38,46 @@ end end + permissions :images? do + context 'admin' do + let(:policy_context) { admin_user } + + it 'allows access' do + expect(policy.images?).to eq(true) + end + end + + context 'a user' do + let(:policy_context) { a_user } + + it 'allows access' do + expect(policy.images?).to eq(true) + end + end + + context 'current user' do + let(:policy_context) { user } + + it 'denies access' do + expect(policy.images?).to eq(true) + end + end + + context 'no user' do + let(:policy_context) { nil } + + it 'denies access' do + expect(policy.images?).to eq(true) + end + end + end + permissions :create? do context 'admin' do let(:policy_context) { admin_user } it 'allows access' do - expect(policy.show?).to eq(true) + expect(policy.create?).to eq(true) end end @@ -59,7 +93,7 @@ let(:policy_context) { user } it 'denies access' do - expect(policy.show?).to eq(true) + expect(policy.create?).to eq(true) end end diff --git a/spec/routing/users/user_images_routing_spec.rb b/spec/routing/users/user_images_routing_spec.rb index 0fcf2315a..993d6c294 100644 --- a/spec/routing/users/user_images_routing_spec.rb +++ b/spec/routing/users/user_images_routing_spec.rb @@ -4,9 +4,9 @@ RSpec.describe Api::V1::Users::UserImagesController, type: :routing do describe 'routing' do it 'routes to #create' do - path = '/api/v1/users/images' + path = '/api/v1/users/1/images' route_path = 'api/v1/users/user_images#create' - expect(post: path).to route_to(route_path) + expect(post: path).to route_to(route_path, user_id: '1') end it 'routes to #show' do diff --git a/spec/routing/users_routing_spec.rb b/spec/routing/users_routing_spec.rb index 806b693a6..f7b06dde8 100644 --- a/spec/routing/users_routing_spec.rb +++ b/spec/routing/users_routing_spec.rb @@ -33,6 +33,12 @@ expect(delete: path).to route_to('api/v1/users#destroy', user_id: '1') end + it 'routes to #images' do + path = '/api/v1/users/images' + route_path = 'api/v1/users#images' + expect(post: path).to route_to(route_path) + end + it 'routes to #matching_jobs' do path = '/api/v1/users/1/matching-jobs' expect(get: path).to route_to('api/v1/users#matching_jobs', user_id: '1')