Пример #1
0
def current_drinks(adapter):
    # optional request paremeter, the name of the machine to get stock information
    machine_name = request.args.get('machine', None)

    # assemble an array of (id, name) tuples
    if machine_name is None:
        machines = adapter.get_machines()
        logger.debug('Fetching contents for machines {}'.format(', '.join(
            [m['name'] for m in machines])))
    else:
        # We're given a machine name
        machine = adapter.get_machine(machine_name)

        if machine is None:
            err = f'The provided machine name \'{machine_name}\' is not a valid machine'
            logger.error(err)
            return bad_params(err)

        logger.debug('Fetching contents for machine {}'.format(machine_name))
        machines = []
        machines.append(machine)

    response = {}

    with Pool(5) as p:
        contents = p.map(query_machine, machines)
        response['machines'] = contents

    response[
        'message'] = 'Successfully retrieved machine contents for {}'.format(
            ', '.join([machine['name'] for machine in machines]))

    return jsonify(response), 200
Пример #2
0
def update_slot_status():
    if request.headers.get('Content-Type') != 'application/json':
        return bad_headers_content_type()

    body = request.json

    logger.debug('Handling slot update')

    unprovided = []
    if 'machine' not in body:
        unprovided.append('machine')
    if 'slot' not in body:
        unprovided.append('slot')

    if len(unprovided) > 0:
        return bad_params(
            'The following required parameters were not provided: {}'.format(
                ', '.join(unprovided)))

    if 'active' not in body and 'item_id' not in body:
        return bad_params(
            'Either the state or item within a slot must be provided for an update.'
        )

    updates = {}

    if 'active' in body:
        if not isinstance(body['active'], bool):
            return bad_params('The active parameter must be a boolean value')

        updates['active'] = body['active']

    if 'item_id' in body:
        try:
            item_id = int(body['item_id'])
            if item_id <= 0:
                raise ValueError()
        except ValueError:
            return bad_params('The item ID value must be a positive integer')

        updates['item'] = item_id

        item = db.session.query(Item).filter(Item.id == item_id).first()

        if item is None:
            return bad_params(
                'No item with ID {} is present in the system'.format(item_id))

    try:
        slot_num = int(body['slot'])

        if slot_num <= 0:
            raise ValueError()
    except ValueError:
        return bad_params('The slot number must be a positive integer')

    machine = db.session.query(Machine).filter(
        Machine.name == body['machine']).first()
    if machine is None:
        return bad_params('The machine \'{}\' is not a valid machine'.format(
            body['machine']))

    slot = db.session.query(Slot).filter(Slot.number == slot_num,
                                         Slot.machine == machine.id).first()
    if slot is None:
        return bad_params(
            'The machine \'{}\' does not have a slot number {}'.format(
                body['machine'],
                body['slot'],
            ))

    logger.debug('Slot update details validated')

    slot = db.session.query(Slot).filter(Slot.number == body['slot'], Slot.machine == machine.id).\
            update(updates, synchronize_session=False)

    if slot < 1:
        return jsonify({
            'error': 'Could not update slot',
            'errorCode': 500,
            'message': 'Contact a drink admin'
        }), 500

    db.session.commit()

    slot = db.session.query(Slot).filter(Slot.number == slot_num,
                                         Slot.machine == machine.id).first()

    success = {
        'message':
        'Successfully updated slot {} in {}'.format(slot.number,
                                                    body['machine']),
        'slot': {
            'machine': body['machine'],
            'number': slot.number,
            'active': slot.active,
            'item_id': slot.item,
        },
    }

    return jsonify(success), 200
