Beispiel #1
0
def verify_input(state, date=None, data=None):
    """
    Verifies that user inputs to the API are within expected bounds. Unacceptable
    input raises a BadRequestError with status code 400.

    :param state: The state specified for the current request.
    :param date: The date specified for the current request.
    :param data: The body data specified for the current request.
    """
    if state not in storage.STATES:
        raise chalice.BadRequestError(
            f"Unknown state '{state}'.\nYour choices are: "
            f"{', '.join(sorted(storage.STATES))}")

    if data is not None and state != data['state']:
        raise chalice.BadRequestError(
            f"The state '{data['state']}' specified in the request body does not "
            f"match the state '{state}' specified in the URL.")

    test_date = date if date is not None else None if data is None else data[
        'date']
    if test_date is not None:
        try:
            iso_date = datetime.date.fromisoformat(test_date)
            earliest_date = datetime.date(year=2020, month=1, day=1)
            today = datetime.date.today()
            if iso_date < earliest_date or iso_date > today:
                raise chalice.BadRequestError(
                    f"Date must be between {earliest_date} and {today}. "
                    f"{test_date} is outside that range.")
        except ValueError as error:
            raise chalice.BadRequestError from error
Beispiel #2
0
def _get_end_time(query_params, current_time):
    if query_params is None or "end_time" not in query_params:
        return current_time
    try:
        end_time = int(query_params["end_time"])
        if end_time < 0:
            raise chalice.BadRequestError(
                "The end time value cannot be negative."
            )
        return end_time
    except ValueError:
        raise chalice.BadRequestError("Invalid end time type.")
Beispiel #3
0
def student():
    """Perform operations on individual student
    Base Schema:
    {
        "s_id": number,
        "username": "******"
    }
    """
    try:
        request = app.current_request
        request_data = app.current_request.json_body

        if request.method == 'GET':
            # Get student data
            data = get_db().get_item(**request_data)
            return {'students': data.get('Item')}
        elif request.method == 'POST':
            # Insert student record
            return {'status': get_db().put_item(**request_data)}
        elif request.method == 'DELETE':
            # Delete specific item from table
            return {'status': get_db().delete_item(request_data)}
        elif request.method == 'PUT':
            # Update existing student -
            # If item not exist then it will insert new record
            return {'status': get_db().update_item(request_data)}
    except Exception as e:
        raise chalice.BadRequestError(e)
Beispiel #4
0
def _get_start_time(query_params, current_time):
    if query_params is None or "start_time" not in query_params:
        return DEFAULT_START_TIME
    try:
        start_time = int(query_params["start_time"])
        if start_time < 0:
            raise chalice.BadRequestError(
                "The start time value cannot be negative."
            )
        if start_time > current_time:
            raise chalice.BadRequestError(
                "The start time cannot be later than now."
            )
        return start_time
    except ValueError:
        raise chalice.BadRequestError("Invalid start time type.")
Beispiel #5
0
    def _validate_notification(self, notification):
        try:
            match = notification['match']
        except KeyError:
            raise chalice.BadRequestError('Missing notification entry: match')

        try:
            bundle_uuid = match['bundle_uuid']
        except KeyError:
            raise chalice.BadRequestError('Missing notification entry: bundle_uuid')

        try:
            bundle_version = match['bundle_version']
        except KeyError:
            raise chalice.BadRequestError('Missing notification entry: bundle_version')

        if not isinstance(bundle_uuid, str):
            raise chalice.BadRequestError(f'Invalid type: bundle_uuid: {type(bundle_uuid)} (should be str)')

        if not isinstance(bundle_version, str):
            raise chalice.BadRequestError(f'Invalid type: bundle_version: {type(bundle_version)} (should be str)')

        if bundle_uuid.lower() != str(uuid.UUID(bundle_uuid)).lower():
            raise chalice.BadRequestError(f'Invalid syntax: {bundle_uuid} (should be a UUID)')

        if not bundle_version:
            raise chalice.BadRequestError('Invalid syntax: bundle_version can not be empty')
