def reschedule_job(job, schedule_event=None): """Regenerates the shifts associated with this job. If a schedule_event is passed then it will only regenerate overlapping shifts. """ if schedule_event: schedule_events = [schedule_event] else: schedule_events = db.query(ScheduleEvent).filter( or_(ScheduleEvent.schedule.in_([x.id for x in job.schedules]), ScheduleEvent.id.in_([x.id for x in job.schedule_events]))).all() if not schedule_event: # Completely regenerate this schedule. Drop and recreate everything. existing = db.query(Shift).filter(Shift.job == job.id).all() new = create_shift_schedule(job, schedule_events) for shift in existing: remove_shift(db, shift) db.flush() for shift in new: add_shift(db, shift) if schedule_event: # Find adjacent schedule events adjacent = [] starttime = schedule_event.starttime - datetime.timedelta( seconds=10) # Treat times within 10 seconds as being adjacent endtime = schedule_event.starttime + datetime.timedelta( seconds=schedule_event.duration + 10) # Calculate the endtime, and add 10 seconds of margin for event in schedule_events: if not event in adjacent: eventstart = event.starttime eventend = event.starttime + datetime.timedelta( seconds=event.duration) if eventstart <= starttime and eventend >= starttime: adjacent.append(event) elif eventstart >= starttime and eventstart <= endtime: adjacent.append(event) # Delete all adjacent schedule events for event in adjacent: shifts = db.query(Shift).filter( Shift.schedule_event == event.id).all() for shift in shifts: remove_shift(db, shift) db.flush() # Create new shifts for adjacent schedule events if request.method == "DELETE": adjacent.remove(schedule_event) new = create_shift_schedule(job, adjacent) for shift in new: add_shift(db, shift) shifts = db.query(Shift).filter(Shift.job == job.id).all() assignments = db.query(ShiftAssignment).all() return shifts
def crud_single(model, event=None, department=None, id=None): perms = model_permissions(model.__tablename__.lower()) if request.method == "GET": if READ_PERMS.intersection( perms['*']) or (id in perms and READ_PERMS.intersection(perms[id])): full = request.args.get("full", False, type=lambda x: x.lower() == 'true') instance = db.query(model).filter(model.id == id).one_or_none() return jsonify( model.serialize(instance, serialize_relationships=full)) raise PermissionDenied() elif request.method == "PATCH": if WRITE_PERMS.intersection( perms['*']) or (id in perms and WRITE_PERMS.intersection(perms[id])): g.data['id'] = id g.data = {k: v for k, v in g.data.items() if hasattr(model, k)} instance = model.deserialize(g.data) db.add(instance) if hasattr(instance, 'onchange_cb'): db.flush() for cb in instance.onchange_cb: cb(db, instance) db.commit() return jsonify(model.serialize(instance)) raise PermissionDenied() elif request.method == "DELETE": if WRITE_PERMS.intersection( perms['*']) or (id in perms and WRITE_PERMS.intersection(perms[id])): instance = db.query(model).filter(model.id == id).one_or_none() if not instance: return "", 404 instance_data = None if hasattr(instance, 'onchange_cb'): instance_data = model.serialize(instance, serialize_relationships=True) db.delete(instance) if hasattr(instance, 'onchange_cb'): db.flush() for cb in instance.onchange_cb: cb(db, instance, deleted=instance_data) db.commit() return "null" raise PermissionDenied() raise MethodNotAllowed()
def add_shift(db, shift): signups = db.query(ShiftSignup).filter( ShiftSignup.job == shift.job, ShiftSignup.starttime == shift.starttime, ShiftSignup.duration == shift.duration, ShiftSignup.shift == None).order_by(ShiftSignup.signuptime).all() for signup in signups: if shift.slots > shift.filledslots: db.add(shift) db.flush() signup.shift = shift.id db.add(signup) assignment = ShiftAssignment(badge=signup.badge, shift=shift.id, event=shift.event) db.add(assignment) shift.filledslots += 1 db.add(shift)
def initial_setup(): if User.query.first(): return "Initial setup has already completed.", 403 if request.json['username'] and request.json['email'] and request.json[ 'password']: user = User(username=request.json['username'], email=request.json['email'], password=sha256_crypt.hash(request.json['password']), active=True) role = Role(name="Server Admin", description="Allowed to do anything.") db.add(user) db.add(role) db.flush() perm = Permission(operation="*.*.*", role=role.id) grant = Grant(user=user.id, role=role.id) db.add(perm) db.add(grant) db.commit() return "null", 200 return "", 406
def create_attendee(uber_model, event, hotel_eligible=True): staff_badge_type = db.query(BadgeType).filter(BadgeType.name == "Staff", BadgeType.event == event).one_or_none() if not staff_badge_type: staff_badge_type = BadgeType(name="Staff", description="Experienced Volunteers") db.flush() badge = Badge( event=event, badge_type=staff_badge_type.id, printed_number=uber_model['badge_num'], printed_name=uber_model['badge_printed_name'], public_name=uber_model['full_name'], search_name=uber_model['full_name'].lower(), first_name=uber_model['first_name'], last_name=uber_model['last_name'], legal_name_matches=(not uber_model['legal_name']), emergency_contact_name=uber_model['ec_name'], emergency_contact_phone=uber_model['ec_phone'], phone=uber_model['cellphone'], email=uber_model['email'], uber_id=uber_model['id'] ) db.add(badge) db.flush() if hotel_eligible: hotel_request = HotelRoomRequest(event=event, badge=badge.id) db.add(hotel_request) db.flush() return badge
def run_staff_import(email, password, url, event): session = requests.Session() db.post(url + "/accounts/login", data={ "email": email, "password": password, "original_location": "homepage" }) attendees = get_uber_csv(session, "Attendee", url) num_staff = 0 print("Retrieved export") role = db.query(Role).filter(Role.name == "Default Staff").one_or_none() if not role: role = Role(name="Default Staff", description="Automatically assigned to staff.", event=event) db.add(role) db.flush() for perm in [ 'staff.search_names', 'hotel_request.create', 'event.read' ]: permission = Permission(operation=perm, role=role.id) db.add(permission) dh_role = db.query(Role).filter( Role.name == "Department Head").one_or_none() if not dh_role: dh_role = Role( name="Department Head", description="Automatically assigned to department heads.", event=event) db.add(dh_role) db.flush() for perm in ['department.write', 'hotel_request.approve']: permission = Permission(operation=perm, role=dh_role.id) db.add(permission) print("Adding attendees...") for attendee in attendees: if attendee['hotel_eligible'].lower() == "true": num_staff += 1 user = db.query(User).filter( User.password == attendee['id']).one_or_none() if not user: user = User(username=attendee['id'], email=attendee['id'], password=attendee['id'], active=False) db.add(user) db.flush() grant = db.query(Grant).filter( Grant.user == user.id, Grant.role == role.id).one_or_none() if not grant: grant = Grant(user=user.id, role=role.id) db.add(grant) badge = db.query(Badge).filter( Badge.event == event, Badge.uber_id == attendee['id']).one_or_none() if badge: badge.printed_number = attendee['badge_num'] badge.printed_name = attendee['badge_printed_name'] badge.search_name = "{} {}".format( attendee['first_name'].lower(), attendee['last_name'].lower()) badge.first_name = attendee['first_name'] badge.last_name = attendee['last_name'] badge.legal_name = attendee['legal_name'] badge.legal_name_matches = bool(attendee['legal_name']) badge.email = attendee['email'] badge.phone = attendee['cellphone'] db.add(badge) if not badge: badge = Badge(uber_id=attendee['id'], event=event, printed_number=attendee['badge_num'], printed_name=attendee['badge_printed_name'], search_name="{} {}".format( attendee['first_name'].lower(), attendee['last_name'].lower()), first_name=attendee['first_name'], last_name=attendee['last_name'], legal_name=attendee['legal_name'], legal_name_matches=bool(attendee['legal_name']), email=attendee['email'], phone=attendee['cellphone'], user_id=user.id) db.add(badge) print("Adding departments...") departments = get_uber_csv(session, "Department", url) for department in departments: current = db.query(Department).filter( Department.event == event, Department.uber_id == department['id']).one_or_none() if not current: dept = Department(uber_id=department['id'], name=department['name'], description=department['description'], event=event) db.add(dept) print("Adding staffers to departments...") deptmembers = get_uber_csv(session, "DeptMembership", url) for dm in deptmembers: badge = db.query(Badge).filter( Badge.event == event, Badge.uber_id == dm['attendee_id']).one_or_none() if not badge: print("Could not find badge {} to place in department {}.".format( dm['attendee_id'], dm['department_id'])) continue department = db.query(Department).filter( Department.event == event, Department.uber_id == dm['department_id']).one_or_none() if not department: print("Could not find department {} for attendee {}.".format( dm['department_id'], dm['attendee_id'])) continue existing = db.query(BadgeToDepartment).filter( BadgeToDepartment.badge == badge.id, BadgeToDepartment.department == department.id).one_or_none() if not existing: department_member = BadgeToDepartment(badge=badge.id, department=department.id) db.add(department_member) grant = db.query(Grant).filter( Grant.user == badge.user_id, Grant.role == dh_role.id, Grant.department == department.id).one_or_none() if (dm['is_dept_head'].lower() == "true") or (dm['is_checklist_admin'].lower() == "true"): if not grant: grant = Grant(user=badge.user_id, role=dh_role.id, department=department.id) db.add(grant) elif grant: db.delete(grant) print("Committing changes...") db.commit() print("Done.")
def import_mock(): if not 'event' in request.json: return "Event is a required parament.", 406 event = db.query(Event).filter( Event.id == request.json['event']).one_or_none() if not event: return "Could not locate event {}".format(escape( request.json['event'])), 404 badges = db.query(Badge).filter(Badge.event == event.id).all() if badges: return "You cannot generate mock data if there are already badges. Please delete the badges first if you really want junk data.", 412 staff_badge_type = db.query(BadgeType).filter( BadgeType.name == "Staff").one_or_none() if not staff_badge_type: staff_badge_type = BadgeType(name="Staff", description="Helps run the show") db.add(staff_badge_type) attendee_badge_type = db.query(BadgeType).filter( BadgeType.name == "Attendee").one_or_none() if not attendee_badge_type: attendee_badge_type = BadgeType(name="Attendee", description="Come to see the show") db.add(attendee_badge_type) db.flush() if 'attendees' in request.json: print("Generating {} attendees".format(request.json['attendees'])) for i in range(request.json['attendees']): if i % 1000 == 0: print(" ...{}/{}".format(i, request.json['attendees'])) first_name = names.get_first_name() last_name = names.get_last_name() legal_name = "{} {}".format(first_name, last_name) full_name = legal_name legal_name_matches = True printed_name = legal_name if random.random() > 0.95: legal_name = names.get_full_name() legal_name_matches = False if random.random() > 0.75: printed_name = names.get_last_name() provider = random.choice( ["verizon", "gmail", "yahoo", "aol", "magfest"]) site = random.choice(["net", "com", "org", "co.uk"]) email = "{}.{}@{}.{}".format(first_name, last_name, provider, site) badge = Badge( event=event.id, badge_type=attendee_badge_type.id, printed_number=(((i + request.json['staffers']) // 1000 + 1) * 1000) if 'staffers' in request.json else i, printed_name=printed_name, search_name=printed_name.lower(), first_name=first_name, last_name=last_name, legal_name=legal_name, legal_name_matches=legal_name_matches, email=email) db.add(badge) departments = [] if 'departments' in request.json: print("Generating {} departments...".format( request.json['departments'])) dept_names = {} while len(dept_names.keys()) < request.json['departments']: name = random.choice([ "Tech", "Staff", "Arcade", "Game", "Medical", "Hotel", "Cat", "Concert", "Music", "Security", "Food", "Rescue", "Warehouse", "Logistics", "Truck", "Management" ]) name += random.choice([ " Ops", " Management", " Wranglers", " Herders", "", " Chasers", " Fixers", " Breakers", " Managers", " Destroyers", " Cleaners" ]) name = ''.join( [x.upper() if random.random() < 0.05 else x for x in name]) dept_names[name] = None for name in dept_names.keys(): description = "The {} department.".format(name) department = Department(name=name, description=description, event=event.id) db.add(department) departments.append(department) staffers = [] if 'staffers' in request.json: print("Generating {} staffers...".format(request.json['staffers'])) for i in range(request.json['staffers']): if i % 1000 == 0: print(" ...{}/{}".format(i, request.json['staffers'])) first_name = names.get_first_name() last_name = names.get_last_name() legal_name = "{} {}".format(first_name, last_name) full_name = legal_name legal_name_matches = True printed_name = legal_name if random.random() > 0.95: legal_name = names.get_full_name() legal_name_matches = False if random.random() > 0.75: printed_name = names.get_last_name() provider = random.choice( ["verizon", "gmail", "yahoo", "aol", "magfest"]) site = random.choice(["net", "com", "org", "co.uk"]) email = "{}.{}@{}.{}".format(first_name, last_name, provider, site) badge = Badge(event=event.id, badge_type=staff_badge_type.id, printed_number=i, printed_name=printed_name, search_name=printed_name.lower(), first_name=first_name, last_name=last_name, legal_name=legal_name, legal_name_matches=legal_name_matches, email=email) db.add(badge) staffers.append(badge) print("Flushing database...") db.flush() print("Adding hotel information...") room_block = HotelRoomBlock(event=event.id, name="The staff block", description="") db.add(room_block) hotel_location = HotelLocation(name="The Really Big Hotel", address="123 Waterfront", event=event.id) db.add(hotel_location) room_nights = [] for i in ["Wednesday", "Thursday"]: room_night = HotelRoomNight(name=i, event=event.id, restricted=True, restriction_type="Setup", hidden=False) db.add(room_night) room_nights.append(room_night) for i in ["Friday", "Saturday", "Sunday"]: room_night = HotelRoomNight(name=i, event=event.id, restricted=False, restriction_type="Setup", hidden=False) db.add(room_night) room_nights.append(room_night) print("Flushing database...") db.flush() print("Adding staffers to departments...") requested_room = [] for staffer in staffers: staffer_depts = list(departments) hotel_requested = False declined = False preferred_department = None for i in range(int(random.random() / 0.3)): staffer_dept = random.choice(staffer_depts) staffer_depts.remove(staffer_dept) assignment = BadgeToDepartment(badge=staffer.id, department=staffer_dept.id) db.add(assignment) preferred_department = staffer_dept.id if random.random() > 0.3: hotel_requested = True if random.random() > 0.1: declined = True else: requested_room.append(staffer) hotel_request = HotelRoomRequest( badge=staffer.id, declined=declined, prefer_department=random.random() > 0.1, preferred_department=preferred_department, notes="Please give room.", prefer_single_gender=random.random() > 0.3, preferred_gender=random.choice(['male', 'female', 'other']), noise_level=random.choice([ 'Quiet - I am quiet, and prefer quiet.', "Moderate - I don't make a lot of noise.", "Loud - I'm ok if someone snores or I snore.", ]), smoke_sensitive=random.choice([True, False]), sleep_time=random.choice( ['2am-4am', '4am-6am', '6am-8am', '8am-10am']), ) db.add(hotel_request) print("Requesting Roommates...") requested_roommates = [] for staffer in requested_room: for i in room_nights: if random.random() > 0.2: req = RoomNightRequest(badge=staffer.id, requested=True, room_night=i.id) db.add(req) for i in range(random.randrange(0, 3)): other = random.choice(requested_room) if other == staffer: continue if random.random() > 0.2: if not (staffer.id, other.id) in requested_roommates: req = HotelRoommateRequest(requester=staffer.id, requested=other.id) requested_roommates.append((staffer.id, other.id)) db.add(req) if random.random() > 0.6: if not (other.id, staffer.id) in requested_roommates: req = HotelRoommateRequest(requester=other.id, requested=staffer.id) requested_roommates.append((other.id, staffer.id)) db.add(req) else: if not (staffer.id, other.id) in requested_roommates: req = HotelAntiRoommateRequest(requester=staffer.id, requested=other.id) requested_roommates.append((staffer.id, other.id)) db.add(req) if random.random() > 0.9: if not (other.id, staffer.id) in requested_roommates: req = HotelAntiRoommateRequest(requester=other.id, requested=staffer.id) requested_roommates.append((other.id, staffer.id)) db.add(req) print("Flushing db...") db.flush() print("Committing...") db.commit() print("Done!") return "null", 200
def staffer_auth(): if not User.query.first(): return "You must set up this server before using this method to log in.", 403 event = config.uber_event req = { "method": "attendee.search", "params": [ request.json['token'], "full" ] } results = requests.post(config.uber_api_url, headers=headers, json=req).json()['result'] if len(results) == 0: return "no result", 403 result = results[0] if not 'id' in result: return "no id", 403 uber_id = result['id'] if uber_id != request.json['token']: return "wrong token", 403 if result['badge_status_label'] == "Deferred": return "Badge is deferred", 403 badge = db.query(Badge).filter(Badge.uber_id == uber_id).one_or_none() hotel_request = None if badge: hotel_request = db.query(HotelRoomRequest).filter(HotelRoomRequest.badge == badge.id).one_or_none() if not hotel_request or not badge: req = {"method": "hotel.eligible_attendees"} eligible = requests.post(config.uber_api_url, headers=headers, json=req).json()['result'] if len(eligible) == 0: return "Failed to load eligible attendees", 403 if not uber_id in eligible: return "You are not eligible", 403 if not badge: staff_badge_type = db.query(BadgeType).filter(BadgeType.event == event, BadgeType.name == "Staff").one_or_none() if not staff_badge_type: staff_badge_type = BadgeType(name="Staff", description="Experienced Volunteers", event=event) db.flush() badge = Badge( event=event, badge_type=staff_badge_type.id, printed_number=result['badge_num'], printed_name=result['badge_printed_name'], public_name=result['full_name'], search_name=result['full_name'].lower(), first_name=result['first_name'], last_name=result['last_name'], legal_name_matches=(not result['legal_name']), emergency_contact_name=result['ec_name'], emergency_contact_phone=result['ec_phone'], phone=result['cellphone'], email=result['email'], uber_id=result['id'] ) req = { "method": "dept.list", "params": [] } uber_depts = requests.post(config.uber_api_url, headers=headers, json=req).json()['result'] uber_depts_names = {} for dept_id in uber_depts: uber_depts_names[uber_depts[dept_id]] = dept_id departments = db.query(Department).filter(Department.event == event).all() dept_names = {} for dept in departments: dept_names[dept.name] = dept for dept_name in result['assigned_depts_labels']: if not dept_name in dept_names and dept_name in uber_depts_names: new_dept = Department(uber_id=uber_depts_names[dept_name], event=event, name=dept_name) db.add(new_dept) badge.departments.append(new_dept) elif dept_name in dept_names: badge.departments.append(dept_names[dept_name]) db.add(badge) db.flush() if not hotel_request: hotel_request = HotelRoomRequest(event=event, badge=badge.id) db.add(hotel_request) db.flush() permissions = { "event": { str(event): [ "rooming.*.request", "badge.*.searchname", f"hotel_room_request.{hotel_request.id}.write", "hotel_room_block.*.read", "hotel_location.*.read", "hotel_room_night.*.read", ], "*": [ "event.*.read", f"badge.{badge.id}.read", "department.*.read" ] }, "department": {} } for department in badge.departments: req = { "method": "dept.members", "params": { "department_id": department.uber_id } } result = requests.post(config.uber_api_url, headers=headers, json=req).json() if 'error' in result: print(f"Could not locate {department.name} ({department.uber_id})") continue uber_dept_members = result['result'] for attendee in uber_dept_members['checklist_admins']: if attendee['id'] == badge.uber_id: if not str(event) in permissions["department"]: permissions["department"][str(event)] = {} permissions["department"][str(event)][str(department.id)] = [ f"department.*.checklist_admin", "hotel_request.*.approve" ] session = Session(badge=badge.id, secret=str(uuid.uuid4()), permissions=json.dumps(permissions), last_active=datetime.datetime.now()) db.add(session) db.commit() response = jsonify(session.secret) response.set_cookie('session', session.secret) return response
def crud_group(model, event=None, department=None): start = time.time() if request.method == "GET": count = request.args.get("count", False, type=lambda x: x.lower() == 'true') sort = request.args.get("sort", "") order = request.args.get("order", "asc") limit = request.args.get("limit", 0, type=int) offset = request.args.get("offset", 0, type=int) page = request.args.get("page", 0, type=int) search = request.args.get("search", "", type=str) search_field = request.args.get("search_field", "", type=str) search_mode = request.args.get("search_mode", "contains", type=str) search_case_sensitive = request.args.get( "search_case_sensitive", False, type=lambda x: x.lower() == 'true') full = request.args.get("full", False, type=lambda x: x.lower() == 'true') deep = request.args.get("deep", False, type=lambda x: x.lower() == 'true') if page: offset = page * 10 if limit: offset = page * limit filters = [] perms = model_permissions(model.__tablename__.lower()) if not READ_PERMS.intersection(perms['*']): ids = [ int(x) for x in perms.keys() if READ_PERMS.intersection(perms[x]) ] if not ids: raise PermissionDenied( f"User is not able to read any values in {model.__tablename__}" ) filters.append(model.id.in_(ids)) if event: filters.append(model.event == event) if department: filters.append(model.department == department) if search_field: if hasattr(model, search_field): columns, relationships = model.get_fields() relationships = {x.key: x for x in relationships} if search_field in relationships: search_model = getattr(model, search_field) model.get_modelclasses() rel_model = model.modelclasses[ relationships[search_field].target.name] search = [int(x) for x in search.split(",")] filters.append(search_model.any(rel_model.id.in_(search))) else: if search_case_sensitive: search_model = getattr(model, search_field) else: search_model = func.lower(getattr(model, search_field)) search = search.lower() if search_mode == "contains": filters.append( search_model.contains(search, autoescape=True)) elif search_mode == "startswith": filters.append( search_model.startswith(search, autoescape=True)) elif search_mode == "endswith": filters.append( search_model.endswith(search, autoescape=True)) elif search_mode == "equals": filters.append(search_model == search) elif search_mode == "notEquals": filters.append(search_model != search) for key, val in request.args.items(): if hasattr(model, key): filters.append(getattr(model, key) == val) rows = db.query(model).filter(*filters) if full: columns, relationships = model.get_fields() for relation in relationships: rows = rows.options(joinedload(relation.key)) if count: return json.dumps(rows.count()), 200 if hasattr(model, sort): if order == "asc": rows = rows.order_by(getattr(model, sort)) else: rows = rows.order_by(getattr(model, sort).desc()) if limit: rows = rows.offset(offset).limit(limit) elif offset: rows = rows.offset(offset).limit(10) rows = rows.all() now = time.time() print(f"{request.path} Load time {now - start}s") data = model.serialize(rows, serialize_relationships=full, deep=deep) print(f"{request.path} Serialize time {time.time() - now}s") return jsonify(data) elif request.method == "POST": if event: g.data['event'] = event if department: g.data['department'] = department instance = model.deserialize(g.data) db.add(instance) if hasattr(instance, 'onchange_cb'): db.flush() for cb in instance.onchange_cb: cb(db, instance) db.commit() return jsonify(model.serialize(instance)) raise MethodNotAllowed()