Пример #3
0
def current_drinks(adapter):
    # optional request paremeter, the name of the machine to get stock information
    machine_name = request.args.get('machine', None)

    # assemble an array of (id, name) tuples
    if machine_name is None:
        machines = adapter.get_machines()
        logger.debug('Fetching contents for machines {}'.format(', '.join(
            [m['name'] for m in machines])))
    else:
        # We're given a machine name
        machine = adapter.get_machine(machine_name)

        if machine is None:
            return bad_params(
                'The provided machine name \'{}\' is not a valid machine'.
                format(machine_name))

        logger.debug('Fetching contents for machine {}'.format(machine_name))
        machines = []
        machines.append(machine)

    response = {"machines": []}

    for machine in machines:
        logger.debug('Querying machine details for {}'.format(machine['name']))
        machine_slots = adapter.get_slots_in_machine(machine['name'])

        is_online = True

        try:
            slot_status = _get_machine_status(machine['name'])
        except requests.exceptions.ConnectionError:
            # We couldn't connect to the machine
            logger.debug(
                'Machine {} is unreachable, reporting as offline'.format(
                    machine['name']))
            slot_status = [{'empty': True} for n in range(len(machine_slots))]
            is_online = False  # seems a useful feature
        except requests.exceptions.Timeout:
            # We hit a timeout waiting for the machine to respond
            logger.debug(
                'Machine {} was reachable, but did not respond within a reasonable amount of time'
                .format(machine['name']))
            slot_status = [{'empty': True} for n in range(len(machine_slots))]
            is_online = False

        machine_contents = {
            'id': machine['id'],
            'name': machine['name'],
            'display_name': machine['display_name'],
            'is_online': is_online,
            'slots': []
        }

        for slot in machine_slots:
            slot_item = adapter.get_item(slot['item'])
            machine_contents['slots'].append({
                "number":
                slot['number'],
                "active":
                slot['active'],
                "count":
                slot['count'],
                "empty":
                slot_status[slot['number'] - 1]['empty'],
                "item": {
                    "name": slot_item['name'],
                    "price": slot_item['price'],
                    "id": slot_item['id'],
                },
            })
        response['machines'].append(machine_contents)
        logger.debug('Fetched all available details for {}'.format(
            machine['name']))

    response[
        'message'] = 'Successfully retrieved machine contents for {}'.format(
            ', '.join([machine['name'] for machine in machines]))

    return jsonify(response), 200
Пример #4
0
def drop_drink(adapter, user=None):
    if request.headers.get('Content-Type') != 'application/json':
        return bad_headers_content_type()

    logger.debug('Handing request to drop drink')

    bal_before = _get_credits(user['preferred_username'])

    body = request.json

    unprovided = []
    if 'machine' not in body:
        unprovided.append('machine')
    if 'slot' not in body:
        unprovided.append('slot')

    if len(unprovided) > 0:
        return bad_params(
            'The following required parameters were not provided: {}'.format(
                ', '.join(unprovided)))

    machine = db.session.query(Machine).filter(
        Machine.name == body['machine']).first()
    if machine is None:
        return bad_params(
            'The machine name \'{}\' is not a valid machine'.format(
                body['machine']))

    slot = db.session.query(Slot).filter(Slot.number == body['slot'],
                                         Slot.machine == machine.id).first()
    if slot is None:
        return bad_params(
            'The machine \'{}\' does not have a slot with id \'{}\''.format(
                body['machine'], body['slot']))

    logger.debug('Drop request is valid')

    slot_status = _get_machine_status(body['machine'])
    if (body['machine'] == 'snack' and slot.count < 1
        ) or slot_status[body['slot'] - 1]['empty']:  # slots are 1 indexed
        return jsonify({
            "error": "The requested slot is empty!",
            "errorCode": 400
        }), 400

    item = db.session.query(Item).filter(Item.id == slot.item).first()

    if bal_before < item.price:
        response = {
            "error": "The user \'{}\' does not have a sufficient drinkBalance",
            "errorCode": 402
        }
        return jsonify(response), 402

    logger.debug('User has sufficient balance')

    machine_hostname = '{}.csh.rit.edu'.format(machine.name)
    request_endpoint = 'https://{}/drop'.format(machine_hostname)

    body = {"slot": slot.number}

    headers = {
        'X-Auth-Token': app.config['MACHINE_API_TOKEN'],
        'Content-Type': 'application/json'
    }

    # Do the thing
    try:
        response = requests.post(request_endpoint,
                                 json=body,
                                 headers=headers,
                                 timeout=5)
    except requests.exceptions.ConnectionError:
        return jsonify({
            "error": "Could not contact drink machine for drop!",
            "errorCode": 500
        }), 500
    except requests.exceptions.Timeout:
        return jsonify({
            "error": "Connection to the drink machine timed out!",
            "errorCode": 500
        }), 500

    try:
        response.raise_for_status()
    except requests.exceptions.HTTPError:
        return jsonify({"error": "Could not access slot for drop!",
                        "message": response.json()['error'],
                        "errorCode": response.status_code}),\
                       response.status_code

    logger.debug('Dropped drink - adjusting user credits')
    new_balance = bal_before - item.price
    _manage_credits(user['preferred_username'], new_balance, adapter)
    logger.debug('Credits for {} updated'.format(user['preferred_username']))

    if machine.name == 'snack':
        slot.count = Slot.count - 1  # Decrement stock count, set inactive if empty
        if slot.count == 0:
            slot.active = False
        db.session.commit()

    return jsonify({
        "message": "Drop successful!",
        "drinkBalance": new_balance
    }), response.status_code