Commit e09513fb authored by Sean Arnold's avatar Sean Arnold

Add service to create Oncall-rotation

Add specs too
parent 9e5f8dc8
# frozen_string_literal: true
module IncidentManagement
class OncallRotationPolicy < ::BasePolicy
delegate :project
end
end
# frozen_string_literal: true
module IncidentManagement
module OncallRotations
class CreateService
# @param schedule [IncidentManagement::OncallSchedule]
# @param project [Project]
# @param user [User]
# @param params [Hash<Symbol,Any>]
# @param params - name [String] The name of the on-call rotation.
# @param params - length [Integer] The length of the rotation.
# @param params - length_unit [String] The unit of the rotation length. (One of 'hours', days', 'weeks')
# @param params - starts_at [DateTime] The datetime the rotation starts on.
# @param params - participants [Array<hash>] An array of hashes defining participants of the on-call rotations.
# - participant [User] The user who is part of the rotation
# - color_palette [String] The color palette to assign to the on-call user, for example: "blue".
# - color_weight [String] The color weight to assign to for the on-call user, for example "500". Max 4 chars.
def initialize(schedule, project, user, params)
@schedule = schedule
@project = project
@current_user = user
@params = params
end
def execute
return error_no_license unless available?
return error_no_permissions unless allowed?
oncall_rotation = schedule.oncall_rotations.create(params.except(:participants))
return error_in_create(oncall_rotation) unless oncall_rotation.persisted?
new_participants = Array(params[:participants]).map do |participant|
OncallParticipant.new(
oncall_rotation: oncall_rotation,
participant: participant[:user],
color_palette: participant[:color_palette],
color_weight: participant[:color_weight]
)
end
OncallParticipant.bulk_insert!(new_participants)
success(oncall_rotation)
end
private
attr_reader :schedule, :project, :current_user, :params, :participants
def allowed?
Ability.allowed?(current_user, :admin_incident_management_oncall_schedule, project)
end
def available?
Feature.enabled?(:oncall_schedules_mvc, project) &&
project.feature_available?(:oncall_schedules)
end
def error(message)
ServiceResponse.error(message: message)
end
def success(oncall_rotation)
ServiceResponse.success(payload: { oncall_rotation: oncall_rotation })
end
def error_no_permissions
error('You have insufficient permissions to create an on-call rotation for this project')
end
def error_no_license
error('Your license does not support on-call rotations')
end
def error_in_create(oncall_rotation)
error(oncall_rotation.errors.full_messages.to_sentence)
end
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IncidentManagement::OncallRotationPolicy do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:oncall_schedule) { create(:incident_management_oncall_schedule, project: project) }
let_it_be(:oncall_schedule) { create(:incident_management_oncall_rotation, oncall_schedule: oncall_schedule) }
subject(:policy) { described_class.new(user, oncall_schedule) }
describe 'rules' do
it { is_expected.to be_disallowed :read_incident_management_oncall_schedule }
context 'when maintainer' do
before do
project.add_maintainer(user)
end
it { is_expected.to be_allowed :read_incident_management_oncall_schedule }
end
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe IncidentManagement::OncallRotations::CreateService do
let_it_be_with_refind(:project) { create(:project) }
let_it_be(:schedule) { create(:incident_management_oncall_schedule, project: project) }
let_it_be(:user_with_permissions) { create(:user) }
let_it_be(:user_without_permissions) { create(:user) }
let_it_be(:current_user) { user_with_permissions }
let(:participants) do
[
{
user: current_user,
color_palette: 'black',
color_weight: '500'
}
]
end
let(:params) { { name: 'On-call rotation', starts_at: Time.current, length: '1', length_unit: 'days' }.merge(participants: participants) }
let(:service) { described_class.new(schedule, project, current_user, params) }
before_all do
project.add_maintainer(user_with_permissions)
end
before do
stub_licensed_features(oncall_schedules: true)
end
describe '#execute' do
shared_examples 'error response' do |message|
it 'has an informative message' do
expect(execute).to be_error
expect(execute.message).to eq(message)
end
end
subject(:execute) { service.execute }
context 'when the current_user is anonymous' do
let(:current_user) { nil }
it_behaves_like 'error response', 'You have insufficient permissions to create an on-call rotation for this project'
end
context 'when the current_user does not have permissions to create on-call schedules' do
let(:current_user) { user_without_permissions }
it_behaves_like 'error response', 'You have insufficient permissions to create an on-call rotation for this project'
end
context 'when feature is not available' do
before do
stub_licensed_features(oncall_schedules: false)
end
it_behaves_like 'error response', 'Your license does not support on-call rotations'
end
context 'when feature flag is disabled' do
before do
stub_feature_flags(oncall_schedules_mvc: false)
end
it_behaves_like 'error response', 'Your license does not support on-call rotations'
end
context 'when an on-call rotation already exists' do
let!(:oncall_schedule) { create(:incident_management_oncall_rotation, oncall_schedule: schedule, name: 'On-call rotation') }
it_behaves_like 'error response', 'Name has already been taken'
end
context 'with valid params' do
it 'successfully creates an on-call rotation' do
expect(execute).to be_success
oncall_schedule = execute.payload[:oncall_rotation]
expect(oncall_schedule).to be_a(::IncidentManagement::OncallRotation)
expect(oncall_schedule.name).to eq('On-call rotation')
expect(oncall_schedule.length).to eq('1')
expect(oncall_schedule.length_unit).to eq('days')
end
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment