Exemplo n.º 1
0
def add_roommates(event, hotel_block, room_id):
    if not check_permission(f'hotel_block.{hotel_block}.write', event=event):
        return "", 403
    reqs = db.query(HotelRoomRequest).filter(HotelRoomRequest.event==event, HotelRoomRequest.badge.in_(g.data['roommates'])).all()
    room_nights = db.query(HotelRoomNight).filter(HotelRoomNight.event==event).all()
    room_nights = {x.id: x for x in room_nights}
    for req in reqs:
        for night in req.room_night_requests:
            assign = False
            if night.requested:
                if room_nights[night.room_night].restricted:
                    for approval in req.room_night_approvals:
                        if approval.room_night == night.room_night and approval.approved:
                            assign = True
                            break
                else:
                    assign = True
            for assignment in req.room_night_assignments:
                if assignment.room_night == night.room_night:
                    assign = False
                    break
            if assign:
                db.add(RoomNightAssignment(event=event, badge=req.badge, room_night=night.room_night, hotel_room=room_id))
    update_room_request_props(db, reqs, assigned=True)
    for req in reqs:
        db.add(req)
    db.commit()
    return "null", 200 
Exemplo n.º 2
0
 def _store_response(self, job_id, iterable):
     with self.lock:
         if self.context[job_id]['state'] == "pending":
             self.context[job_id]['state'] = "immediate"
             return
     request_context = json.dumps({
         "status":
         self.context[job_id]['status'],
         "response_headers":
         self.context[job_id]['response_headers']
     })
     del self.context[job_id]
     progress = json.dumps({
         "complete": True,
         "amount": 0,
         "messages": "",
         "status": ""
     })
     if r:
         r.set(f"{job_id}/context", request_context)
         for data in iterable:
             r.append(f"{job_id}/data", data)
         r.set(f"{job_id}/progress", progress)
     else:
         data = bytes()
         for chunk in iterable:
             data = data + chunk
         with self.lock:
             job = db.query(BackgroundJob).filter(
                 BackgroundJob.uuid == job_id).one()
             job.progress = progress
             job.result = data
             job.context = request_context
             db.add(job)
             db.commit()
Exemplo n.º 3
0
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
Exemplo n.º 4
0
def flush_session_perms(user_id=None):
    if user_id:
        sessions = db.query(Session).filter(Session.user == user_id).all()
    else:
        sessions = db.query(Session).all()
    for session in sessions:
        perms = get_permissions(user_id=session.user)
        session.permissions=json.dumps(perms)
        db.add(session)
    db.commit()
Exemplo n.º 5
0
def remove_roommates(event, hotel_block, room_id):
    if not check_permission(f'hotel_block.{hotel_block}.write', event=event):
        return "", 403
    db.query(RoomNightAssignment).filter(RoomNightAssignment.event==event, RoomNightAssignment.hotel_room==room_id, RoomNightAssignment.badge.in_(g.data['roommates'])).delete()
    reqs = db.query(HotelRoomRequest).filter(HotelRoomRequest.event==event, HotelRoomRequest.badge.in_(g.data['roommates'])).all()
    update_room_request_props(db, reqs, assigned=False)
    for req in reqs:
        db.add(req)
    db.commit()
    return "null", 200
Exemplo n.º 6
0
def remove_shift(db, shift):
    signups = db.query(ShiftSignup).filter(
        ShiftSignup.shift == shift.id).order_by(
            ShiftSignup.signuptime.desc()).all()
    for signup in signups:
        signup.shift = None
        db.add(signup)
    db.query(ShiftAssignment).filter(
        ShiftAssignment.shift == shift.id).delete()
    db.delete(shift)
Exemplo n.º 7
0
def shiftassignmentchange(db, shiftassignment):
    if request.method == "POST":
        shift = db.query(Shift).filter(Shift.id == shiftassignment.shift).one()
        shift.filledslots += 1
        if shift.filledslots > shift.slots:
            return "Too many badges assigned to shift.", 412
        db.add(shift)
    elif request.method == "DELETE":
        shift = db.query(Shift).filter(
            Shift.id == shiftassignmentchange.shift).one()
        shift.filledslots = max(0, shift.filledslots - 1)
        db.add(shift)
Exemplo n.º 8
0
def clear_broken_signups(db, shift):
    signups = db.query(ShiftSignup).filter(
        ShiftSignup.shift == shift.id).order_by(
            ShiftSignup.signuptime.desc()).all()
    for signup in signups:
        if signup.starttime != shift.starttime or signup.duration != shift.duration or signup.job != shift.job or shift.filledslots > shift.slots:
            signup.shift = None
            db.query(ShiftAssignment).filter(
                ShiftAssignment.shift == shift.id).delete()
            db.add(signup)
            shift.filledslots = max(0, shift.filledslots - 1)
    db.add(shift)
Exemplo n.º 9
0
def change_password(user_id):
    if not check_permission(f"user.{user_id}.change_password"
                            ) and not check_permission(f"user.{user_id}.self"):
        return "", 403
    user = db.query(User).filter(User.id == user_id).one()
    if not 'password' in g.data:
        return "You must provide a password", 406
    if len(g.data['password']) < 8:
        return "Your password must be at least 8 characters.", 406
    user.password = sha256_crypt.hash(g.data['password'])
    db.add(user)
    db.commit()
    return "null", 200
Exemplo n.º 10
0
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()
Exemplo n.º 11
0
def update_room_request(db, instance, deleted=None):
    reqs = []
    if request.method == "DELETE" and type(instance) is HotelRoom:
        print(f"Deleting hotel room {deleted['name']}")
        print(deleted)
        reqs = db.query(HotelRoomRequest).filter(HotelRoomRequest.badge.in_(deleted['roommates'])).all()
    elif type(instance) is RoomNightRequest or type(instance) is RoomNightAssignment or type(instance) is RoomNightApproval:
        reqs = db.query(HotelRoomRequest).filter(HotelRoomRequest.badge == instance.badge).all()
    elif type(instance) is HotelRoomRequest:
        reqs = [instance]
    elif type(instance) is HotelRoomNight:
        reqs = db.query(HotelRoomRequest).filter(HotelRoomRequest.event == instance.event).options(joinedload('room_night_requests')).options(joinedload('room_night_approvals')).options(joinedload('room_night_assignments')).all()
    update_room_request_props(db, reqs)
    if not type(instance) is HotelRoomRequest:
        for req in reqs:
            db.add(req)
Exemplo n.º 12
0
def schedulechange(db, schedule):
    if request.method == "DELETE":
        shifts = db.query(Shift).filter(Shift.schedule == schedule.id).all()
        list(map(db.delete, shifts))
        jobs = db.query(Job).filter(
            Job.schedules.any(Schedule.id == schedule.id)).all()
        for job in jobs:
            job.schedules.remove(schedule.id)
            db.add(job)
        shiftassignments = db.query(ShiftAssignment).filter(
            ShiftAssignment.shift.in_([x.id for x in shifts])).all()
        list(map(db.delete, shiftassignments))
        shiftsignups = db.query(ShiftSignup).filter(
            ShiftSignup.schedule == schedule.id).all()
        for signup in shiftsignups:
            signup.schedule = None
            db.add(signup)
