def access_token_view(): grant_type = request.form.get('grant_type') code = request.form.get('code') if grant_type.lower() != 'authorization_code' or not code: return send_error(request, 400) app = extract_client(request, OAUTH2_APPS) grant = mongo.db.OAuth2Code.find({ 'app': app['client_id'], 'token': code, 'expires': { '$gt': datetime.now() } }) if grant.count() == 0: return send_error(request, 404) grant = cursor_to_list(grant)[0] token = { 'expires': datetime.now() + timedelta(seconds=36000), 'access_token': generate_token(), 'refresh_token': generate_token(), 'token_type': 'Bearer', 'user': grant['user'], } mongo.db.OAuth2Access.insert(token) mongo.db.OAuth2Code.delete_one({'token': code, 'app': app['client_id']}) token['expires'] = 36000 return send_response(request, token)
def register_me(route_id): try: response = requests.get(SESSIONS_SERVICE_URL + 'identify/', headers=clean_hh(request)) if response.status_code != 200: return send_error(request, 403) except ConnectionError: return send_response(request, {'status': 'Session service is down'}) user = response.json()['data'] print({'USER': user}) headers = {} headers.update({ 'X_EMAIL': user['email'], 'X_SECRET': user['password'], }) print({'HEADERS': headers}) try: response = requests.post(ROUTE_SERVICE_URL + 'route/%s/register/' % route_id, headers=headers) if response.status_code == 200: return send_response(request, {'status': 'OK'}) return send_error(request, response.status_code) except ConnectionError: return send_response(request, {'status': 'Route service is down'})
def delete(self, transaction_id): ''' Endpoint for deleting a transaction Deletes the given Transaction and updates the associated User record's balance ''' parser = reqparse.RequestParser() parser.add_argument('Credits-Token', location='headers', required=True, type=netid_from_token, dest='admin_netid') args = parser.parse_args() # Require an admin session token to delete transactions if not is_admin(args.admin_netid): return send_error("Must be admin to delete transaction", 403) transaction = Transaction.query.filter_by(id=transaction_id).first() if transaction: transaction.user.balance -= transaction.amount db.session.add(transaction.user) db.session.delete(transaction) db.session.commit() return send_success("Deleted transaction: %s" % transaction_id) else: return send_error("Unknown transaction")
def post(self): ''' Endpoint for registering a meme ''' parser = reqparse.RequestParser() parser.add_argument('url', required=True) parser.add_argument('title') args = parser.parse_args() if Meme.query.filter_by(url=args.url).first(): return send_error("This meme has already been submitted! " "Lay off the stale memes.", 400) try: args.url = validate_imgur_link(args.url) except ValueError as e: logger.info('%s sent an invalid imgur link.' % flask.g.netid) return send_error(str(e)) meme = Meme( url=args.url, title=args.title, netid=flask.g.netid ) db.session.add(meme) db.session.commit() logger.info("%s created new meme with id %s" % (flask.g.netid, meme.id)) return jsonify(meme.to_dict())
def register_view(route_id): """ curl -X post 'http://127.0.0.1:9093/route/586f9570050df411919ca465/register/' -H 'X_EMAIL: [email protected]' -H 'X_SECRET: ewifyw521763eyuwfgeuwYTWDYA' """ idid = int(route_id) if not idid: return send_error(request, 404) email = request.headers.environ.get('HTTP_X_EMAIL') if not email: return send_error(request, 404) route = mongo.db.route.find({'self_id': idid}) if route.count() == 0: return send_error(request, 404) route = cursor_to_list(route)[0] users_on_route = route.get('users', []) if email not in users_on_route: users_on_route.append(email) result = mongo.db.route.update_one({'self_id': idid}, {'$set': { 'users': users_on_route }}) return send_response(request, { 'status': 'OK', 'updated': result.matched_count }) else: return send_response(request, {'status': 'OK', 'updated': 0})
def add_post(): """ This method should add a new post in db :return: a notification of successful or errors """ params = { 'title': fields.String(), 'content': fields.String() } json_data = parse_req(params) content = json_data.get("content", None) if check_input(content): return send_error(code=406, message="Content contains special characters") title = json_data.get('title', None) if check_input(title): return send_error(code=406, message="Title contains special characters") query_data = { '_id': str(ObjectId()), 'title': title, 'content': content } try: result = news.insert(query_data) return send_result(result) except: return send_error(code=400)
def login_view(): if request.method == 'GET': auth = session.get('email') if auth: return render_template('yet_auth.html', email=auth) return render_template('login.html', url=request.url) elif request.method == 'POST': email = request.form.get('email') password = request.form.get('password') if not email or not password: return send_error(request, 400) password = get_hash(password.encode('ascii')).hexdigest() users_cursor = mongo.db.user.find({ 'email': email, 'password': password }) if users_cursor.count() == 0: return send_error(request, 404) user = cursor_to_list(users_cursor)[0] session['email'] = user['email'] if 'next' in request.args: redirect_uri = unquote(request.args.get('next')) return redirect(redirect_uri) return send_response(request, {'status': 'Authorized'})
def get_route_view(route_id): """ curl -X get 'http://127.0.0.1:9093/route/586f956f050df411919ca464' curl -X delete 'http://127.0.0.1:9093/route/586f956f050df411919ca464' """ idid = int(route_id) if not idid: return send_error(request, 404) if request.method == 'GET': route = mongo.db.route.find({'self_id': idid}) route = cursor_to_list(route) print({'method': 'get', 'route': route}) if len(route) > 0: return send_response(request, route[0]) else: return send_error(request, 404) elif request.method == 'PATCH': #TODO: check company owner json_s = request.get_json(force=True) print(json_s) json_d = json.loads(json_s) print({"jayson": json_d}) if json_d is None: return send_error(request, 400) # route = {field: json_d[field] for field in ROUTE_FIELDS if json_d[field] is not None} route = {} for field in ROUTE_FIELDS: if field in json_d: value = json_d[field] if value is not None: route.update({field: value}) print({'method': 'patch', 'route': route}) if len(route) == 0: return send_error(request, 400) route['updated'] = datetime.now() result = mongo.db.route.update({'self_id': idid}, {'$set': route}) return send_response(request, { 'status': 'OK', 'updated': result['nModified'] }) elif request.method == 'DELETE': #TODO: check company owner result = mongo.db.route.delete_one({'self_id': idid}) return send_response(request, { 'self_id': idid, 'deleted': result.deleted_count })
def personal_view(): try: response = requests.get(SESSIONS_SERVICE_URL + 'identify/', headers=clean_hh(request)) if response.status_code != 200: return send_error(request, 403) except ConnectionError as e: return send_response(request, {'status': 'Session service is down'}) user = response.json()['data'] headers = {'X_EMAIL': user['email']} try: response = requests.get(COMPANY_SERVICE_URL + 'companies/', headers=headers) if response.status_code == 200: companies = json.loads(response.text) user['companies'] = companies['data'] except ConnectionError as e: user['companies'] = {'error': 'Company service is down'} try: response = requests.get(ROUTE_SERVICE_URL + 'my_routes/', headers=headers) if response.status_code == 200: routes = json.loads(response.text) user['routes'] = routes['data'] except ConnectionError as e: user['routes'] = {'error': 'Routes service is down'} return send_response(request, {'status': 'OK', 'data': user})
def update_data_by_id(): """ This method should update a post by its id in db :return: a notification of successful or error """ param_id = request.args.get('_id', None) query_id = { '_id': param_id } find_id = news.find(query_id) if find_id is None: return jsonify("_id doesn't exist!") params = { 'title': fields.String(), 'content': fields.String() } json_data = parse_req(params) try: title = json_data.get('title', None) content = json_data.get('content', None) except: return jsonify("Error occur when getting data !") new_param = { '$set': { 'title': title, 'content': content } } try: result = news.update_one(query_id, new_param) return send_result(result) except: return send_error(code=500)
def post_notification(): data = request.get_json(force=True) if not data: return send_error('Could not parse JSON from request body') notification, errors = Notification().load(data) if errors: return send_validation_errors(errors) if not notification['services']: return send_error('Must specify services to send to') for service in notification['services']: if service['name'] not in SERVICE_CLIENTS: return send_error('Invalid service: {}'.format(service['name'])) send_func = SERVICE_CLIENTS[service['name']].send for key in service.keys(): if key != 'name' and key not in inspect.getargspec(send_func)[0]: return send_error('Invalid key for service "{}": {}'.format( service['name'], key) ) try: logger.info( 'Sending notification through {}'.format(service['name']) ) send_func( message=notification['message'], **{k: v for k, v in service.items() if k != 'name'} ) except Exception as e: logger.error( 'Exception while sending notification to {}: {}'.format( service['name'], e ) ) return send_error( 'Error sending notification to {}: {}'.format( service['name'], e ), 500 ) return send_success('Notification(s) sent')
def create_route_view(): """ curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:9093/route/' \ -d '{"name": "North Russia", "departure": "2015-10-10 12:00:00", "arrival": "2015-10-15 18:00:00", "price": 100, "company": "TTS"}' """ #TODO: check company owner json_s = request.get_json(force=True) json_d = json.loads(json_s) if json_d is None: return send_error(request, 400) #route = {field: request.json.get(field) for field in ROUTE_FIELDS} route = {} for field in ROUTE_FIELDS: if field in json_d: value = json_d[field] if value is not None: route.update({field: value}) else: route.update({field: None}) if route['company'] is None: return send_error(request, 404) response = requests.get(COMPANY_SERVICE_URL + 'company/' + route['company']) if response.status_code == 404: return send_error(request, 404) route['created'] = datetime.now() # max_response = mongo.db.route.find().sort({'self_id': -1}).limit(1) max_response = mongo.db.route.find({}, {'self_id': 1}) print({'max_response': max_response}) if max_response.count() == 0: route['self_id'] = int(1) else: max_id = 1 for r in max_response: if r['self_id'] > max_id: max_id = r['self_id'] route['self_id'] = int(max_id) + 1 mongo.db.route.insert(route) return send_response(request, {'status': 'OK', 'data': route})
def get_title(): """ This method should find a post by its content :return: a post """ param_title = request.args.get('title', None) query_title = { 'title': param_title } if check_input(param_title): find_title = news.find_one(query_title) if find_title: page_size = request.args.get('page_size', '0') page_number = request.args.get('page_number', '0') skips = int(page_size) * int(page_number) find_data = list(news.find(query_title, {'_id': 0}).skip(skips).limit(int(page_size))) return send_result(find_data) return send_error(code=404, message="Title doesn't exist") return send_error(code=406, message="Invalid title")
def make_payment(): ''' Endpoint for executing Stripe payments Params: * netid: NetID of user making payment * amount: Payment amount in cents * token: Stipe.js payment token * description: Description of payment ''' parser = reqparse.RequestParser() parser.add_argument('netid', location='json', required=True, type=validate_netid) parser.add_argument('amount', location='json', required=True, type=int) parser.add_argument('token', location='json', required=True) parser.add_argument('description', location='json', required=True) parser.add_argument('adjust_balance', location='json', default=True, type=bool) args = parser.parse_args() if (args.amount < 500) or (args.amount > 5000): return send_error('Invalid transaction amount.') try: customer = stripe.Customer.create(description=args.netid, source=args.token) stripe.Charge.create(customer=customer.id, amount=args.amount, currency='usd', description=args.description) float_amount = (args.amount / 100.0) # Convert from cents to dollars if args.adjust_balance: # Create transaction for payment refill = Transaction(netid=args.netid, amount=float_amount, description=args.description) # Update User balance user = get_user(args.netid) user.balance += float_amount db.session.add(refill) db.session.add(user) db.session.commit() return jsonify({'successful': True}) except Exception as e: print e return jsonify({'successful': False})
def my_routes_view(): email = request.headers.environ.get('HTTP_X_EMAIL') print(request.headers) print(email) if not email: return send_error(request, 403) routes = mongo.db.route.find({'users': email}) routes = cursor_to_list(routes) return send_response(request, {'status': 'OK', 'data': routes})
def routes_view(): """ curl -X get 'http://127.0.0.1:9093/routes/?size=2&page=1' """ try: routes = mongo.db.route.find({}).sort('created', DESCENDING) result = paginate(request, data=routes) return send_response(request, result) except Error as e: return send_error(request, e.code)
def get(self, netid=None): ''' Endpoint for checking a user's balance ''' if netid: # Find single user's balance try: validate_netid(netid) except ValueError: return send_error('Unrecognized user', 404) user = get_user(netid) return jsonify(user.serialize()) else: # Find all users' balances users = User.query.all() return jsonify([u.serialize() for u in users])
def register_view(): if request.method == 'GET': auth = session.get('email') if auth: return render_template('yet_auth.html', email=auth) return render_template('register.html') elif request.method == 'POST': user = {field: request.form.get(field) for field in USER_FIELDS} if not user['email'] or not user['password']: return send_error(request, 400) yet_created = mongo.db.user.find({'email': user['email']}).count() if yet_created > 0: return send_error(request, 400) user['password'] = get_hash( user['password'].encode('ascii')).hexdigest() user['created'] = datetime.now() mongo.db.user.insert(user) return redirect('/login/')
def get_company_view(abbr): """ curl -X GET 'http://localhost:9092/company/TTS/' curl -X PATCH -d '{"info": "Hello"}' -H "Content-Type: application/json" 'http://127.0.0.1:9092/company/TTS/' curl -X DELETE 'http://localhost:9092/company/TTS/' """ if request.method == 'GET': company = mongo.db.company.find({'abbreviation': abbr}) company = cursor_to_list(company) print({'method': 'get', 'company': company}) if len(company) > 0: return send_response(request, company[0]) else: return send_error(request, 404) elif request.method == 'PATCH': #TODO: check owner json_s = request.get_json() if json_s is None: return send_error(request, 400) json_d = json.loads(json_s) if json_d is None: return send_error(request, 400) company = {field: json_d.get(field) for field in COMPANY_FIELDS if field in json_d} if len(company) == 0: return send_error(request, 400) company['updated'] = datetime.now() result = mongo.db.company.update_one({'abbreviation': abbr}, {'$set': company}) return send_response(request, {'status': 'OK', 'updated': result.modified_count}) elif request.method == 'DELETE': #TODO: check owner result = mongo.db.company.delete_one({'abbreviation': abbr}) return send_response(request, {'abbreviation': abbr, 'deleted': result.deleted_count})
def identify_view(): auth_header = request.headers.environ.get('HTTP_AUTHORIZATION', '') if not auth_header.startswith('Bearer'): return send_error(request, 403) token = auth_header[7:] grant = mongo.db.OAuth2Access.find({ 'access_token': token, 'expires': { '$gt': datetime.now() } }) if grant.count() == 0: return send_error(request, 403) grant = cursor_to_list(grant)[0] user_cursor = mongo.db.user.find({'email': grant['user']}) if user_cursor.count() != 1: return send_error(request, 403) user_data = cursor_to_list(user_cursor)[0] return send_response(request, {'status': 'OK', 'data': user_data})
def create_company_view(): """ curl -X POST -H "Content-Type: application/json" 'http://127.0.0.1:9092/company/' \ -d '{"abbreviation": "TTS", "name": "Transport Travel System", "info": null, "user": "******"}' """ #TODO: create with owner json_s = request.get_json() if json_s is None: return send_error(request, 400) json_d = json.loads(json_s) if json_d is None: return send_error(request, 400) company = {field: json_d.get(field) for field in COMPANY_FIELDS} found = mongo.db.company.find({'abbreviation': company['abbreviation']}).count() if found > 0: return send_response(request, {'status': 'Such abbr already exists'}) company['created'] = datetime.now() mongo.db.company.insert(company) return send_response(request, {'status': 'OK', 'data': company})
def register_account(): """ This method should add another user :return: A notification of successful """ params = {'username': fields.String(), 'password': fields.String()} json_data = parse_req(params) try: username = json_data.get('username', None) password = json_data.get('password', None) except: return send_error(code=500) query_account = {'username': username, 'password': password} find_username = userRegister.find({}, {'username': 1, '_id': 0}) for user in find_username: if user['username'] == username: return jsonify("This account is already exist !") try: result = userRegister.insert_one(query_account) return send_result(result) except: return send_error(code=500)
def delete(self, meme_id): ''' Remove your vote for the requested meme ''' netid = flask.g.netid vote = Vote.query.filter_by( netid=netid, meme_id=meme_id).first() if vote: db.session.delete(vote) db.session.commit() logger.info("Deleted vote for %s by %s" % (flask.g.netid, meme_id)) return send_success("Deleted vote for %s" % meme_id) else: logger.info("%s tried to delete non-existant vote for %s" % (flask.g.netid, meme_id)) return send_error("You haven't voted for meme %s" % meme_id)
def companies_view(): """ curl -X GET 'http://localhost:9092/companies/?size=2&page=2' """ find_params = {} email = request.headers.environ.get('HTTP_X_EMAIL') if email: find_params['user'] = email try: companies = mongo.db.company.find(find_params).sort('created', DESCENDING) result = paginate(request, data=companies) return send_response(request, result) except Error as e: return send_error(request, e.code)
def delete_post_by_id(): """ This method should delete a post by its id in db :return: a notification of successful or error """ param_id = request.args.get('_id', None) query_id = { '_id': param_id } find_id = news.find(query_id) if find_id is None: return jsonify("_id doesn't exist!") try: result = news.delete_one(query_id) return send_result(result) except: return send_error(code=500)
def post(self, id=None): ''' Endpoint for creating a new transaction Creates a new Transaction record and updates the associated User record's balance ''' parser = reqparse.RequestParser() parser.add_argument('netid', location='json', required=True, type=validate_netid) parser.add_argument('amount', location='json', required=True, type=float) parser.add_argument('description', location='json', default='') parser.add_argument('Credits-Token', location='headers', required=True, type=netid_from_token, dest='admin_netid') args = parser.parse_args() # Require an admin session token to create transactions if not is_admin(args.admin_netid): return send_error("Must be admin to delete transaction", 403) transaction = Transaction(netid=args.netid, amount=args.amount, description=args.description) user = get_user(args.netid) user.balance += args.amount db.session.add(user) db.session.add(transaction) db.session.commit() return jsonify(transaction.serialize())
def execute(self, authorization: str, batch_id: int): log.info('Start execution of batch Id %i.', batch_id) # Get list of indicator sessions log.debug('Get list of indicator sessions.') query = 'query{allSessions(condition:{batchId:batch_id},orderBy:ID_ASC){nodes{id,batchId,indicatorId,userGroupId,indicatorByIndicatorId{name,indicatorTypeId,indicatorTypeByIndicatorTypeId{module,class,method},parametersByIndicatorId{nodes{parameterTypeId,value}}}}}}' query = query.replace( 'batch_id', str(batch_id) ) # Use replace() instead of format() because of curly braces query = {'query': query} # Convert to dictionary response = utils.execute_graphql_request(authorization, query) if response['data']['allSessions']['nodes']: # Update batch status to running log.debug('Update batch status to Running.') self.update_batch_status(authorization, batch_id, 'Running') is_error = False # Variable used to update batch status to Failed if one indicator fails # For each indicator session execute corresponding method for session in response['data']['allSessions']['nodes']: try: module_name = session['indicatorByIndicatorId'][ 'indicatorTypeByIndicatorTypeId']['module'] class_name = session['indicatorByIndicatorId'][ 'indicatorTypeByIndicatorTypeId']['class'] method_name = session['indicatorByIndicatorId'][ 'indicatorTypeByIndicatorTypeId']['method'] class_instance = getattr(sys.modules[module_name], class_name)() getattr(class_instance, method_name)(authorization, session) except Exception: # pylint: disable=broad-except is_error = True error_message = traceback.format_exc() log.error(error_message) # Update session status session_id = session['id'] update_session_status(authorization, session_id, 'Failed') # Get error context and send error e-mail indicator_id = session['indicatorId'] indicator_name = session['indicatorByIndicatorId']['name'] for parameter in session['indicatorByIndicatorId'][ 'parametersByIndicatorId']['nodes']: if parameter[ 'parameterTypeId'] == 3: # Distribution list distribution_list = literal_eval( parameter['value']) utils.send_error(indicator_id, indicator_name, session_id, distribution_list, error_message) # Update batch status if is_error: log.debug('Update batch status to Failed.') self.update_batch_status(authorization, batch_id, 'Failed') log.warning('Batch Id %i completed with errors.', batch_id) else: log.debug('Update batch status to Success.') self.update_batch_status(authorization, batch_id, 'Success') log.info('Batch Id %i completed successfully.', batch_id) else: error_message = f'Batch Id {batch_id} does not exist or has no indicator session.' log.error(error_message) raise Exception(error_message)
def execute(self, authorization: str, batch_id: int): log.info('Start execution of batch Id %i.', batch_id) # Get list of indicator sessions log.debug('Get list of indicator sessions.') query = 'query getAllSessions($batchId: Int){allSessions(condition:{batchId: $batchId}, orderBy:ID_ASC){nodes{id, batchId, indicatorId, userGroupId, indicatorByIndicatorId{name, indicatorTypeId, indicatorTypeByIndicatorTypeId{module, class, method}, parametersByIndicatorId{nodes{parameterTypeId, value}}}}}}' variables = {'batchId': batch_id} payload = {'query': query, 'variables': variables} response = utils.execute_graphql_request(authorization, payload) if response['data']['allSessions']['nodes']: # Update batch status to running log.debug('Update batch status to Running.') self.update_batch_status(authorization, batch_id, 'Running') is_error = False # Variable used to update batch status to Failed if one indicator fails # Loop over each indicator session for session in response['data']['allSessions']['nodes']: try: # Recreate custom log handler to add session Id to context root_log = logging.getLogger() custom_handler = root_log.handlers[1] root_log.removeHandler(custom_handler) root_log.addHandler( utils.CustomLogHandler(authorization, batch_id=batch_id, session_id=session['id'])) # For each session execute indicator type method module_name = session['indicatorByIndicatorId'][ 'indicatorTypeByIndicatorTypeId']['module'] class_name = session['indicatorByIndicatorId'][ 'indicatorTypeByIndicatorTypeId']['class'] method_name = session['indicatorByIndicatorId'][ 'indicatorTypeByIndicatorTypeId']['method'] class_instance = getattr(sys.modules[module_name], class_name)() getattr(class_instance, method_name)(authorization, session) except Exception: # pylint: disable=broad-except is_error = True error_message = traceback.format_exc() log.error(error_message) # Update session status session_id = session['id'] Session().update_session_status(authorization, session_id, 'Failed') # Get error context and send error e-mail indicator_id = session['indicatorId'] indicator_name = session['indicatorByIndicatorId']['name'] for parameter in session['indicatorByIndicatorId'][ 'parametersByIndicatorId']['nodes']: if parameter[ 'parameterTypeId'] == 3: # Distribution list distribution_list = literal_eval( parameter['value']) utils.send_error(indicator_id, indicator_name, session_id, distribution_list, error_message) # Update batch status if is_error: log.debug('Update batch status to Failed.') self.update_batch_status(authorization, batch_id, 'Failed') log.warning('Batch Id %i completed with errors.', batch_id) else: log.debug('Update batch status to Success.') self.update_batch_status(authorization, batch_id, 'Success') log.info('Batch Id %i completed successfully.', batch_id) else: error_message = f'Batch Id {batch_id} does not exist or has no indicator session.' log.error(error_message) raise Exception(error_message)
def authorize_view(): if request.method == 'GET': auth = session.get('email') if not auth: redirect_uri = '/login/?next=%s' % quote(request.url) return redirect(redirect_uri) # print('email found\n'); client_id = request.args.get('client_id') response_type = request.args.get('response_type') if not client_id or response_type.lower() != 'code': return send_error(request, 400) # print('client id found\n') codes = mongo.db.OAuth2Code.find({ 'client_id': client_id, 'user': auth, 'expires': { '$gt': datetime.now() } }) if codes.count() > 0: token = generate_token() expires = datetime.now() + timedelta(seconds=60) mongo.db.OAuth2Code.update_one( { 'client_id': client_id, 'user': auth }, { 'token': token, 'expires': expires }) redirect_uri = request.form.get( 'redirect_uri') + '?code=%s' % token return redirect(redirect_uri) # print('redirect!\n') form_values = { 'client_id': client_id, 'response_type': response_type, 'redirect_uri': OAUTH2_APPS.get(client_id, {}).get('callback_uri'), } return render_template('accept.html', **form_values) elif request.method == 'POST': allow = request.form.get('allow') if not allow: return redirect('/login/') # print('authentificated!') token = { 'token': generate_token(), 'expires': datetime.now() + timedelta(seconds=600), 'user': session.get('email'), 'app': request.form.get('client_id'), } mongo.db.OAuth2Code.insert(token) redirect_uri = request.form.get( 'redirect_uri') + '?code=%s' % token['token'] # print('redirect uri created!\n') return redirect(redirect_uri)
def reject_failed_admin(): logger.info("Rejecting admin request from %s" % flask.g.netid) return send_error("Nice try memelord, " "but I can't let you do that.", 403)