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
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.")
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)
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.")
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')
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)
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 }
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
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)
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)
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)
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)
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)
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)