Beispiel #6
0
def balances_address(address):

    query_params = app.current_request.query_params or {}
    asset_id = _get_asset_id(query_params)

    if asset_id != "{}":
        cond1 = "AND b.asset_id = ANY (%(asset_id)s)"
        args1 = {"asset_id": asset_id}
        to_array = list(map(int, asset_id[1:-1].split(",")))
        args2 = {
            "asset_id": sorted(to_array) if len(to_array) > 1 else to_array[0]
        }
    else:
        cond1 = ""
        args1 = {}
        args2 = {}

    if not _is_address(address):
        raise chalice.BadRequestError(
            "Please use only alphanumeric characters and ensure total length of 48."
        )

    q = f"""
WITH latest_block AS (
SELECT
    b.address,
    max(b.block_number) AS block_number,
    b.asset_id,
    a.symbol
FROM {os.environ["DB_SCHEMA"]}.balance b
LEFT JOIN {os.environ["DB_SCHEMA"]}.asset a ON b.asset_id = a.id
WHERE b.address = %(address)s
""" + cond1 + f"""
GROUP BY b.address, b.asset_id, a.symbol
)
SELECT
    balance,
    reserved_balance AS "reservedBalance",
    block_number AS "blockNumber",
    asset_id AS "assetId",
    symbol AS "assetSymbol"
FROM {os.environ["DB_SCHEMA"]}.balance
JOIN latest_block USING ("address", "block_number", "asset_id")
ORDER BY asset_id ASC
"""

    args = {
        "address": address,
    }
    args.update(args1)
    result = _select(q, args=args)
    args.update(args2)
    resp = {
        "params": args,
        "result": result,
    }
    return json.dumps(resp, cls=CustomJsonEncoder)
Beispiel #7
0
def answer_question(question_id):
    if 'answer' not in app.current_request.json_body:
        raise chalice.BadRequestError('Missing "answer" in request body')
    provided_answer = app.current_request.json_body['answer']
    table = chalicelib.questions.QuestionsTable()
    question = table.get_question(question_id)
    if not question:
        raise chalice.NotFoundError('Requested resource does not exist')
    elif provided_answer not in question.possible_answers:
        raise chalice.BadRequestError(
            'Provided answer: %s is not a valid answer. Please submit an '
            'answer from the list of possible answers: %s' %
            (provided_answer, question.possible_answers))
    return {
        'is_correct': provided_answer == question.correct_answer,
        'provided_answer': provided_answer,
        'correct_answer': question.correct_answer,
        'question_id': question.question_id
    }
Beispiel #8
0
def answer_question_for_user(question_id):
    answer_data = answer_question(question_id)
    username = _get_authenticated_username()
    user_table = chalicelib.users.UsersTable()
    try:
        user_table.update_user_score(username, question_id,
                                     answer_data['provided_answer'],
                                     answer_data['is_correct'])
    except chalicelib.users.UserAlreadyAnsweredError as e:
        raise chalice.BadRequestError(str(e))
    return answer_data
Beispiel #9
0
def blocks():
    query_params = app.current_request.query_params or {}
    current_time = int(time.time())
    limit = _get_limit(query_params)
    page = _get_page(query_params)
    start_time = _get_start_time(query_params, current_time)
    end_time = _get_end_time(query_params, current_time)

    if start_time > end_time:
        raise chalice.BadRequestError(
            "The end time cannot be before the start time."
        )

    q = f"""
SELECT
    b."number",
    b.hash,
    b.parent_hash AS "parentHash",
    b.state_root AS "stateRoot",
    b.extrinsics_root AS "extrinsicsRoot",
    b."timestamp",
    b.transaction_count AS "transactionCount",
    b.base_fee AS "baseFee",
    b.byte_fee AS "byteFee",
    b.transfer_fee AS "transferFee",
    b.author,
    b.extrinsic_count AS "extrinsicsCount",
    s.validators
FROM {os.environ["DB_SCHEMA"]}.block b
LEFT JOIN {os.environ["DB_SCHEMA"]}.session s ON b."number" = s.block_number
WHERE b."timestamp" BETWEEN %(start_time)s AND %(end_time)s
ORDER BY b."number" DESC
LIMIT %(limit)s
OFFSET (%(page)s - 1) * %(limit)s
    """
    args = {
        "limit": limit,
        "page": page,
        "start_time": start_time,
        "end_time": end_time,
    }
    resp = {
        "params": args,
        "result": _select(q, args=args),
    }
    return json.dumps(resp, cls=CustomJsonEncoder)
