Skip to content

Commit

Permalink
Shifts (#47)
Browse files Browse the repository at this point in the history
* Adding shift models

* Updated tests

* Added shift tests

* Shift system implemented, still needs tests

* Added shift tests

* Sped up tests

* Added migration for shift db

* Adding docs

* Changed path to includes

* Rearranged
  • Loading branch information
bitbyt3r authored May 24, 2020
1 parent 08199c7 commit cec2441
Show file tree
Hide file tree
Showing 20 changed files with 1,764 additions and 92 deletions.
174 changes: 174 additions & 0 deletions backend/migrations/versions/7a98a0c9fb44_added_shift_management.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"""Added shift management
Revision ID: 7a98a0c9fb44
Revises: 4affc388b48b
Create Date: 2020-05-22 16:43:21.650563
"""
from alembic import op
import sqlalchemy as sa


# revision identifiers, used by Alembic.
revision = '7a98a0c9fb44'
down_revision = '4affc388b48b'
branch_labels = None
depends_on = None


def upgrade():
# ### commands auto generated by Alembic - please adjust! ###
op.create_table('schedule',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.Column('description', sa.String(), nullable=True),
sa.Column('event', sa.Integer(), nullable=True),
sa.Column('tags', sa.JSON(), nullable=True),
sa.ForeignKeyConstraint(['event'], ['event.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('job',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.Column('description', sa.String(), nullable=True),
sa.Column('event', sa.Integer(), nullable=True),
sa.Column('documentation', sa.String(), nullable=True),
sa.Column('department', sa.Integer(), nullable=True),
sa.Column('method', sa.JSON(), nullable=True),
sa.Column('signuprules', sa.JSON(), nullable=True),
sa.Column('sticky', sa.Boolean(), nullable=True),
sa.ForeignKeyConstraint(['department'], ['department.id'], ),
sa.ForeignKeyConstraint(['event'], ['event.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('schedule_event',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('name', sa.String(), nullable=True),
sa.Column('description', sa.String(), nullable=True),
sa.Column('starttime', sa.DateTime(), nullable=True),
sa.Column('duration', sa.Float(), nullable=True),
sa.Column('schedule', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['schedule'], ['schedule.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('job_role_association',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('job', sa.Integer(), nullable=True),
sa.Column('role', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['job'], ['job.id'], ),
sa.ForeignKeyConstraint(['role'], ['role.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('job_schedule_association',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('job', sa.Integer(), nullable=True),
sa.Column('schedule', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['job'], ['job.id'], ),
sa.ForeignKeyConstraint(['schedule'], ['schedule.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('job_schedule_event_association',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('job', sa.Integer(), nullable=True),
sa.Column('schedule_event', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['job'], ['job.id'], ),
sa.ForeignKeyConstraint(['schedule_event'], ['schedule_event.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('shift',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('job', sa.Integer(), nullable=True),
sa.Column('schedule', sa.Integer(), nullable=True),
sa.Column('schedule_event', sa.Integer(), nullable=True),
sa.Column('starttime', sa.DateTime(), nullable=True),
sa.Column('duration', sa.Float(), nullable=True),
sa.Column('slots', sa.Integer(), nullable=True),
sa.Column('filledslots', sa.Integer(), nullable=True),
sa.Column('weighting', sa.Float(), nullable=True),
sa.ForeignKeyConstraint(['job'], ['job.id'], ),
sa.ForeignKeyConstraint(['schedule'], ['schedule.id'], ),
sa.ForeignKeyConstraint(['schedule_event'], ['schedule_event.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('shift_assignment',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('badge', sa.Integer(), nullable=True),
sa.Column('shift', sa.Integer(), nullable=True),
sa.ForeignKeyConstraint(['badge'], ['badge.id'], ),
sa.ForeignKeyConstraint(['shift'], ['shift.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_table('shift_signup',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('badge', sa.Integer(), nullable=True),
sa.Column('job', sa.Integer(), nullable=True),
sa.Column('shift', sa.Integer(), nullable=True),
sa.Column('schedule', sa.Integer(), nullable=True),
sa.Column('schedule_event', sa.Integer(), nullable=True),
sa.Column('starttime', sa.DateTime(), nullable=True),
sa.Column('duration', sa.Float(), nullable=True),
sa.Column('signuptime', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['badge'], ['badge.id'], ),
sa.ForeignKeyConstraint(['job'], ['job.id'], ),
sa.ForeignKeyConstraint(['schedule'], ['schedule.id'], ),
sa.ForeignKeyConstraint(['schedule_event'], ['schedule_event.id'], ),
sa.ForeignKeyConstraint(['shift'], ['shift.id'], ),
sa.PrimaryKeyConstraint('id')
)
with op.batch_alter_table('badge', schema=None) as batch_op:
batch_op.alter_column('badge_type',
existing_type=sa.INTEGER(),
nullable=True,
existing_server_default=sa.text('1'))
batch_op.alter_column('email',
existing_type=sa.VARCHAR(length=128),
nullable=True)
batch_op.alter_column('first_name',
existing_type=sa.VARCHAR(length=128),
nullable=True)
batch_op.alter_column('last_name',
existing_type=sa.VARCHAR(length=128),
nullable=True)
batch_op.alter_column('printed_name',
existing_type=sa.VARCHAR(length=256),
nullable=True)
batch_op.alter_column('search_name',
existing_type=sa.VARCHAR(length=256),
nullable=True)

# ### end Alembic commands ###


def downgrade():
# ### commands auto generated by Alembic - please adjust! ###
with op.batch_alter_table('badge', schema=None) as batch_op:
batch_op.alter_column('search_name',
existing_type=sa.VARCHAR(length=256),
nullable=False)
batch_op.alter_column('printed_name',
existing_type=sa.VARCHAR(length=256),
nullable=False)
batch_op.alter_column('last_name',
existing_type=sa.VARCHAR(length=128),
nullable=False)
batch_op.alter_column('first_name',
existing_type=sa.VARCHAR(length=128),
nullable=False)
batch_op.alter_column('email',
existing_type=sa.VARCHAR(length=128),
nullable=False)
batch_op.alter_column('badge_type',
existing_type=sa.INTEGER(),
nullable=False,
existing_server_default=sa.text('1'))

op.drop_table('shift_signup')
op.drop_table('shift_assignment')
op.drop_table('shift')
op.drop_table('job_schedule_event_association')
op.drop_table('job_schedule_association')
op.drop_table('job_role_association')
op.drop_table('schedule_event')
op.drop_table('job')
op.drop_table('schedule')
# ### end Alembic commands ###
16 changes: 8 additions & 8 deletions backend/tests/test_hotel.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
def test_staffer_auth(mock_post, client):
"""Make sure the staffer login system is able to authenticate against uber"""
mock_post.return_value.json = lambda: {"result": [{"id": "123", "email": "test@test.com", "staffing": True}]}
rv = client.post('/api/uber_login', data=json.dumps({"token": "123"}), content_type="application/json")
token = csrf(rv)
assert(not json.loads(rv.data)['success'])
rv = client.post('/api/uber_login', json={"token": "123"})
print(rv.data)
assert(rv.is_json)
assert(not rv.json['success'])

rv = client.post('/api/uber_login', data=json.dumps({"token": "123", "csrf_token": token}), content_type="application/json")
assert(not json.loads(rv.data)['success'])
rv = client.post('/api/uber_login', json={"token": "123"})
assert(not rv.json['success'])

rv = client.post('/api/uber_login', data=json.dumps({"token": "abc", "csrf_token": token}), content_type="application/json")
assert(not json.loads(rv.data)['success'])
clear_table("user")
rv = client.post('/api/uber_login', json={"token": "abc"})
assert(not rv.json['success'])
162 changes: 162 additions & 0 deletions backend/tests/test_shifts.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
from util import *
import datetime
import json

def test_schedule_change(client):
"""Make sure that creating an scheduleevent on a schedule creates a shift on the associated job"""
schedule = client.post("/api/events/1/schedules", json={
"name": "Shift Schedule",
"description": "A schedule for shifts!"
}).json
assert(schedule['name'] == "Shift Schedule")

eventstart = datetime.datetime.utcnow()
scheduleevent = client.post("/api/scheduleevents", json={
"name": "The big panel",
"description": "You know the one",
"starttime": eventstart.isoformat(),
"duration": 3600,
"schedule": schedule['id']
}).json
assert(scheduleevent['name'] == "The big panel")

job = client.post("/api/events/1/jobs", json={
"name": "Do a thing",
"description": "Help make the thing happen, at the place",
"documentation": "Here's how to do the thing",
"method": {
"name": "copy",
"slots": 4
},
"schedules": [
schedule['id']
]
}).json
assert(job['name'] == "Do a thing")

shifts = client.get("/api/shifts", query_string={"full": True}).json
assert(len(shifts) == 1)
assert(shifts[0]['starttime'] == scheduleevent['starttime'])
assert(shifts[0]['duration'] == scheduleevent['duration'])
assert(shifts[0]['slots'] == 4)

newevent = client.post("/api/scheduleevents", json={
"name": "Another cool panel",
"description": "You probably don't know about this one yet",
"starttime": (eventstart + datetime.timedelta(seconds=3600)).isoformat(),
"duration": 3600,
"schedule": schedule['id']
}).json
assert(newevent['name'] == "Another cool panel")

shifts = client.get("/api/shifts", query_string={"full": True}).json
assert(len(shifts) == 2)

client.delete("/api/scheduleevents/"+str(scheduleevent['id']))

events = client.get("/api/scheduleevents", query_string={"full": True}).json
assert(len(events) == 1)

shifts = client.get("/api/shifts", query_string={"full": True}).json
assert(len(shifts) == 1)

def test_signup_persistence(client):
"""Make sure that a signup survives a shift being deleted and coming back"""
schedule = client.post("/api/events/1/schedules", json={
"name": "Shift Schedule",
"description": "A schedule for shifts!"
}).json
assert(schedule['name'] == "Shift Schedule")

eventstart = datetime.datetime.utcnow()
scheduleevent = client.post("/api/scheduleevents", json={
"name": "The big panel",
"description": "You know the one",
"starttime": eventstart.isoformat(),
"duration": 3600,
"schedule": schedule['id']
}).json
assert(scheduleevent['name'] == "The big panel")

department = client.post("/api/events/1/departments", json={
"name": "Product Testing"
}).json
assert(department['name'] == "Product Testing")

role = client.post("/api/roles", json={
"name": "Manager",
"description": "Allowed to sign up for manager shifts",
"event": 1
}).json
assert(role['name'] == "Manager")

user = client.post("/api/users", json={
"username": "testing",
"email": "test@test.com",
"active": True
}).json
assert(user['username'] == "testing")

grant = client.post("/api/grants", json={
"user": user['id'],
"role": role['id'],
"department": department['id']
}).json
assert(grant['user'] == user['id'])

job = client.post("/api/events/1/jobs", json={
"name": "Do a thing",
"description": "Help make the thing happen, at the place",
"documentation": "Here's how to do the thing",
"method": {
"name": "copy",
"slots": 4
},
"schedules": [
schedule['id']
],
"roles": [
role['id']
],
"department": department['id']
}).json
assert(job['name'] == "Do a thing")
assert(job['department'] == department['id'])

badge = client.post("/api/events/1/badges", json={
"legal_name": "Test User",
"user": user['id'],
"departments": [
department['id']
]
}).json
assert(badge['legal_name'] == "Test User")

jobs = client.get("/api/events/1/jobs/available", query_string={"badge": badge['id']}).json
assert(len(jobs) == 1)
assert(len(jobs[0]['shifts']) == 1)

signup = client.post("/api/events/1/shifts/"+str(jobs[0]['shifts'][0]['id'])+"/signup", json={
"badge": badge['id']
}).json
assert(signup['shift'])

assignedshifts = client.get("/api/shiftassignments", query_string={"badge": badge['id']}).json
assert(len(assignedshifts) == 1)

client.delete("/api/scheduleevents/"+str(scheduleevent['id']))

assignedshifts = client.get("/api/shiftassignments", query_string={"badge": badge['id']}).json
assert(len(assignedshifts) == 0)

replacement_scheduleevent = client.post("/api/scheduleevents", json={
"name": "A similar large panel",
"description": "It starts the same time as the old one, and is just as long!",
"starttime": eventstart.isoformat(),
"duration": 3600,
"schedule": schedule['id']
}).json
assert(replacement_scheduleevent['name'] == "A similar large panel")

assignedshifts = client.get("/api/shiftassignments", query_string={"badge": badge['id']}).json
assert(len(assignedshifts) == 1)
Loading

0 comments on commit cec2441

Please sign in to comment.