Exemplo n.º 13
0
def hotel_approve(event, department):
    if check_permission("hotel_request.*.approve", event=event, department=department):
        room_night_request = db.query(RoomNightRequest).filter(RoomNightRequest.room_night == request.json['room_night'], RoomNightRequest.badge == request.json['badge']).one_or_none()
        if not room_night_request:
            return "Could not find corresponding request.", 404
        approval = db.query(RoomNightApproval).filter(RoomNightApproval.badge == request.json['badge'], RoomNightApproval.room_night == request.json['room_night'], RoomNightApproval.department == department).one_or_none()
        if request.json['approved'] is None:
            if approval:
                db.delete(approval)
        else:
            if not approval:
                approval = RoomNightApproval(event=event, badge=request.json['badge'], department=department)
            approval.approved = request.json['approved']
            approval.room_night = request.json['room_night']
            db.add(approval)
        hotel_room_request = db.query(HotelRoomRequest).filter(HotelRoomRequest.badge == room_night_request.badge).one()
        update_room_request_props(db, [hotel_room_request,])
        db.add(room_night_request)
        db.commit()
        return "null", 200
    return "", 403
Exemplo n.º 14
0
def shift_signup(event, shift):
    if 'badge' in request.json:
        badge = db.query(Badge).filter(Badge.id == request.json['badge']).one()
    elif g.badge:
        badge = g.badge
    else:
        return "The current user does not have a badge, and thus cannot sign up for shifts.", 412
    shift = db.query(Shift).filter(Shift.id == shift).one()
    if shift.filledslots >= shift.slots:
        return "The shift is full.", 412
    shift.filledslots += 1
    assignment = ShiftAssignment(shift=shift.id, badge=badge.id, event=event)
    signup = ShiftSignup(badge=badge.id,
                         shift=shift.id,
                         job=shift.job,
                         schedule=shift.schedule,
                         schedule_event=shift.schedule_event,
                         starttime=shift.starttime,
                         duration=shift.duration)
    db.add(shift)
    db.add(assignment)
    db.add(signup)
    db.commit()
    return jsonify(shift=Shift.serialize(shift),
                   shift_assignment=ShiftAssignment.serialize(assignment),
                   shift_signup=ShiftSignup.serialize(signup))
Exemplo n.º 15
0
def login():
    if request.json['username'] and request.json['password']:
        user = db.query(User).filter(
            User.username == request.json['username']).one_or_none()
        if user:
            if sha256_crypt.verify(request.json['password'], user.password):
                badges = db.query(Badge).filter(Badge.user == user.id).all()
                badge = None
                if badges:
                    badge = badges[0].id
                perm_cache = get_permissions(user=user.id)
                session = Session(user=user.id,
                                  badge=badge,
                                  last_active=datetime.datetime.now(),
                                  secret=str(uuid.uuid4()),
                                  permissions=json.dumps(perm_cache))
                db.add(session)
                db.commit()
                response = jsonify(session.secret)
                response.set_cookie('session', session.secret)
                return response
    return "", 406
Exemplo n.º 16
0
 def progress(self, amount, status=""):
     job_id = request.environ.get("TUBER_JOB_ID", "")
     if not job_id:
         return
     with self.lock:
         if r:
             progress = json.loads(r.get(f"{job_id}/progress"))
             progress['amount'] = amount
             if status:
                 progress['status'] = status
                 progress['messages'] += status + "\n"
             r.set(f"{job_id}/progress", json.dumps(progress))
         else:
             job = db.query(BackgroundJob).filter(
                 BackgroundJob.uuid == job_id).one()
             progress = json.loads(job.progress)
             progress['amount'] = amount
             if status:
                 progress['status'] = status
                 progress['messages'] += status + "\n"
             job.progress = json.dumps(progress)
             db.add(job)
             db.commit()