Beispiel #10
0
def transaction_hash(hash):

    if not _is_hex(hash):
        raise chalice.BadRequestError(
            "Wrong hash format. Please use only alphanumeric characters and `0x` prefix."
        )

    q = f"""
SELECT
    tx.hash,
    tx.block_number AS "blockNumber",
    tx.block_hash AS "blockHash",
    tx.from_address AS "fromAddress",
    b1.balance AS "fromAddressBalance",
    tx.to_address AS "toAddress",
    b2.balance AS "toAddressBalance",
    tx."value",
    tx.fee,
    tx.nonce,
    tx."size",
    tx.status,
    tx."timestamp",
    tx.asset_id AS "assetId",
    a.symbol AS "assetSymbol",
    tx.gas_limit AS "gasLimit",
    tx.index,
    tx.type,
    tx.data
FROM {os.environ["DB_SCHEMA"]}.transaction tx
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b1 ON tx.block_number = b1.block_number AND tx.from_address = b1.address AND tx.asset_id = b1.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b2 ON tx.block_number = b2.block_number AND tx.to_address = b2.address AND tx.asset_id = b2.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.asset a ON tx.asset_id = a.id
WHERE tx."hash" = %(hash)s
     """
    args = {
        "hash": hash,
    }
    resp = {
        "result": _select(q, args=args, one=True),
    }

    return json.dumps(resp, cls=CustomJsonEncoder)
Beispiel #11
0
def block(id):

    # {id} can be either block number or block hash

    column = ""
    if id.isdigit():
        column = 'b."number"'
        id = int(id)
    elif _is_hex(id):
        column = 'b.hash'
    else:
        raise chalice.BadRequestError(
            "Please specify either block number or block hash."
        )

    q = f"""
SELECT
    b."number",
    b.hash,
    b.parent_hash AS "parentHash",
    b.state_root AS "stateRoot",
    b.extrinsics_root AS "extrinsicsRoot",
    b."timestamp",
    b.transaction_count AS "transactionCount",
    b.base_fee AS "baseFee",
    b.byte_fee AS "byteFee",
    b.transfer_fee AS "transferFee",
    b.author,
    b.extrinsic_count AS "extrinsicsCount",
    s.validators
FROM {os.environ["DB_SCHEMA"]}.block b
LEFT JOIN {os.environ["DB_SCHEMA"]}.session s ON b."number" = s.block_number
WHERE {column} = %(id)s
    """
    args = {
        "id": id,
    }
    resp = {
        "result": _select(q, args=args, one=True),
    }
    return json.dumps(resp, cls=CustomJsonEncoder)
