Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add daily-round-robin scheduler algorithm #259

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions db/schema.v0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ CREATE TABLE IF NOT EXISTS `contact_mode` (
-- Initialize contact modes
-- -----------------------------------------------------
INSERT INTO `contact_mode` (`name`)
VALUES ('email'), ('sms'), ('call'), ('slack'), ('teams_messenger');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is teams_messenger being deleted?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its removed as teams_messenger is not a basic mode of contact in oncall.
Else it can be added any time in the contact_mode table to make it accessible in the UI.

VALUES ('email'), ('sms'), ('call'), ('slack');

-- -----------------------------------------------------
-- Table `user_contact`
Expand Down Expand Up @@ -464,8 +464,10 @@ VALUES ('default',
'Default scheduling algorithm'),
('round-robin',
'Round robin in roster order; does not respect vacations/conflicts'),
('no-skip-matching',
'Default scheduling algorithm; doesn\'t skips creating events if matching events already exist on the calendar');
('no-skip-matching',
'Default scheduling algorithm; doesn\'t skips creating events if matching events already exist on the calendar'),
('daily-round-robin',
'Follows roster order of round-robin, but divides week long shifts into day long shifts among different users');

-- -----------------------------------------------------
-- Initialize notification types
Expand Down
39 changes: 37 additions & 2 deletions src/oncall/api/v0/roster_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
from ...utils import load_json_body, unsubscribe_notifications, create_audit
from ... import db
from ...constants import ROSTER_USER_DELETED, ROSTER_USER_EDITED

import logging
logger = logging.getLogger()

@login_required
def on_delete(req, resp, team, roster, user):
Expand Down Expand Up @@ -44,15 +45,49 @@ def on_delete(req, resp, team, roster, user):
roster_id = cursor.fetchone()
if roster_id is None:
raise HTTPNotFound()

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This logic can be handled by the scheduler. In particular, the round-robin scheduler uses the calendar to guess the previous user if one has been deleted, so we don't need to do any schedule management in a roster_user action.

cursor.execute('''SELECT `user_id` FROM `roster_user`
WHERE `roster_id` = %s''',
roster_id)
user_ids = [r[0] for r in cursor]
cursor.execute('''SELECT `id` FROM `user`
WHERE `name` = %s''',
user)
user_id = [r[0] for r in cursor]
cursor.execute('''SELECT `id` FROM `schedule`
WHERE `roster_id` = %s AND `last_scheduled_user_id`=%s ''',
(roster_id,user_id[0]))
schedule_id = [r[0] for r in cursor]
last_scheduled_user_id=None
if(schedule_id):
cursor.execute('''SELECT `last_scheduled_user_id` FROM `schedule`
WHERE `roster_id` = %s AND `id`=%s ''',
(roster_id,schedule_id[0]))
last_scheduled_user_id = [r[0] for r in cursor]

if(last_scheduled_user_id):
if(last_scheduled_user_id[0]==user_id[0]):
user_index=user_ids.index(user_id[0])
last_scheduled_user=0

if(user_index==0):
last_scheduled_user=user_ids[len(user_ids)-1]
else:
last_scheduled_user=user_ids[user_index-1]
for ids in schedule_id:
cursor.execute('UPDATE `schedule` SET `last_scheduled_user_id` = %s WHERE `id` = %s', (last_scheduled_user, ids))

cursor.execute('''DELETE FROM `roster_user`
WHERE `roster_id`= %s
AND `user_id`=(SELECT `id` FROM `user` WHERE `name`=%s)''',
(roster_id, user))

cursor.execute('''DELETE `schedule_order` FROM `schedule_order`
JOIN `schedule` ON `schedule`.`id` = `schedule_order`.`schedule_id`
WHERE `roster_id` = %s
AND user_id = (SELECT `id` FROM `user` WHERE `name` = %s)''',
(roster_id, user))

create_audit({'roster': roster, 'user': user}, team, ROSTER_USER_DELETED, req, cursor)

# Remove user from the team if needed
Expand Down Expand Up @@ -130,4 +165,4 @@ def on_put(req, resp, team, roster, user):
cursor.close()
connection.close()
resp.status = HTTP_200
resp.body = '[]'
resp.body = '[]'
Loading