Skip to content

Commit

Permalink
add time off controller
Browse files Browse the repository at this point in the history
  • Loading branch information
kaiomagalhaes committed Mar 29, 2024
1 parent f17082a commit c72c902
Show file tree
Hide file tree
Showing 11 changed files with 230 additions and 6 deletions.
14 changes: 10 additions & 4 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
# This configuration was generated by
# `rubocop --auto-gen-config`
# on 2024-03-25 17:29:24 UTC using RuboCop version 1.56.2.
# on 2024-03-29 19:02:54 UTC using RuboCop version 1.56.2.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
# versions of RuboCop, may require this file to be generated again.

# Offense count: 7
# Offense count: 1
# Configuration parameters: AllowedParentClasses.
Lint/MissingSuper:
Exclude:
- 'app/services/time_off_creator.rb'

# Offense count: 8
# Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
Metrics/AbcSize:
Max: 34
Expand All @@ -25,9 +31,9 @@ Style/OptionalBooleanParameter:
- 'app/models/maintenance_contract_model.rb'
- 'app/utils/analytics/finances/models/financial_statements_of_work.rb'

# Offense count: 9
# Offense count: 8
# This cop supports safe autocorrection (--autocorrect).
# Configuration parameters: AllowHeredoc, AllowURI, URISchemes, IgnoreCopDirectives, AllowedPatterns.
# URISchemes: http, https
Layout/LineLength:
Max: 130
Max: 124
1 change: 0 additions & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

class ApplicationController < ActionController::API
before_action :set_default_response_format

before_action :authenticate
attr_reader :current_user

Expand Down
49 changes: 49 additions & 0 deletions app/controllers/time_offs_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# frozen_string_literal: true

class TimeOffsController < ApplicationController
skip_before_action :authenticate

def create
if text.blank? || start_datetime.nil? || end_datetime.nil?
render json: { message: 'Invalid parameters' }, status: :ok
return
end

time_off = TimeOffBuilder.call(text, start_datetime, end_datetime)
time_off&.save
success = time_off&.persisted?
msg = success ? { id: time_off&.id } : 'The time of request creation failed'

render json: msg, status: success ? :ok : :unprocessable_entity
rescue StandardError => e
logger.fatal "Error: TimeOffCreator: #{e.message}, Params: #{time_off_params}"

render json: { message: e.message }, status: :internal_server_error
end

def destroy
time_off = TimeOffBuilder.new(text, start_datetime, end_datetime).call
found_time_off = TimeOff.where(user: time_off.user, starts_at: time_off.starts_at, ends_at: time_off.ends_at).first
found_time_off&.destroy

render json: { message: 'Time off request deleted' }, status: :ok
end

private

def text
@text ||= time_off_params[:text]
end

def start_datetime
@start_datetime ||= time_off_params[:start_datetime]
end

def end_datetime
@end_datetime ||= time_off_params[:end_datetime]
end

def time_off_params
params.require(:webhook_time_off).permit(:text, :start_datetime, :end_datetime).to_h
end
end
3 changes: 2 additions & 1 deletion app/models/time_off_type.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class TimeOffType < ApplicationRecord
VACATION_TYPE = 'vacation'
SICK_LEAVE_TYPE = 'sick leave'
ERRAND_TYPE = 'errand'
UNPAID_LEAVE = 'unpaid leave'

validates :name, presence: true, inclusion: { in: [VACATION_TYPE, SICK_LEAVE_TYPE, ERRAND_TYPE] }
validates :name, presence: true, inclusion: { in: [VACATION_TYPE, SICK_LEAVE_TYPE, ERRAND_TYPE, UNPAID_LEAVE] }
end
59 changes: 59 additions & 0 deletions app/services/time_off_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# frozen_string_literal: true

class TimeOffBuilder < ApplicationService
def initialize(text, start_datetime, end_datetime)
@text = text
@start_datetime = start_datetime.to_time
@end_datetime = end_datetime.to_time
end

def call
return nil if invalid_params?

return raise("Many users with the same name. Users: #{users}") unless users.count.eql?(1)
return raise("No user found with the name #{user_name}") if users.count.eql?(0)

build_time_off(users.first)
end

def build_time_off(user)
TimeOff.new(
user:,
starts_at: @start_datetime,
ends_at: @end_datetime,
time_off_type:
)
end

private

def time_off_type
TimeOffType.find_or_create_by!(name: time_off_name)
end