Beispiel #12
0
def address_transactions(address):
    query_params = app.current_request.query_params or {}
    current_time = int(time.time())
    limit = _get_limit(query_params)
    page = _get_page(query_params)
    start_time = _get_start_time(query_params, current_time)
    end_time = _get_end_time(query_params, current_time)
    asset_id = _get_asset_id(query_params)
    txn_flow = _get_txn_flow(query_params)
    txn_type = _get_txn_type(query_params)

    if asset_id != "{}":
        cond1 = "AND tx.asset_id = ANY (%(asset_id)s)"
        args1 = {"asset_id": asset_id}
        to_array = list(map(int, asset_id[1:-1].split(",")))
        args2 = {
            "asset_id": sorted(to_array) if len(to_array) > 1 else to_array[0]
        }
    else:
        cond1 = ""
        args1 = {}
        args2 = {}

    if start_time > end_time:
        raise chalice.BadRequestError(
            "The end time cannot be before the start time."
        )
    if not _is_address(address):
        raise chalice.BadRequestError(
            "Please use only alphanumeric characters and ensure total length of 48."
        )

    q_total_cnt = f"""
WITH block AS (
    SELECT
    "number" AS block_number
    FROM {os.environ["DB_SCHEMA"]}.block
    WHERE "timestamp" BETWEEN %(start_time)s AND %(end_time)s
), combined_txns AS (
    SELECT 
    CASE WHEN from_address = %(address)s THEN 'Outgoing' ELSE 'Incoming' END AS txn_flow,
    type, 
    asset_id
    FROM {os.environ["DB_SCHEMA"]}.transaction
    JOIN block USING ("block_number")
    WHERE to_address = %(address)s OR from_address = %(address)s
    UNION ALL
    SELECT 
    CASE WHEN from_address = %(address)s THEN 'Outgoing' ELSE 'Incoming' END AS txn_flow,
    'Internal'::text AS type, 
    asset_id
    FROM {os.environ["DB_SCHEMA"]}.trace
    JOIN block USING ("block_number")
    WHERE to_address = %(address)s OR from_address = %(address)s
)
SELECT count(*) AS total
FROM combined_txns tx
WHERE tx.txn_flow = ANY ( %(txn_flow)s )
AND tx.type = ANY (%(txn_type)s)
""" + cond1

    q = f"""
WITH block AS (
    SELECT
    hash AS block_hash, "number" AS block_number
    FROM {os.environ["DB_SCHEMA"]}.block
    WHERE "timestamp" BETWEEN %(start_time)s AND %(end_time)s
), combined_txns AS (
    SELECT tx.*,
    CASE WHEN from_address = %(address)s THEN 'Outgoing' ELSE 'Incoming' END AS txn_flow
    FROM {os.environ["DB_SCHEMA"]}.transaction tx
    JOIN block USING ("block_number")
    WHERE to_address = %(address)s OR from_address = %(address)s
    UNION ALL
    SELECT transaction_hash as hash, block_number, block.block_hash, from_address, to_address, value, null, null, null,
    true::bool AS status, timestamp, asset_id, null, index, 'Internal'::text AS type, null,
    CASE WHEN from_address = %(address)s THEN 'Outgoing' ELSE 'Incoming' END AS txn_flow
    FROM {os.environ["DB_SCHEMA"]}.trace
    JOIN block USING ("block_number")
    WHERE to_address = %(address)s OR from_address = %(address)s
)
SELECT
    tx.hash,
    tx.block_number AS "blockNumber",
    tx.block_hash AS "blockHash",
    tx.from_address AS "fromAddress",
    b1.balance AS "fromAddressBalance",
    tx.to_address AS "toAddress",
    b2.balance AS "toAddressBalance",
    tx."value",
    tx.fee,
    tx.nonce,
    tx."size",
    tx.status,
    tx."timestamp",
    tx.asset_id AS "assetId",
    tx.txn_flow AS "transactionFlow",
    a.symbol AS "assetSymbol",
    tx.gas_limit AS "gasLimit",
    tx.index,
    tx.type,
    tx.data
FROM combined_txns tx
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b1 ON tx.block_number = b1.block_number AND tx.from_address = b1.address AND tx.asset_id = b1.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b2 ON tx.block_number = b2.block_number AND tx.to_address = b2.address AND tx.asset_id = b2.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.asset a ON tx.asset_id = a.id
WHERE tx.txn_flow = ANY ( %(txn_flow)s )
AND tx.type = ANY ( %(txn_type)s )
""" + cond1 + f"""
ORDER BY tx.block_number DESC, tx.index ASC
LIMIT %(limit)s
OFFSET (%(page)s - 1) * %(limit)s
    """
    args = {
        "address": address,
        "limit": limit,
        "page": page,
        "start_time": start_time,
        "end_time": end_time,
        "txn_flow": txn_flow,
        "txn_type": txn_type,
    }
    args.update(args1)
    result = _select(q, args=args)
    args.update(_select(q_total_cnt, args=args, one=True) or {})
    args.update(
        {
            "txn_flow": txn_flow[1:-1].split(","),
            "txn_type": txn_type[1:-1].split(",")
        }
    )
    args.update(args2)
    resp = {
        "params": args,
        "result": result,
    }
    return json.dumps(resp, cls=CustomJsonEncoder)
Beispiel #13
0
def transaction_hash_internal(hash):
    query_params = app.current_request.query_params or {}
    limit = _get_limit(query_params)
    page = _get_page(query_params)
    asset_id = _get_asset_id(query_params)

    if asset_id != "{}":
        cond1 = "AND tx.asset_id = ANY (%(asset_id)s)"
        args1 = {"asset_id": asset_id}
        to_array = list(map(int, asset_id[1:-1].split(",")))
        args2 = {
            "asset_id": sorted(to_array) if len(to_array) > 1 else to_array[0]
        }
    else:
        cond1 = ""
        args1 = {}
        args2 = {}

    if not _is_hex(hash):
        raise chalice.BadRequestError(
            "Wrong hash format. Please use only alphanumeric characters and `0x` prefix."
        )

    q_total_cnt = f"""
SELECT count(*) AS total
FROM {os.environ["DB_SCHEMA"]}.trace tx
WHERE tx.transaction_hash = %(hash)s
""" + cond1

    q = f"""
SELECT
    tx.transaction_hash AS "hash",
    tx.block_number AS "blockNumber",
    tx.from_address AS "fromAddress",
    b1.balance AS "fromAddressBalance",
    tx.to_address AS "toAddress",
    b2.balance AS "toAddressBalance",
    tx."value",
    tx."timestamp",
    tx.asset_id AS "assetId",
    a.symbol AS "assetSymbol",
    tx.index
FROM {os.environ["DB_SCHEMA"]}.trace tx
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b1 ON tx.block_number = b1.block_number AND tx.from_address = b1.address AND tx.asset_id = b1.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b2 ON tx.block_number = b2.block_number AND tx.to_address = b2.address AND tx.asset_id = b2.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.asset a ON tx.asset_id = a.id
WHERE tx.transaction_hash = %(hash)s
""" + cond1 + """
ORDER BY tx.index ASC
"""

    args = {
        "hash": hash,
        "limit": limit,
        "page": page,
    }
    args.update(args1)
    result = _select(q, args=args)
    args.update(_select(q_total_cnt, args=args, one=True) or {})
    args.update(args2)
    resp = {
        "params": args,
        "result": result,
    }

    return json.dumps(resp, cls=CustomJsonEncoder)
