diff --git a/apiary.apib b/apiary.apib index 5155068b..26c6a505 100644 --- a/apiary.apib +++ b/apiary.apib @@ -1713,16 +1713,39 @@ API endpoints that Operation Code's Rails backend makes available to its React f { errors: "Some error message" } -## User | Create [/api/v1/users{?first_name,last_name,email,zip,password,mentor}] +## User | Create [/api/v1/users{?first_name,last_name,email,zip,password,bio,verified,state,address1,address2,city,username,volunteer,branch_of_service,years_of_service,pay_grade,military_occupational_speciality,github,twitter,linked_in,mentor,employment_status,education,military_status,company_role,company_name,education_level,scholarship_info,interests}] + Parameters - + first_name (string, required) - First Name of the user in the form of an string - + last_name (string, required) - Last Name of the user in the form of an string + email (string, required) - Email of the User in the form of a string + zip (string, required) - Zipcode of the User in the form of a string + + first_name (string, required) - First Name of the user in the form of an string + + last_name (string, required) - Last Name of the user in the form of an string + + mentor (string, optional) - in the form of a string + password (string, required) - Password of the User in the form on a string - + mentor (boolean, optional) - Is User requesting mentor in the form of a boolean + + bio (string, optional) - in the form of a string + + verified (string, optional) - in the form of a string + + state (string, optional) - in the form of a string + + address1 (string, optional) - in the form of a string + + address2 (string, optional) - in the form of a string + + city (string, optional) - in the form of a string + + username (string, optional) - in the form of a string + + volunteer (string, optional) - in the form of a string + + branch_of_service (string, optional) - in the form of a string + + years_of_service (string, optional) - in the form of a string + + pay_grade (string, optional) - in the form of a string + + military_occupational_speciality (string, optional) - in the form of a string + + github (string, optional) - in the form of a string + + twitter (string, optional) - in the form of a string + + linked_in (string, optional) - in the form of a string + + employment_status (string, optional) - in the form of a string + + education (string, optional) - in the form of a string + + military_status (string, optional) - in the form of a string + + company_role (string, optional) - in the form of a string + + company_name (string, optional) - in the form of a string + + education_level (string, optional) - in the form of a string + + scholarship_info (boolean, optional) - in the form of a string + + interests (string, optional) - in the form of a string ### Create new user record [POST] @@ -1731,11 +1754,37 @@ API endpoints that Operation Code's Rails backend makes available to its React f + Body { - first_name: "Mike", - last_name: "Johnson", email: "dreams@operationcode.org", + password: "hunter2", zip: "80020", - mentor: "true" + first_name: "Mike", + last_name: "Johnson", + bio: "Information", + verified: false, + state: "NC", + address1: "My address", + address2: "PO BOX", + city: "My city", + username: "mike house" + volunteer: "false", + branch_of_service: "Air Force", + years_of_service: "100", + pay_grade: "0", + military_occupational_speciality: "3N", + github: "user_name", + twitter: "user_name", + linked_in: "user_name", + mentor: "true", + education_level: "College Graduate", + scholarship_info: "true", + employment_status: "Employed", + education: "BS", + military_status: "spouse", + company_role: "Developer", + company_name: "Comcast", + education_level: "BS", + scholarship_info: "True", + interests: "Python, Python, Python, Python" } @@ -1751,6 +1800,96 @@ API endpoints that Operation Code's Rails backend makes available to its React f errors: "Some error message" } +## User | Exists [/api/v1/users/email/{email}] + ++ Parameters + + + email (string, required) - User email in form of a string + +### Checks if a user currently exists [GET] + ++ Request (application/json) + ++ Response 200 (application/json) + + Body + + { + status: "ok" + } + ++ Response 422 (application/json) + + Body + + { + status: "Unprocessable Entity" + } + +## User | Me [/api/v1/users{?email}] + ++ Parameters + + + email (string, required) - Email of the User in the form of a string + +### Get full details for a specific user [GET] + ++ Request (application/json) + + + Headers + + Authorization: Bearer Access-Token + ++ Response 200 (application/json) + + + Body + + { + email: "dreams@operationcode.org", + zip: "80020", + first_name: "Mike", + last_name: "Johnson", + bio: "Information", + verified: false, + state: "NC", + address1: "My address", + address2: "PO BOX", + city: "My city", + username: "mike house" + volunteer: "false", + branch_of_service: "Air Force", + years_of_service: "100", + pay_grade: "0", + military_occupational_speciality: "3N", + github: "user_name", + twitter: "user_name", + linked_in: "user_name", + mentor: "true", + education_level: "College Graduate", + scholarship_info: "true", + employment_status: "Employed", + education: "BS", + military_status: "spouse", + company_role: "Developer", + company_name: "Comcast", + education_level: "BS", + scholarship_info: "True", + interests: "Python, Python, Python, Python" + } + ++ Response 422 (application/json) + + + Body + + { + status: "Unprocessable Entity" + } + ++ Response 404 (application/json) + + { + error: 'No such record' + } + + ## User | Reset Password [/api/v1/users/passwords/reset{?email}] + Parameters @@ -1798,20 +1937,39 @@ API endpoints that Operation Code's Rails backend makes available to its React f { errors: "Some error message" } -## User | Update [/api/v1/users{?education_level,mentor,scholarship_info,employment_status,company_name,company_role,volunteer,military_status,branch_of_service,interests}] +## User | Update [/api/v1/users{?first_name,last_name,email,zip,password,mentor,bio,verified,state,address1,address2,city,username,volunteer,branch_of_service,years_of_service,pay_grade,military_occupational_speciality,github,twitter,linked_in,employment_status,education,military_status,company_role,company_name,education_level,scholarship_info,interests}] + Parameters - + education_level (string, optional) - Users highest level of education in the form of a string + + first_name (string, required) - First Name of the user in the form of an string + + last_name (string, required) - Last Name of the user in the form of an string + + email (string, required) - Email of the User in the form of a string + + zip (string, required) - Zipcode of the User in the form of a string + + password (string, required) - Password of the User in the form on a string + mentor (boolean, optional) - Is User requesting mentor in the form of a boolean - + scholarship_info (boolean, optional) - Is User interested in scholarship info in the form of a boolean - + employment_status (string, optional) - Users employment status in the form of a string - + company_name (string, optional) - Users name of employer in the form on a string - + company_role (string, optional) - Users role at company in the form of a string - + volunteer (boolean, optional) - Is User wanting to volunteer in the form of a boolean - + military_status (string, optional) - Users military status, either current, veteran, spouse, or blank - + branch_of_service (string, optional) - Users branch of service in the form of a string - + interests (string, optional) - User interests in the form of a string. + + bio (string, optional) - in the form of a string + + verified (string, optional) - in the form of a string + + state (string, optional) - in the form of a string + + address1 (string, optional) - in the form of a string + + address2 (string, optional) - in the form of a string + + city (string, optional) - in the form of a string + + username (string, optional) - in the form of a string + + volunteer (string, optional) - in the form of a string + + branch_of_service (string, optional) - in the form of a string + + years_of_service (string, optional) - in the form of a string + + pay_grade (string, optional) - in the form of a string + + military_occupational_speciality (string, optional) - in the form of a string + + github (string, optional) - in the form of a string + + twitter (string, optional) - in the form of a string + + linked_in (string, optional) - in the form of a string + + employment_status (string, optional) - in the form of a string + + education (string, optional) - in the form of a string + + military_status (string, optional) - in the form of a string + + company_role (string, optional) - in the form of a string + + company_name (string, optional) - in the form of a string + + education_level (string, optional) - in the form of a string + + scholarship_info (boolean, optional) - in the form of a string + + interests (string, optional) - in the form of a string ### Update user record [PATCH] @@ -1824,15 +1982,36 @@ API endpoints that Operation Code's Rails backend makes available to its React f + Body { - education_level: "College Graduate" , + email: "dreams@operationcode.org", + password: "hunter2", + zip: "80020", + first_name: "Mike", + last_name: "Johnson", + bio: "Information", + verified: false, + state: "NC", + address1: "My address", + address2: "PO BOX", + city: "My city", + username: "mike house" + volunteer: "false", + branch_of_service: "Air Force", + years_of_service: "100", + pay_grade: "0", + military_occupational_speciality: "3N", + github: "user_name", + twitter: "user_name", + linked_in: "user_name", mentor: "true", + education_level: "College Graduate", scholarship_info: "true", employment_status: "Employed", - company_name: "Comcast", - company_role: "Developer", + education: "BS", military_status: "spouse", - volunteer: "false", - branch_of_service: "Air Force", + company_role: "Developer", + company_name: "Comcast", + education_level: "BS", + scholarship_info: "True", interests: "Python, Python, Python, Python" } diff --git a/app/controllers/api/v1/users_controller.rb b/app/controllers/api/v1/users_controller.rb index bf8994d5..6700f65d 100644 --- a/app/controllers/api/v1/users_controller.rb +++ b/app/controllers/api/v1/users_controller.rb @@ -1,7 +1,7 @@ module Api module V1 class UsersController < ApiController - before_action :authenticate_user!, only: %i[update] + before_action :authenticate_user!, only: %i[update me] def index render json: { user_count: User.count }, status: :ok @@ -13,7 +13,8 @@ def create user = User.new(user_params) if user.save - user.welcome_user + user.invite_to_slack + user.add_to_send_grid UserMailer.welcome(user).deliver unless user.invalid? sign_in(user) render json: { token: user.token } @@ -53,6 +54,25 @@ def by_location render json: { errors: e.message }, status: :unprocessable_entity end + def by_email + user = User.find_by(email: params[:email]) + if user + Rails.logger.debug "search by email successful #{request.env}" + render json: { status: :ok }, status: :ok + else + Rails.logger.debug "search by email not found from request: #{request.env}" + render json: { status: :not_found }, status: :not_found + end + end + + def me + # Rails.logger.debug "search by email for authed user email: #{current_user}" + render json: ComplexUserSerializer.new(current_user), status: :ok + rescue StandardError => e + Rails.logger.debug "search by email errored: #{current_user} error: #{e}" + render json: { status: :unprocessable_entity }, status: :unprocessable_entity + end + private def user_params @@ -68,6 +88,7 @@ def user_params :state, :address1, :address2, + :city, :username, :volunteer, :branch_of_service, @@ -84,7 +105,6 @@ def user_params :company_name, :education_level, :scholarship_info, - :role_id, interests: [] ) end diff --git a/app/jobs/add_user_to_send_grid_job.rb b/app/jobs/add_user_to_send_grid_job.rb index 44b1b2c5..59bdcc5c 100644 --- a/app/jobs/add_user_to_send_grid_job.rb +++ b/app/jobs/add_user_to_send_grid_job.rb @@ -3,6 +3,7 @@ class AddUserToSendGridJob < ApplicationJob def perform(user_id) user = User.find(user_id) + SendGridClient.new.add_user(user) end end diff --git a/app/lib/slack/client.rb b/app/lib/slack/client.rb index df5b258a..18396a04 100644 --- a/app/lib/slack/client.rb +++ b/app/lib/slack/client.rb @@ -23,7 +23,9 @@ def initialize(subdomain:, token:) end def invite(extra_message:, email:, channels: []) - Rails.logger.info "Inviting user with email '#{email}'" + # unsure if some string expansion is causing an error here + Rails.logger.info 'Inviting slack user user' + Rails.logger.info "Inviting slack user user with email #{email}" body = send_api_request( to: INVITE_PATH, payload: { @@ -40,6 +42,10 @@ def invite(extra_message:, email:, channels: []) end true + rescue StandardError => e + Rails.logger.warn "Some Exception occured while inviting slack user #{e}" + # want to reraise the exception so the job retries + raise end def post_message_to(channel:, with_text:) diff --git a/app/models/user.rb b/app/models/user.rb index 62e63c1a..2a476114 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -151,17 +151,16 @@ def name "#{first_name} #{last_name}" end - def welcome_user - add_to_send_grid - invite_to_slack - end - def invite_to_slack SlackJobs::InviterJob.perform_async(self.email) + rescue StandardError => e + Rails.logger.warn "Error occured when trying to add to job queue for slack invite #{e}" end def add_to_send_grid AddUserToSendGridJob.perform_async(self.id) + rescue StandardError => e + Rails.logger.warn "Error occured when trying to add to job queue for sendgrid #{e}" end def token diff --git a/app/serializers/complex_user_serializer.rb b/app/serializers/complex_user_serializer.rb new file mode 100644 index 00000000..80cc7583 --- /dev/null +++ b/app/serializers/complex_user_serializer.rb @@ -0,0 +1,30 @@ +class ComplexUserSerializer < ActiveModel::Serializer + attributes :email, + :zip, + :mentor, + :first_name, + :last_name, + :bio, + :verified, + :state, + :address1, + :address2, + :city, + :username, + :volunteer, + :branch_of_service, + :years_of_service, + :pay_grade, + :military_occupational_specialty, + :github, + :twitter, + :linked_in, + :employment_status, + :education, + :military_status, + :company_role, + :company_name, + :education_level, + :scholarship_info, + interests: [] +end diff --git a/config/routes.rb b/config/routes.rb index b60ac05a..14757df1 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -24,6 +24,7 @@ get '/status/protected', to: 'status#protected' get '/users/by_location', to: 'users#by_location' + get '/users/by_email', to: 'users#by_email' post '/users/profile/verify', to: 'users#verify' resources :code_schools do @@ -49,7 +50,7 @@ resources :team_members, only: [:index, :create, :update, :destroy] resources :users, only: [:index, :create] patch '/users', to: 'users#update' - + get '/users/me', to: 'users#me' devise_scope :user do post '/sessions', to: 'sessions#create' get '/sessions/sso', to: 'sessions#sso' diff --git a/test/controllers/api/v1/users_controller_test.rb b/test/controllers/api/v1/users_controller_test.rb index 55250125..a834df65 100644 --- a/test/controllers/api/v1/users_controller_test.rb +++ b/test/controllers/api/v1/users_controller_test.rb @@ -54,13 +54,53 @@ def valid_user_params assert valid_user_params[:zip], user.zip end - test '#create welcomes a new user' do - User.any_instance.expects(:welcome_user) + test '#create calls add_to_send_grid job queue addition' do + User.any_instance.expects(:add_to_send_grid) post api_v1_users_url, params: { user: valid_user_params }, as: :json end + test '#create calls invite_to_slack job queue addition' do + User.any_instance.expects(:invite_to_slack) + post api_v1_users_url, + params: { user: valid_user_params }, + as: :json + end + + test '#by_email returns success when user exists' do + tom = create(:user) + params = { email: tom.email } + get api_v1_users_by_email_path(params), as: :json + assert_equal({ 'status' => 'ok' }, response.parsed_body) + assert_equal 200, response.status + end + + test '#by_email returns failure user when doesn\'t exist' do + params = { email: 'fake_email@gmail.com' } + get api_v1_users_by_email_url(params), as: :json + assert_equal({ 'status' => 'not_found'}, response.parsed_body) + assert_equal 404, response.status + end + + # test '#me requires auth token to get valid response' do + # user_good = create(:user) + # user_bad = create(:user) + # headers_good = authorization_headers(user_good) + # headers_bad = authorization_headers(user_bad) + # user_good.valid? + # debugger user_good.errors.messages + # get api_v1_users_me_url, params: { email: user_bad.email }, headers: headers_good , as: :json + # assert_equal 422, response.status + # end + + # test '#me with valid auth token returns success' do + # user = create(:user) + # headers = authorization_headers(user) + # post api_v1_users_me_url, params: { email: user.email }, headers: headers, as: :json + # assert_equal 200, response.status + # end + test ':by_location returns User.count of users located in the passed in location' do tom = create :user sam = create :user diff --git a/test/models/user_test.rb b/test/models/user_test.rb index 7a47c614..330fb842 100644 --- a/test/models/user_test.rb +++ b/test/models/user_test.rb @@ -11,14 +11,14 @@ def teardown test 'welcoming a user adds them to SendGrid' do user = create(:user, user_opts) - user.welcome_user + user.add_to_send_grid assert_equal 1, AddUserToSendGridJob.jobs.length assert_equal [user.id], AddUserToSendGridJob.jobs.first['args'] end test 'welcoming a user adds them to SlackInvite' do user = create(:user, user_opts) - user.welcome_user + user.invite_to_slack assert_equal 1, SlackJobs::InviterJob.jobs.length assert_equal [user.email], SlackJobs::InviterJob.jobs.first['args'] end