def users
@users = User.by_name(user_name)
end

def invalid_params?
@text.blank? || (@start_datetime.nil? || @end_datetime.nil?)
end

def user_name
name_match = @text.match(/^([\w'-]+(?:\s+[\w'-]+)*)(?:\s+on|\s+is)/i)
name_match ? name_match[1] : @text
end

def time_off_name
case @text
when /.*Paid Time Off.*/
'vacation'
when /.*Unpaid Time Off.*/
'unpaid leave'
when /.*Errand.*/, /.*Out of Office.*/
'errand'
when /.*Sick.*/
'sick leave'
end
end
end
4 changes: 4 additions & 0 deletions app/views/time_offs/_time_off.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

json.extract! time_off, :id, :created_at, :updated_at
json.url time_off_url(time_off, format: :json)
3 changes: 3 additions & 0 deletions app/views/time_offs/index.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

json.array! @time_offs, partial: 'time_offs/time_off', as: :time_off
3 changes: 3 additions & 0 deletions app/views/time_offs/show.json.jbuilder
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# frozen_string_literal: true

json.partial! 'time_offs/time_off', time_off: @time_off
2 changes: 2 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
require 'sidekiq/cron/web'

Rails.application.routes.draw do
resources :time_offs, only: [:create]
post 'time_off/destroy', to: 'time_offs#destroy'
resources :time_entries
resources :payments
resources :assignments
Expand Down
7 changes: 7 additions & 0 deletions db/migrate/20240329180055_add_unaccent_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class AddUnaccentExtension < ActiveRecord::Migration[7.0]
def change
enable_extension 'unaccent'
end
end
91 changes: 91 additions & 0 deletions spec/controllers/time_offs_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe TimeOffsController, type: :controller do
render_views

let!(:user) { create(:user, first_name: 'Kaio', last_name: 'Magalhaes') }

def valid_params(text, _start_datetime = '2018-03-29T13:34:00', end_datetime = '2018-03-29T17:35:00')
{ webhook_time_off: {
text:,
start_datetime: end_datetime, end_datetime:
} }
end

before do
user
end

describe '#create' do
context 'with valid params' do
it 'creates a new TimeOff' do
post :create, params: valid_params('Kaio Costa Porto De Magalhães on Paid Time Off')
expect(response).to have_http_status(:ok)
end
end

context 'with a Paid Time Off request it' do
it "creates a time off with the 'paid time off' type" do
post :create, params: valid_params('Kaio Costa Porto De Magalhães on Paid Time Off')
time_of_id = response.parsed_body['id']
time_off = TimeOff.find(time_of_id)

expect(time_off.time_off_type.name).to eq('vacation')
end
end

context 'with an On Errands request it' do
it "creates a time off with the 'errands' type" do
post :create, params: valid_params('Kaio Costa Porto De Magalhães on Errands')
time_of_id = response.parsed_body['id']
time_off = TimeOff.find(time_of_id)

expect(time_off.time_off_type.name).to eq('errand')
end
end

context 'with a Sick Leave request it' do
it "creates a time off with the 'sick leave' type" do
post :create, params: valid_params('Kaio Costa Porto De Magalhães on Sick Leave')
time_of_id = response.parsed_body['id']
time_off = TimeOff.find(time_of_id)

expect(time_off.time_off_type.name).to eq('sick leave')
end
end

context 'with a start and end date difference of less than 4 hours' do
it 'creates a time off request' do
start_date = '2018-03-29T13:34:00'
end_date = '2018-03-29T14:35:00'
difference_in_hours = (Time.zone.parse(end_date) - Time.zone.parse(start_date)) / 3600

# confirm the difference in hours between the dates
expect(difference_in_hours).to be < 4

post :create,
params: valid_params('Kaio Costa Porto De Magalhães on Errands', end_date,
end_date)

expect(response).to have_http_status(:ok)
end
end
end

describe '#destroy' do
context 'with valid params' do
it 'finds and deletes the time off' do
create(:time_off_type)
# first creat the time off
post :create,
params: valid_params('Kaio Costa Porto De Magalhães on Paid Time Off')

expect do
delete :destroy, params: valid_params('Kaio Costa Porto De Magalhães on Paid Time Off')
end.to change(TimeOff, :count).by(-1)
end
end
end
end

0 comments on commit c72c902

Please sign in to comment.