Exemplo n.º 17
0
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)
Exemplo n.º 18
0
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
Exemplo n.º 19
0
def csv_import():
    if request.method == "GET":
        if not check_permission("export.*.csv"):
            return "Permission Denied", 403
        export_type = request.args['csv_type']
        model = globals()[export_type]
        data = db.query(model).all()
        cols = model.__table__.columns.keys()

        def generate():
            yield ','.join(cols) + "\n"
            for row in data:
                yield ','.join([str(getattr(row, x)) for x in cols]) + "\n"

        response = Response(generate(), mimetype="text/csv")
        response.headers.set('Content-Disposition',
                             'attachment; filename={}.csv'.format(export_type))
        return response
    elif request.method == "POST":
        if not check_permission("import.*.csv"):
            return "Permission Denied", 403
        import_type = request.form['csv_type']
        model = globals()[import_type]
        raw_import = request.form['raw_import'].lower().strip() == "true"
        full_import = request.form['full_import'].lower().strip() == "true"
        file = request.files['files']
        data = file.read().decode('UTF-8').replace("\r\n", "\n")
        if full_import:
            db.query(model).delete()
        rows = data.split("\n")
        cols = rows[0].split(",")
        rows = rows[1:]

        def convert(key, val):
            col = model.__table__.columns[key]
            if col.nullable:
                if val == 'None':
                    return None
            coltype = type(col.type)
            if coltype is sqlalchemy.sql.sqltypes.Integer:
                if val == '':
                    return None
                return int(val)
            if coltype is sqlalchemy.sql.sqltypes.Boolean:
                if val.lower() == "true":
                    return True
                return False
            return val

        count = 0
        for row in rows:
            if not row.strip():
                continue
            row = row.split(",")
            new = model(
                **{key: convert(key, val)
                   for key, val in zip(cols, row)})
            db.add(new)
            count += 1
        db.commit()
        return str(count), 200