Beispiel #14
0
def block_transactions(id):
    query_params = app.current_request.query_params or {}
    limit = _get_limit(query_params)
    page = _get_page(query_params)
    asset_id = _get_asset_id(query_params)
    txn_type = _get_txn_type(query_params)

    if asset_id != "{}":
        cond1 = "AND tx.asset_id = ANY (%(asset_id)s)"
        args1 = {"asset_id": asset_id}
        to_array = list(map(int, asset_id[1:-1].split(",")))
        args2 = {
            "asset_id": sorted(to_array) if len(to_array) > 1 else to_array[0]
        }
    else:
        cond1 = ""
        args1 = {}
        args2 = {}

    # {id} can be either block number or block hash

    column = ""
    if id.isdigit():
        column = "number"
        id = int(id)
    elif _is_hex(id):
        column = "hash"
    else:
        raise chalice.BadRequestError(
            "Please specify either block number or block hash."
        )

    q_total_cnt = f"""
WITH block AS (
    SELECT
    "number" AS block_number
    FROM {os.environ["DB_SCHEMA"]}.block
    WHERE {column} = %(id)s
), combined_txns AS (
    SELECT type, asset_id
    FROM {os.environ["DB_SCHEMA"]}.transaction
    JOIN block USING ("block_number")
    UNION ALL
    SELECT 'Internal'::text AS type, asset_id
    FROM {os.environ["DB_SCHEMA"]}.trace
    JOIN block USING ("block_number")
)
SELECT count(*) AS total
FROM combined_txns tx
WHERE tx.type = ANY (%(txn_type)s)
""" + cond1

    q = f"""
WITH block AS (
    SELECT
    hash AS block_hash, "number" AS block_number
    FROM {os.environ["DB_SCHEMA"]}.block
    WHERE {column} = %(id)s
), combined_txns AS (
    SELECT tx.*
    FROM {os.environ["DB_SCHEMA"]}.transaction tx
    JOIN block USING ("block_number")
    UNION ALL
    SELECT transaction_hash as hash, block_number, block.block_hash, from_address, to_address, value, null, null, null,
    true::bool AS status, timestamp, asset_id, null, index, 'Internal'::text AS type, null
    FROM {os.environ["DB_SCHEMA"]}.trace
    JOIN block USING ("block_number")
)
SELECT
    tx.hash,
    tx.block_number AS "blockNumber",
    tx.block_hash AS "blockHash",
    tx.from_address AS "fromAddress",
    b1.balance AS "fromAddressBalance",
    tx.to_address AS "toAddress",
    b2.balance AS "toAddressBalance",
    tx."value",
    tx.fee,
    tx.nonce,
    tx."size",
    tx.status,
    tx."timestamp",
    tx.asset_id AS "assetId",
    a.symbol AS "assetSymbol",
    tx.gas_limit AS "gasLimit",
    tx.index,
    tx.type,
    tx.data
FROM combined_txns tx
JOIN block USING("block_number")
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b1 ON tx.block_number = b1.block_number AND tx.from_address = b1.address AND tx.asset_id = b1.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.balance b2 ON tx.block_number = b2.block_number AND tx.to_address = b2.address AND tx.asset_id = b2.asset_id
LEFT JOIN {os.environ["DB_SCHEMA"]}.asset a ON tx.asset_id = a.id
WHERE tx.type = ANY (%(txn_type)s)
""" + cond1 + f"""
ORDER BY tx.block_number DESC, tx.index ASC
LIMIT %(limit)s
OFFSET (%(page)s - 1) * %(limit)s
    """
    args = {
        "id": id,
        "limit": limit,
        "page": page,
        "txn_type": txn_type,
    }
    args.update(args1)
    result = _select(q, args=args)
    args.update(_select(q_total_cnt, args=args, one=True) or {})
    args.update({"txn_type": txn_type[1:-1].split(",")})
    args.update(args2)
    resp = {
        "params": args,
        "result": result,
    }
    return json.dumps(resp, cls=CustomJsonEncoder)