Exemplo n.º 20
0
def department_sync():
    if not check_permission("department.*.sync"):
        return "", 403
    event = config.uber_event
    req = {"method": "hotel.eligible_attendees"}
    eligible = requests.post(config.uber_api_url, headers=headers, json=req).json()['result']
    req = {"method": "dept.list"}
    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

    badges = db.query(Badge).filter(Badge.event == event).options(joinedload('departments')).all()
    badgelookup = {badge.uber_id: badge for badge in badges}

    for attendee in eligible:
        req = {
            "method": "attendee.search",
            "params": [
                attendee,
                "full"
            ]
        }
        uber_model = requests.post(config.uber_api_url, headers=headers, json=req).json()['result'][0]
        if attendee in badgelookup:
            badge = badgelookup[attendee]
            if uber_model['full_name'] != badge.public_name:
                print(f"Updating public name from {badge.public_name} to {uber_model['full_name']}")
                badge.first_name = uber_model['first_name']
                badge.last_name = uber_model['last_name']
                badge.public_name = uber_model['full_name']
                db.add(badge)
        if uber_model['badge_status_label'] == "Deferred":
            if attendee in badgelookup:
                print(f"Deleting deferred attendee {attendee} ({badgelookup[attendee].public_name})")
                rnrs = badgelookup[attendee].room_night_requests
                if any([x.requested for x in rnrs]):
                    print("WARNING: ATTENDEE REQUESTED ROOM NIGHTS")
                #db.delete(badgelookup[attendee])
        else:
            if not attendee in badgelookup:
                print(f"Missing attendee: {attendee}")
                new_badge = create_attendee(uber_model, event)
                badgelookup[attendee] = new_badge

            badge = badgelookup[attendee]
            for dept_name in uber_model['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)
                    dept_names[dept_name] = new_dept
                    print(f"Creating department {dept_name}")
                    db.add(new_dept)
                if not dept_names[dept_name] in badge.departments:
                    badge.departments.append(dept_names[dept_name])
                    print(f"Adding {badge.public_name} to {dept_name}")

            to_remove = []
            for dept in badge.departments:
                if not dept.name in uber_model['assigned_depts_labels']:
                    to_remove.append(dept)
            for dept in to_remove:
                print(f"Removing {badge.public_name} from {dept.name}")
                badge.departments.remove(dept)
            db.add(badge)
        
    db.commit()
    return "", 200
Exemplo n.º 21
0
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
Exemplo n.º 22
0
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()
Exemplo n.º 23
0
def hotel_request_single_api(event, request_id):
    if not check_permission("rooming.*.manage", event=event) and not check_permission(f"hotel_room_request.{request_id}.write", event=event):
        return "", 403
    if request.method == "GET":
        hotel_request = db.query(HotelRoomRequest).filter(HotelRoomRequest.id == request_id).one_or_none()
        if not hotel_request:
            return "Could not locate hotel room request", 404
        room_nights = []
        requested = db.query(RoomNightRequest, HotelRoomNight).join(HotelRoomNight, RoomNightRequest.room_night == HotelRoomNight.id).filter(RoomNightRequest.badge == hotel_request.badge).all()
        for req, night in requested:
            if not night.hidden:
                room_nights.append({
                    "id": night.id,
                    "requested": req.requested,
                    "date": night.date,
                    "name": night.name,
                    "restricted": night.restricted,
                    "restriction_type": night.restriction_type,
                })
        all_room_nights = db.query(HotelRoomNight).filter(HotelRoomNight.event == event).all()
        for room_night in all_room_nights:
            for existing in room_nights:
                if existing['id'] == room_night.id:
                    break
            else:
                room_nights.append({
                    "id": room_night.id,
                    "requested": False,
                    "date": room_night.date,
                    "name": room_night.name,
                    "restricted": room_night.restricted,
                    "restriction_type": room_night.restriction_type
                })
        room_nights.sort(key=lambda x: x['date'])
        return jsonify({
            "event": hotel_request.event,
            "badge": hotel_request.badge,
            "first_name": hotel_request.first_name or "",
            "last_name": hotel_request.last_name or "",
            "declined": hotel_request.declined,
            "prefer_department": hotel_request.prefer_department,
            "preferred_department": hotel_request.preferred_department,
            "notes": hotel_request.notes or "",
            "prefer_single_gender": hotel_request.prefer_single_gender,
            "preferred_gender": hotel_request.preferred_gender or "",
            "noise_level": hotel_request.noise_level or "",
            "smoke_sensitive": hotel_request.smoke_sensitive,
            "sleep_time": hotel_request.sleep_time or "",
            "room_night_justification": hotel_request.room_night_justification or "",
            "requested_roommates": [x.id for x in hotel_request.roommate_requests],
            "antirequested_roommates": [x.id for x in hotel_request.roommate_anti_requests],
            "room_nights": room_nights
        })
    elif request.method == "PATCH":
        hotel_request = db.query(HotelRoomRequest).filter(HotelRoomRequest.id == request_id).one_or_none()
        if not hotel_request:
            return "Could not locate hotel room request", 404
        hotel_request.first_name = g.data['first_name']
        hotel_request.last_name = g.data['last_name']
        hotel_request.declined = g.data['declined']
        hotel_request.prefer_department = g.data['prefer_department']
        hotel_request.preferred_department = g.data['preferred_department']
        hotel_request.notes = g.data['notes']
        hotel_request.prefer_single_gender = g.data['prefer_single_gender']
        hotel_request.preferred_gender = g.data['preferred_gender']
        hotel_request.noise_level = g.data['noise_level']
        hotel_request.smoke_sensitive = g.data['smoke_sensitive']
        hotel_request.sleep_time = g.data['sleep_time']
        hotel_request.room_night_justification = g.data['room_night_justification']
        hotel_request.roommate_requests = db.query(Badge).filter(Badge.id.in_(g.data['requested_roommates'])).all()
        hotel_request.roommate_anti_requests = db.query(Badge).filter(Badge.id.in_(g.data['antirequested_roommates'])).all()
        db.add(hotel_request)
        requested = db.query(RoomNightRequest, HotelRoomNight).join(HotelRoomNight, RoomNightRequest.room_night == HotelRoomNight.id).filter(RoomNightRequest.badge == hotel_request.badge).all()
        night_status = {}
        for req, night in requested:
            night_status[night.id] = req
        for room_night_request in g.data['room_nights']:
            if room_night_request['id'] in night_status:
                night_status[room_night_request['id']].requested = room_night_request['requested']
                db.add(night_status[room_night_request['id']])
            else:
                requested_night = RoomNightRequest(event=event, badge=hotel_request.badge, requested=room_night_request['requested'], room_night=room_night_request['id'])
                db.add(requested_night)
        update_room_request_props(db, [hotel_request,])
        db.commit()
        return "null", 200
Exemplo n.º 24
0
def load_session(endpoint, values):
    g.user = None
    g.badge = None
    g.session = None
    g.event = None
    g.department = None
    g.perms = {
        "event": {},
        "department": {}
    }

    if request.method != "GET":
        if not request.json is None:
            g.data = dict(request.json)
        elif not request.form is None:
            g.data = dict(request.form)
    elif not request.args is None:
        g.data = dict(request.args)

    if not values:
        values = {}
    if 'event' in values:
        g.event = int(values['event'])
    if 'department' in values:
        g.department = int(values['department'])
    if 'session' in request.cookies:
        session = db.query(Session).filter(Session.secret == request.cookies.get('session')).one_or_none()
        if session:
            if datetime.datetime.now() < session.last_active + datetime.timedelta(seconds=config.session_duration):
                session.last_active = datetime.datetime.now()
                g.session = session
                g.user = db.query(User).filter(User.id == session.user).one_or_none()
                g.badge = db.query(Badge).filter(Badge.id == session.badge).one_or_none()
                if "event" in values and not g.badge and g.user:
                    g.badge = db.query(Badge).filter(Badge.user == g.user.id, Badge.event == values['event']).one_or_none()
                perms = json.loads(session.permissions)
                g.perms = {
                    "event": {int(k) if k != '*' else k: v for k, v in perms['event'].items()},
                    "department": {int(k) if k != '*' else k: {int(m) if m != '*' else m: n for m, n in v.items()} for k, v in perms['department'].items()}
                }
                db.add(session)
            else:
                db.delete(session)
            db.commit()
    elif request.headers.get('X-Auth-Token', ""):
        key = request.headers.get('X-Auth-Token')
        apikey = db.query(APIKey).filter(APIKey.key == key).one_or_none()
        if not apikey:
            raise PermissionDenied(message="Invalid API Key")
        if not apikey.enabled:
            raise PermissionDenied(message="API Key is disabled")
        user = db.query(User).filter(User.id == apikey.user).one_or_none()
        if not user:
            raise PermissionDenied(message="Invalid API Key")
        if not user.active:
            raise PermissionDenied(message="API Key is disabled")
        g.user=user
        perms = get_permissions()
        g.perms = {
            "event": {int(k) if k != '*' else k: v for k, v in perms['event'].items()},
            "department": {int(k) if k != '*' else k: {int(m) if m != '*' else m: n for m, n in v.items()} for k, v in perms['department'].items()}
        }
        if "event" in values and not g.badge and g.user:
            g.badge = db.query(Badge).filter(Badge.user == g.user.id, Badge.event == values['event']).one_or_none()
Exemplo n.º 25
0
def update_requests(event):
    if not check_permission("rooming.*.admin"):
        return "", 403
    updates = {
        "requests": {},
        "badges": {}
    }
    badges = db.query(Badge).filter(Badge.event == event).all()
    for badge in badges:
        if not badge.public_name and badge.printed_name:
            badge.public_name = badge.printed_name
            updates['badges'][badge.id] = badge.public_name
            db.add(badge)
    badgeLookup = {x.id: x for x in badges}

    room_nights = db.query(HotelRoomNight).filter(HotelRoomNight.event == event).all()
    room_night_lookup = {x.id: x for x in room_nights}
    block = db.query(HotelRoomBlock).filter(HotelRoomBlock.event == event).first()

    reqs = db.query(HotelRoomRequest).filter(HotelRoomRequest.event == event).options(joinedload('room_night_requests')).all()
    for req in reqs:
        req.requested = False
        req.approved = False
        if not req.declined:
            for rnr in req.room_night_requests:
                if rnr.requested:
                    req.requested = True
                    if not room_night_lookup[rnr.room_night].restricted:
                        req.approved = True
                    else:
                        for rna in req.room_night_approvals:
                            if rna.room_night == rnr.room_night and rna.approved:
                                req.approved = True

        req.assigned = bool(req.room_night_assignments)
        updates['requests'][req.id] = {
            "requested": req.requested,
            "approved": req.approved,
            "assigned": req.assigned
        }

        badge_name = " "
        badge = badgeLookup[req.badge]
        if badge.public_name:
            badge_name = badge.public_name
        elif badge.search_name:
            badge_name = " ".join([x.capitalize() for x in badge.search_name.split(" ")])
        elif badge.legal_name:
            badge_name = badge.legal_name
        elif badge.printed_name:
            badge_name = badge.printed_name

        badge_first_name = badge.first_name
        if not badge_first_name:
            badge_first_name = badge_name.split(" ")[0]

        badge_last_name = badge.last_name
        if not badge_last_name:
            badge_last_name = badge_name.split(" ", 1)[1]

        if not req.first_name:
            if badge_first_name:
                req.first_name = badge_first_name
                updates['requests'][req.id]['first_name'] = req.first_name
        if not req.last_name:
            if badge_last_name:
                req.last_name = badge_last_name
                updates['requests'][req.id]['last_name'] = req.last_name

        if not req.hotel_block:
            req.hotel_block = block.id
        db.add(req)

    

    db.commit()
    return jsonify(updates), 200
Exemplo n.º 26
0
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
Exemplo n.º 27
0
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.")
Exemplo n.º 28
0
    def __call__(self, environ, start_response):
        if environ['REQUEST_URI'].startswith("/api/job/"):
            job_id = environ['REQUEST_URI'].split("/api/job/")[1]
            if r:
                progress = json.loads(r.get(f"{job_id}/progress"))
                if not progress:
                    start_response("404 Not Found", [])
                    return [bytes()]
                if not progress['complete']:
                    start_response("202 Accepted",
                                   [("Content-Type", "application/json")])
                    return [json.dumps(progress).encode()]
                data = r.get(f"{job_id}/data")
                start_response("200 Ok",
                               [("Content-Type", "application/json")])
                return [data]
            else:
                job = db.query(BackgroundJob).filter(
                    BackgroundJob.uuid == job_id).one_or_none()
                if not job:
                    start_response("404 Not Found", [])
                    return [bytes()]
                else:
                    progress = json.loads(job.progress)
                    if progress['complete']:
                        start_response("200 Ok",
                                       [("Content-Type", "application/json")])
                        return [job.result]
                    start_response("202 Accepted",
                                   [("Content-Type", "application/json")])
                    return [job.progress.encode()]
        job_id = str(uuid.uuid4())
        environ['TUBER_JOB_ID'] = job_id
        request_context = {
            "state": "pending",
            "status": "202 Accepted",
            "response_headers": [("Location", f"/api/job/{job_id}")]
        }
        with self.lock:
            if len(self.context) > config.circuitbreaker_threads:
                start_response("504 Gateway Timeout", [])
                return [bytes()]
            self.context[job_id] = request_context

        thread = self.pool.apply_async(
            self.application, (environ, lambda *args, **kwargs: self.
                               _start_response(job_id, *args, **kwargs)),
            callback=lambda *args, **kwargs: self._store_response(
                job_id, *args, **kwargs))
        thread.wait(timeout=config.circuitbreaker_timeout)

        with self.lock:
            start_response(request_context['status'],
                           request_context['response_headers'])
            if request_context['state'] == "immediate":
                del self.context[job_id]
                return thread.get()
            request_context['state'] = "deferred"
            progress = json.dumps({
                "complete": False,
                "amount": 0,
                "messages": "",
                "status": ""
            })
            if r:
                r.set(f"{job_id}/progress", progress)
            else:
                job = BackgroundJob(uuid=job_id, progress=progress)
                db.add(job)
                db.commit()
        return [bytes()]