def setup(cls: "ErrorView", manager: "pysite.route_manager.RouteManager", blueprint: Blueprint): """ Set up the view by registering it as the error handler for the HTTP status codes specified in the class attributes - this will also deal with multiple inheritance by calling `super().setup()` as appropriate. :param manager: Instance of the current RouteManager :param blueprint: Current Flask blueprint to register the error handler for """ if hasattr(super(), "setup"): super().setup(manager, blueprint) # pragma: no cover if not cls.name or not cls.error_code: raise RuntimeError( "Error views must have both `name` and `error_code` defined") if isinstance(cls.error_code, int): cls.error_code = [cls.error_code] if isinstance(cls.error_code, Iterable): for code in cls.error_code: if isinstance(code, int) and code not in default_exceptions: continue # Otherwise we'll possibly get an exception thrown during blueprint registration if cls.register_on_app: manager.app.errorhandler(code)(cls.as_view(cls.name)) else: blueprint.errorhandler(code)(cls.as_view(cls.name)) else: raise RuntimeError( "Error views must have an `error_code` that is either an `int` or an iterable" ) # pragma: no cover # noqa: E501
def create_api_blueprint(name, import_name, url_prefix=None, jsonize=True, handle_http_error=True): """ 幺蛾子, 就是因为flask写API挂路由太累了, 搞了这么个东西. 会把url_prefix挂到/api/下. 比如url_prefix是test, 那么route全部在/api/test下 """ if url_prefix and url_prefix.startswith('/'): raise URLPrefixError('url_prefix ("%s") must not start with /' % url_prefix) bp_url_prefix = '/api/' if url_prefix: bp_url_prefix = os.path.join(bp_url_prefix, url_prefix) bp = Blueprint(name, import_name, url_prefix=bp_url_prefix) if handle_http_error: def _error_hanlder(error): return jsonify({'error': error.description}), error.code for code in ERROR_CODES: bp.errorhandler(code)(_error_hanlder) # 如果不需要自动帮忙jsonize, 就不要 # 可能的场景比如返回一个stream if jsonize: patch_blueprint_route(bp) return bp
def create_page_blueprint(name, import_name, url_prefix=None): bp = Blueprint(name, import_name, url_prefix=url_prefix) def _error_hanlder(error): return render_template('/error/%s.mako' % error.code, err=error) for code in ERROR_CODES: bp.errorhandler(code)(_error_hanlder) return bp
def create_api_blueprint(name, import_name, url_prefix=None): bp = Blueprint(name, import_name, url_prefix=url_prefix) def _error_hanlder(error): return jsonify({"error": error.description}), error.code for code in ERROR_CODES: bp.errorhandler(code)(_error_hanlder) patch_blueprint_route(bp) return bp
def create_ajax_blueprint(name, import_name, url_prefix=None): bp = Blueprint(name, import_name, url_prefix=url_prefix) def _error_hanlder(error): return jsonify({'error': error.description}), error.code for code in ERROR_CODES: bp.errorhandler(code)(_error_hanlder) patch_blueprint_route(bp) return bp
def create_blueprint(endpoints): """Create Invenio-Deposit-REST blueprint.""" blueprint = Blueprint( 'b2share_deposit_rest', __name__, url_prefix='', ) blueprint.errorhandler(PIDInvalidAction)(create_api_errorhandler( status=403, message='Invalid action')) blueprint.errorhandler(InvalidOperationError)(create_api_errorhandler( status=403, message='Invalid operation')) for endpoint, options in (endpoints or {}).items(): for rule in records_rest_url_rules(endpoint, **options): blueprint.add_url_rule(**rule) return blueprint
def create_blueprint(endpoints): """Create Invenio-Deposit-REST blueprint.""" blueprint = Blueprint( 'b2share_deposit_rest', __name__, url_prefix='', ) blueprint.errorhandler(PIDInvalidAction)(create_api_errorhandler( status=403, message='Invalid action' )) blueprint.errorhandler(InvalidOperationError)(create_api_errorhandler( status=403, message='Invalid operation' )) for endpoint, options in (endpoints or {}).items(): for rule in records_rest_url_rules(endpoint, **options): blueprint.add_url_rule(**rule) return blueprint
return apology(message="subject doesn't exist") db.execute("DELETE FROM subjects WHERE user_id = :id AND subject = :s AND type = :t AND lecturer = :l AND day = :d AND place = :p AND start_time = :st AND end_time = :e", {"id": session["user_id"], "s": s, "t": t, "l": l, "d": d, "p": p, "st": st, "e": e}) db.commit() # Update session['subjects'] (used in navbar and filling forms) because this might be the last period of the subject (which deletes it entirely) subject_count = db.execute("SELECT COUNT(subject) FROM subjects WHERE user_id = :id AND subject = :s", {"id": session["user_id"], 's': s}).fetchone()[0] if subject_count == 0: session["subjects"] = rowproxy_to_dict(db.execute("SELECT DISTINCT subject FROM subjects WHERE user_id = :id ORDER BY subject", {"id": session["user_id"]}).fetchall()) # Delete the subject's dues db.execute("DELETE FROM dues WHERE user_id = :id AND subject = :s", {"id": session["user_id"], "s": s}) # Delete the subjetc's notes db.execute("DELETE FROM notes WHERE user_id = :id AND subject = :s", {"id": session["user_id"], "s": s}) db.commit() flash("Period deleted!") return redirect("/schedule") def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code) # Listen for errors for code in default_exceptions: periods.errorhandler(code)(errorhandler)
from . import core, ext from ._compat import text_type from .core import CtfException bp = Blueprint('api', __name__) ext.csrf.exempt(bp) def handle_error(exc): return jsonify({'message': exc.description}), exc.code for code in exceptions.default_exceptions.keys(): if code != 500: bp.errorhandler(code)(handle_error) def param(key, desired_type=None): """Return a decorator to parse a JSON request value.""" def decorator(view_func): """The actual decorator""" @wraps(view_func) def inner(*args, **kwargs): data = request.get_json() # May raise a 400 try: value = data[key] except (KeyError, TypeError): abort(400, "Missing JSON value '{0}'.".format(key)) if desired_type and not isinstance(value, desired_type): # For the error message
def setup(cls: "ErrorView", blueprint: Blueprint): if not cls.name or not cls.error_code: raise RuntimeError( "Error views must have both `name` and `error_code` defined") blueprint.errorhandler(cls.error_code)(cls.as_view(cls.name))
else: return apology("must enter stock ticker symbol", 403) # request symbol information from IEX cloud quoteInfo = lookup(symbol) # redirect to buy page with error message if no symbol was found if quoteInfo is None: return apology( "The symbol was not found or something else went wrong.", 403) # get number of owned stocks and average price of aquisition for row in holdings: if symbol == row.symbol: sharesOwned = row.shares avgPrice = row.avgprice amount = row.total break # load sell page with stock ticker information filled in return render_template("sell.html", quoteInfo=quoteInfo, sharesOwned=sharesOwned, avgPrice=avgPrice, amount=amount) # Listen for errors for code in default_exceptions: transactions.errorhandler(code)(errorhandler)
from app.main import errors auth = Blueprint('auth', __name__) auth.add_url_rule('/login/', 'login', views.login, methods=['GET', 'POST']) auth.add_url_rule('/logout/', 'logout', views.logout) auth.add_url_rule('/registration/', 'register', views.register, methods=['GET', 'POST']) auth.add_url_rule('/registration/su', 'register_su', views.register, defaults={'create_su': True}, methods=['GET', 'POST']) auth.add_url_rule('/add-user/', 'add_user', views.add_user, methods=['GET', 'POST']) auth.add_url_rule('/users/', view_func=views.Users.as_view('users')) auth.add_url_rule('/users/edit/<username>', view_func=views.User.as_view('edit_user')) auth.add_url_rule('/su-users/', view_func=views.SuUsers.as_view('su_users')) auth.add_url_rule('/su-users/edit/<username>', view_func=views.SuUser.as_view('su_edit_user')) auth.add_url_rule('/user/settings/', view_func=views.Profile.as_view('settings')) auth.add_url_rule('/user/password/', view_func=views.Password.as_view('password')) auth.errorhandler(403)(errors.handle_forbidden)
}).fetchone() if not diary: return error_page("Diary doesn't exist") with open('diary.md', 'w') as d: header = f"{diary['title']}\nby {username}.\n{diary['date']}\nThat day was {diary['rating']}.\n" d.write(header) d.write(diary['diary']) return send_file('diary.md', as_attachment=True) @diary.route('/public_diaries') @login_required def public_diaries(): diaries = db.execute("""SELECT title, rating, diary, date, username FROM diaries JOIN users ON diaries.user_id = users.id WHERE users.visibility = '1' ORDER BY date DESC""" ).fetchall() return render_template('public_diaries.html', diaries=diaries) def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code) # Listen for errors for code in default_exceptions: diary.errorhandler(code)(errorhandler)
from flask import Blueprint from . import views from utils import errors main = Blueprint('main', __name__) main.errorhandler(404)(errors.page_not_found) main.errorhandler(401)(errors.handle_unauthorized) main.add_url_rule('/', view_func=views.IndexView.as_view('index')) main.add_url_rule('/enterprise/', view_func=views.EnterpriseView.as_view('enterprise')) main.add_url_rule('/users/<username>/', view_func=views.UserView.as_view('user_view')) # main.add_url_rule('/test-celery/', 'test-celery', views.test_celery) # main.add_url_rule('/test/', 'test', views.test) main.add_url_rule('/import-repo/', view_func=views.ImportRepoView.as_view('import_repo'), defaults={'starred':True}) main.add_url_rule('/starred-repos/', view_func=views.StarredRepoView.as_view('starred_repos')) main.add_url_rule('/users/<username>/starred-repos/', view_func=views.StarredRepoView.as_view('user_starred_repos')) main.add_url_rule('/all-repos/', view_func=views.ReposView.as_view('all_repos')) main.add_url_rule('/search/github/', view_func=views.GitHubResultView.as_view('github_result')) main.add_url_rule('/user/collections/', view_func=views.MyCollectionsView.as_view('my_collections')) main.add_url_rule('/users/<username>/collections/', view_func=views.UserCollectionsView.as_view('user_collections')) main.add_url_rule('/user/collections/<collection_id>/edit/', view_func=views.MyCollectionEditView.as_view('edit_collection')) main.add_url_rule('/user/collections/<collection_id>/detail/', view_func=views.CollectionView.as_view('collection_detail')) main.add_url_rule('/user/collections/<collection_id>/detail/edit/', view_func=views.CollectionDetailEditView.as_view('collection_detail_edit')) main.add_url_rule('/user/collections/<collection_id>/detail/edit/search', view_func=views.Search4Collection.as_view('collection_detail_edit_search'))
return render_template("feedback.html") else: feedback_type = request.form.get("type") email = request.form.get("email") feedback = request.form.get("feedback") if not (feedback_type or email or feedback): return apology("please fill the form") db.execute( "INSERT INTO feedback (user_id, email, feedback, feedback_type) VALUES(:id, :email, :feedback, :type)", { "id": session["user_id"], "email": email, "feedback": feedback, "type": feedback_type }) db.commit() flash("Feedback submitted! Thanks for your feedback!") return redirect("/") def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code) # Listen for errors for code in default_exceptions: settings.errorhandler(code)(errorhandler)
'message': error.description, 'id': error.id, } status_code = error.code elif isinstance(error, HTTPException): message = error.description status_code = error.code error_data = { 'message': message, 'id': "internal", 'code': status_code } else: message = "Unknown error" status_code = 500 error_data = { 'message': message, 'id': "internal", 'code': status_code } response = jsonify(status='error', error=error_data) response.status_code = status_code return response for code, _ in default_exceptions.items(): auth_bp.app_errorhandler(code)(error_handler) auth_bp.errorhandler(code)(error_handler)
def as_blueprint(self) -> Blueprint: bp = Blueprint('athena_controllers', __name__) bp.route('/')(self.index_handler) bp.route('/du')(self.du_handler) bp.errorhandler(HTTPException)(error_handler) return bp
def create_api_blueprint(name, import_name, url_prefix=None, jsonize=True): """方便创建 api blueprint 增加 4xx 请求处理,返回值 json 化 name, import_name, url_prefix 同 Blueprint jsonize 等于 Ture 时,自动帮忙序列化,反之没有处理 在 debug 模式下,500 的错误不进行处理,走 flask 默认的处理,方便调试 使用: from flask import abort abort(404, 'xxx not found') request 返回 {'msg': 'xxx not found', 'code': 404}, 200 # raise 非自定义错误 raise Exception('xxx') request 返回 {'msg': '服务器错误'}, 500 raise CustomError('error', code, payload) request 返回 {'msg': 'error', 'code': 200, payload}, 200 """ if url_prefix and url_prefix.startswith('/'): raise URLPrefixError( 'url_prefix ("{}") must not start with /'.format(url_prefix)) bp_url_prefix = '/api/' if url_prefix: bp_url_prefix = os.path.join(bp_url_prefix, url_prefix) bp = Blueprint(name, import_name, url_prefix=bp_url_prefix) def _error_hanlder(error): print(error) # 处理自定义错误 if issubclass(error.__class__, CustomError): return jsonify(error.to_dict()) # 处理 abort 错误 if isinstance(error, HTTPException): return jsonify({ 'msg': error.description, 'code': error.code, }) if isinstance(error, JWTError): return jsonify({'msg': error.description, 'code': 401}) # 处理其他错误 return jsonify({ 'msg': '服务器错误', 'code': INTERNAL_SERVER_ERROR, }), INTERNAL_SERVER_ERROR for code in ERROR_CODES: bp.errorhandler(code)(_error_hanlder) bp.errorhandler(CustomError)(_error_hanlder) bp.errorhandler(JWTError)(_error_hanlder) if not DEBUG: bp.errorhandler(INTERNAL_SERVER_ERROR)(_error_hanlder) if jsonize: patch_blueprint_route(bp) return bp
def make_blueprint(config: SDConfig) -> Blueprint: api = Blueprint("api", __name__) @api.route("/") def get_endpoints() -> Tuple[flask.Response, int]: endpoints = { "sources_url": "/api/v1/sources", "current_user_url": "/api/v1/user", "all_users_url": "/api/v1/users", "submissions_url": "/api/v1/submissions", "replies_url": "/api/v1/replies", "seen_url": "/api/v1/seen", "auth_token_url": "/api/v1/token", } return jsonify(endpoints), 200 # Before every post, we validate the payload before processing the request @api.before_request def validate_data() -> None: if request.method == "POST": # flag, star, and logout can have empty payloads if not request.data: dataless_endpoints = [ "add_star", "remove_star", "flag", "logout", ] for endpoint in dataless_endpoints: if request.endpoint == "api." + endpoint: return abort(400, "malformed request") # other requests must have valid JSON payload else: try: json.loads(request.data.decode("utf-8")) except (ValueError): abort(400, "malformed request") @api.route("/token", methods=["POST"]) def get_token() -> Tuple[flask.Response, int]: creds = json.loads(request.data.decode("utf-8")) username = creds.get("username", None) passphrase = creds.get("passphrase", None) one_time_code = creds.get("one_time_code", None) if username is None: abort(400, "username field is missing") if passphrase is None: abort(400, "passphrase field is missing") if one_time_code is None: abort(400, "one_time_code field is missing") try: journalist = Journalist.login(username, passphrase, one_time_code) token_expiry = datetime.now( timezone.utc) + timedelta(seconds=TOKEN_EXPIRATION_MINS * 60) response = jsonify({ "token": journalist.generate_api_token( expiration=TOKEN_EXPIRATION_MINS * 60), "expiration": token_expiry, "journalist_uuid": journalist.uuid, "journalist_first_name": journalist.first_name, "journalist_last_name": journalist.last_name, }) # Update access metadata journalist.last_access = datetime.now(timezone.utc) db.session.add(journalist) db.session.commit() return response, 200 except ( LoginThrottledException, InvalidUsernameException, BadTokenException, InvalidOTPSecretException, WrongPasswordException, ): return abort(403, "Token authentication failed.") @api.route("/sources", methods=["GET"]) @token_required def get_all_sources() -> Tuple[flask.Response, int]: sources = Source.query.filter_by(pending=False, deleted_at=None).all() return jsonify({"sources": [source.to_json() for source in sources]}), 200 @api.route("/sources/<source_uuid>", methods=["GET", "DELETE"]) @token_required def single_source(source_uuid: str) -> Tuple[flask.Response, int]: if request.method == "GET": source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify(source.to_json()), 200 elif request.method == "DELETE": source = get_or_404(Source, source_uuid, column=Source.uuid) utils.delete_collection(source.filesystem_id) return jsonify({"message": "Source and submissions deleted"}), 200 else: abort(405) @api.route("/sources/<source_uuid>/add_star", methods=["POST"]) @token_required def add_star(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) utils.make_star_true(source.filesystem_id) db.session.commit() return jsonify({"message": "Star added"}), 201 @api.route("/sources/<source_uuid>/remove_star", methods=["DELETE"]) @token_required def remove_star(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) utils.make_star_false(source.filesystem_id) db.session.commit() return jsonify({"message": "Star removed"}), 200 @api.route("/sources/<source_uuid>/flag", methods=["POST"]) @token_required def flag(source_uuid: str) -> Tuple[flask.Response, int]: return jsonify( {"message": "Sources no longer need to be flagged for reply"}), 200 @api.route("/sources/<source_uuid>/conversation", methods=["DELETE"]) @token_required def source_conversation(source_uuid: str) -> Tuple[flask.Response, int]: if request.method == "DELETE": source = get_or_404(Source, source_uuid, column=Source.uuid) utils.delete_source_files(source.filesystem_id) return jsonify({"message": "Source data deleted"}), 200 else: abort(405) @api.route("/sources/<source_uuid>/submissions", methods=["GET"]) @token_required def all_source_submissions(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) return ( jsonify({ "submissions": [submission.to_json() for submission in source.submissions] }), 200, ) @api.route("/sources/<source_uuid>/submissions/<submission_uuid>/download", methods=["GET"]) @token_required def download_submission(source_uuid: str, submission_uuid: str) -> flask.Response: get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) return utils.serve_file_with_etag(submission) @api.route("/sources/<source_uuid>/replies/<reply_uuid>/download", methods=["GET"]) @token_required def download_reply(source_uuid: str, reply_uuid: str) -> flask.Response: get_or_404(Source, source_uuid, column=Source.uuid) reply = get_or_404(Reply, reply_uuid, column=Reply.uuid) return utils.serve_file_with_etag(reply) @api.route("/sources/<source_uuid>/submissions/<submission_uuid>", methods=["GET", "DELETE"]) @token_required def single_submission(source_uuid: str, submission_uuid: str) -> Tuple[flask.Response, int]: if request.method == "GET": get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) return jsonify(submission.to_json()), 200 elif request.method == "DELETE": get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) utils.delete_file_object(submission) return jsonify({"message": "Submission deleted"}), 200 else: abort(405) @api.route("/sources/<source_uuid>/replies", methods=["GET", "POST"]) @token_required def all_source_replies(source_uuid: str) -> Tuple[flask.Response, int]: if request.method == "GET": source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify( {"replies": [reply.to_json() for reply in source.replies]}), 200 elif request.method == "POST": source = get_or_404(Source, source_uuid, column=Source.uuid) if request.json is None: abort(400, "please send requests in valid JSON") if "reply" not in request.json: abort(400, "reply not found in request body") user = _authenticate_user_from_auth_header(request) data = request.json if not data["reply"]: abort(400, "reply should not be empty") source.interaction_count += 1 try: filename = Storage.get_default().save_pre_encrypted_reply( source.filesystem_id, source.interaction_count, source.journalist_filename, data["reply"], ) except NotEncrypted: return jsonify( {"message": "You must encrypt replies client side"}), 400 # issue #3918 filename = path.basename(filename) reply = Reply(user, source, filename, Storage.get_default()) reply_uuid = data.get("uuid", None) if reply_uuid is not None: # check that is is parseable try: UUID(reply_uuid) except ValueError: abort(400, "'uuid' was not a valid UUID") reply.uuid = reply_uuid try: db.session.add(reply) seen_reply = SeenReply(reply=reply, journalist=user) db.session.add(seen_reply) db.session.add(source) db.session.commit() except IntegrityError as e: db.session.rollback() if "UNIQUE constraint failed: replies.uuid" in str(e): abort(409, "That UUID is already in use.") else: raise e return ( jsonify({ "message": "Your reply has been stored", "uuid": reply.uuid, "filename": reply.filename, }), 201, ) else: abort(405) @api.route("/sources/<source_uuid>/replies/<reply_uuid>", methods=["GET", "DELETE"]) @token_required def single_reply(source_uuid: str, reply_uuid: str) -> Tuple[flask.Response, int]: get_or_404(Source, source_uuid, column=Source.uuid) reply = get_or_404(Reply, reply_uuid, column=Reply.uuid) if request.method == "GET": return jsonify(reply.to_json()), 200 elif request.method == "DELETE": utils.delete_file_object(reply) return jsonify({"message": "Reply deleted"}), 200 else: abort(405) @api.route("/submissions", methods=["GET"]) @token_required def get_all_submissions() -> Tuple[flask.Response, int]: submissions = Submission.query.all() return ( jsonify({ "submissions": [ submission.to_json() for submission in submissions if submission.source ] }), 200, ) @api.route("/replies", methods=["GET"]) @token_required def get_all_replies() -> Tuple[flask.Response, int]: replies = Reply.query.all() return jsonify({ "replies": [reply.to_json() for reply in replies if reply.source] }), 200 @api.route("/seen", methods=["POST"]) @token_required def seen() -> Tuple[flask.Response, int]: """ Lists or marks the source conversation items that the journalist has seen. """ user = _authenticate_user_from_auth_header(request) if request.method == "POST": if request.json is None or not isinstance(request.json, collections.abc.Mapping): abort(400, "Please send requests in valid JSON.") if not any(map(request.json.get, ["files", "messages", "replies"])): abort(400, "Please specify the resources to mark seen.") # gather everything to be marked seen. if any don't exist, # reject the request. targets = set() # type: Set[Union[Submission, Reply]] for file_uuid in request.json.get("files", []): f = Submission.query.filter( Submission.uuid == file_uuid).one_or_none() if f is None or not f.is_file: abort(404, "file not found: {}".format(file_uuid)) targets.add(f) for message_uuid in request.json.get("messages", []): m = Submission.query.filter( Submission.uuid == message_uuid).one_or_none() if m is None or not m.is_message: abort(404, "message not found: {}".format(message_uuid)) targets.add(m) for reply_uuid in request.json.get("replies", []): r = Reply.query.filter(Reply.uuid == reply_uuid).one_or_none() if r is None: abort(404, "reply not found: {}".format(reply_uuid)) targets.add(r) # now mark everything seen. utils.mark_seen(list(targets), user) return jsonify({"message": "resources marked seen"}), 200 abort(405) @api.route("/user", methods=["GET"]) @token_required def get_current_user() -> Tuple[flask.Response, int]: user = _authenticate_user_from_auth_header(request) return jsonify(user.to_json()), 200 @api.route("/users", methods=["GET"]) @token_required def get_all_users() -> Tuple[flask.Response, int]: users = Journalist.query.all() return jsonify( {"users": [user.to_json(all_info=False) for user in users]}), 200 @api.route("/logout", methods=["POST"]) @token_required def logout() -> Tuple[flask.Response, int]: user = _authenticate_user_from_auth_header(request) auth_token = request.headers["Authorization"].split(" ")[1] utils.revoke_token(user, auth_token) return jsonify({"message": "Your token has been revoked."}), 200 def _handle_api_http_exception( error: werkzeug.exceptions.HTTPException, ) -> Tuple[flask.Response, int]: # Workaround for no blueprint-level 404/5 error handlers, see: # https://github.com/pallets/flask/issues/503#issuecomment-71383286 response = jsonify({"error": error.name, "message": error.description}) return response, error.code # type: ignore for code in default_exceptions: api.errorhandler(code)(_handle_api_http_exception) return api
from flask import Blueprint from . import views, errors main = Blueprint('main', __name__) main.add_url_rule('/', 'index', views.index, methods=['GET']) main.add_url_rule('/show_more', 'show_more', views.show_more, methods=['POST']) main.errorhandler(404)(errors.page_not_found) main.add_url_rule('/<path:invalid_path>', 'handle_unmatchable', errors.handle_unmatchable)
"s": subject, "n": note }) db.commit() except Exception as x: return apology(x) flash("Note deleted!") return redirect("/notes") @notes.route("/delete/notes", methods=["POST"]) @login_required def delete_notes(): db.execute("DELETE FROM notes WHERE user_id = :id", {"id": session["user_id"]}) db.commit() flash("All notes deleted!") return redirect("/") def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code) # Listen for errors for code in default_exceptions: notes.errorhandler(code)(errorhandler)
current = Users.query.filter(Users.id == user_id).first() if operation == "add": new_amount = current.cash + amount message = "You successfully added funds to your account" if operation == "withdraw": if amount > current.cash: return apology( "The amount of cash in your account is not enough", 403) new_amount = current.cash - amount message = "You successfully withdrew funds from your account" # Udate cash amount in database current.cash = new_amount db.session.commit() # Flash success message flash(message) # Redirect user to home page return redirect(url_for("home.index")) else: return redirect(url_for("admin.account")) # Listen for errors for code in default_exceptions: admin.errorhandler(code)(errorhandler)
from twilio import TwilioRestException from sqlalchemy.exc import SQLAlchemyError from ..extensions import csrf, db from .models import Call, Session from ..campaign.constants import ORDER_SHUFFLE, LOCATION_POSTAL, LOCATION_DISTRICT from ..campaign.models import Campaign, Target from ..political_data.lookup import locate_targets from .decorators import crossdomain, abortJSON, stripANSI call = Blueprint('call', __name__, url_prefix='/call') call_methods = ['GET', 'POST'] csrf.exempt(call) call.errorhandler(400)(abortJSON) def play_or_say(r, audio, **kwds): """ Take twilio response and play or say message from an AudioRecording Can use mustache templates to render keyword arguments """ if audio: if (hasattr(audio, 'text_to_speech') and not (audio.text_to_speech == '')): msg = pystache.render(audio.text_to_speech, kwds) r.say(msg) elif (hasattr(audio, 'file_storage') and (audio.file_storage.fp is not None)): r.play(audio.file_url()) elif type(audio) == str:
def create_blueprint(endpoints): """Create Invenio-Deposit-REST blueprint.""" blueprint = Blueprint( 'invenio_deposit_rest', __name__, url_prefix='', ) blueprint.errorhandler(PIDInvalidAction)(create_api_errorhandler( status=403, message='Invalid action')) blueprint.errorhandler(InvalidOperationError)(create_api_errorhandler( status=403, message='Invalid operation')) blueprint.errorhandler(ValidationError)(create_api_errorhandler( status=400, message='Validation error')) for endpoint, options in (endpoints or {}).items(): options = deepcopy(options) if 'files_serializers' in options: files_serializers = options.get('files_serializers') files_serializers = { mime: obj_or_import_string(func) for mime, func in files_serializers.items() } del options['files_serializers'] else: files_serializers = {} if 'record_serializers' in options: serializers = options.get('record_serializers') serializers = { mime: obj_or_import_string(func) for mime, func in serializers.items() } else: serializers = {} file_list_route = options.pop( 'file_list_route', '{0}/files'.format(options['item_route'])) file_item_route = options.pop( 'file_item_route', '{0}/files/<path:key>'.format(options['item_route'])) options.setdefault('search_class', DepositSearch) search_class = obj_or_import_string(options['search_class']) # records rest endpoints will use the deposit class as record class options.setdefault('record_class', Deposit) record_class = obj_or_import_string(options['record_class']) for rule in records_rest_url_rules(endpoint, **options): blueprint.add_url_rule(**rule) search_class_kwargs = {} if options.get('search_index'): search_class_kwargs['index'] = options['search_index'] if options.get('search_type'): search_class_kwargs['doc_type'] = options['search_type'] ctx = dict( read_permission_factory=obj_or_import_string( options.get('read_permission_factory_imp')), create_permission_factory=obj_or_import_string( options.get('create_permission_factory_imp')), update_permission_factory=obj_or_import_string( options.get('update_permission_factory_imp')), delete_permission_factory=obj_or_import_string( options.get('delete_permission_factory_imp')), record_class=record_class, search_class=partial(search_class, **search_class_kwargs), default_media_type=options.get('default_media_type'), ) deposit_actions = DepositActionResource.as_view( DepositActionResource.view_name.format(endpoint), serializers=serializers, pid_type=options['pid_type'], ctx=ctx, ) blueprint.add_url_rule( '{0}/actions/<any(publish,edit,discard):action>'.format( options['item_route']), view_func=deposit_actions, methods=['POST'], ) deposit_files = DepositFilesResource.as_view( DepositFilesResource.view_name.format(endpoint), serializers=files_serializers, pid_type=options['pid_type'], ctx=ctx, ) blueprint.add_url_rule( file_list_route, view_func=deposit_files, methods=['GET', 'POST', 'PUT'], ) deposit_file = DepositFileResource.as_view( DepositFileResource.view_name.format(endpoint), serializers=files_serializers, pid_type=options['pid_type'], ctx=ctx, ) blueprint.add_url_rule( file_item_route, view_func=deposit_file, methods=['GET', 'PUT', 'DELETE'], ) return blueprint
#!/usr/bin/env python2 # -*- coding: utf-8 -*- from flask import Blueprint from . import views from app.main import errors auth = Blueprint('auth', __name__) auth.add_url_rule('/login/', 'login', views.login, methods=['GET', 'POST']) auth.add_url_rule('/logout/', 'logout', views.logout) auth.add_url_rule('/registration/', 'register', views.register, methods=['GET', 'POST']) auth.add_url_rule('/registration/su', 'register_su', views.register, defaults={'create_su': True}, methods=['GET', 'POST']) auth.add_url_rule('/add-user/', 'add_user', views.add_user, methods=['GET', 'POST']) auth.add_url_rule('/users/', view_func=views.Users.as_view('users')) auth.add_url_rule('/users/edit/<username>', view_func=views.User.as_view('edit_user')) auth.add_url_rule('/su-users/', view_func=views.SuUsers.as_view('su_users')) auth.add_url_rule('/su-users/edit/<username>', view_func=views.SuUser.as_view('su_edit_user')) auth.add_url_rule('/user/settings/', view_func=views.Profile.as_view('settings')) auth.add_url_rule('/user/password/', view_func=views.Password.as_view('password')) auth.errorhandler(403)(errors.handle_forbidden)
accounts = Blueprint('accounts', __name__) accounts.add_url_rule('/login/', 'login', views.login, methods=['GET', 'POST']) accounts.add_url_rule('/logout/', 'logout', views.logout) accounts.add_url_rule('/registration/', 'register', views.register, methods=['GET', 'POST']) accounts.add_url_rule('/registration/su', 'register_su', views.register, defaults={'create_su': True}, methods=['GET', 'POST']) accounts.add_url_rule('/add-user/', 'add_user', views.add_user, methods=['GET', 'POST']) accounts.add_url_rule('/users/', view_func=views.Users.as_view('users')) accounts.add_url_rule('/users/edit/<username>', view_func=views.User.as_view('edit_user')) accounts.add_url_rule('/su-users/', view_func=views.SuUsers.as_view('su_users')) accounts.add_url_rule('/su-users/edit/<username>', view_func=views.SuUser.as_view('su_edit_user')) accounts.add_url_rule('/user/settings/', view_func=views.Profile.as_view('settings')) accounts.add_url_rule('/user/password/', view_func=views.Password.as_view('password')) accounts.errorhandler(403)(errors.handle_forbidden)
def search(): """Search for something (Optional)""" results = '' return render_template("results.html", results=results) @main.route("/profile") @login_required def profile(): """Display user profile""" # Username and email are already stored in the session, registeration time isn't, you can query for registeration time only instead # Values in profile.html are from this query but you can use the values in the session instead info = db.execute('SELECT * FROM users WHERE id = :id', { 'id': session['user_id'] }).fetchone() return render_template("profile.html", info=info) def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code) # Listen for errors for code in default_exceptions: main.errorhandler(code)(errorhandler)
views.post_detail_general) main.add_url_rule('/pages/<slug>/', 'page_detail', views.post_detail, defaults={'post_type': 'page'}) main.add_url_rule('/wechats/<slug>/', 'wechat_detail', views.post_detail, defaults={'post_type': 'wechat'}) main.add_url_rule('/archive/', 'archive', views.archive) main.add_url_rule('/users/<username>/', 'author_detail', views.author_detail) main.add_url_rule('/atom/', 'recent_feed', views.recent_feed) main.add_url_rule('/sitemap.xml/', 'sitemap', views.sitemap) main.add_url_rule('/uploads/<filename>/', 'uploaded_file', upload.uploaded_file) main.errorhandler(404)(errors.page_not_found) main.errorhandler(401)(errors.handle_unauthorized) main.add_url_rule('/<path:invalid_path>', 'handle_unmatchable', errors.handle_unmatchable) blog_admin = Blueprint('blog_admin', __name__) blog_admin.add_url_rule('/', view_func=admin_views.AdminIndex.as_view('index')) blog_admin.add_url_rule('/posts/', view_func=admin_views.PostsList.as_view('posts')) blog_admin.add_url_rule('/posts/draft/', view_func=admin_views.DraftList.as_view('drafts')) blog_admin.add_url_rule('/new-post/', view_func=admin_views.Post.as_view('new_post')) blog_admin.add_url_rule('/posts/<slug>/',
def create_blueprint(endpoints): """Create Invenio-Deposit-REST blueprint.""" blueprint = Blueprint( 'invenio_deposit_rest', __name__, url_prefix='', ) blueprint.errorhandler(PIDInvalidAction)(create_api_errorhandler( status=403, message='Invalid action' )) blueprint.errorhandler(InvalidOperationError)(create_api_errorhandler( status=403, message='Invalid operation' )) blueprint.errorhandler(ValidationError)(create_api_errorhandler( status=400, message='Validation error' )) for endpoint, options in (endpoints or {}).items(): options = deepcopy(options) if 'files_serializers' in options: files_serializers = options.get('files_serializers') files_serializers = {mime: obj_or_import_string(func) for mime, func in files_serializers.items()} del options['files_serializers'] else: files_serializers = {} if 'record_serializers' in options: serializers = options.get('record_serializers') serializers = {mime: obj_or_import_string(func) for mime, func in serializers.items()} else: serializers = {} file_list_route = options.pop( 'file_list_route', '{0}/files'.format(options['item_route']) ) file_item_route = options.pop( 'file_item_route', '{0}/files/<path:key>'.format(options['item_route']) ) options.setdefault('search_class', DepositSearch) search_class = obj_or_import_string(options['search_class']) # records rest endpoints will use the deposit class as record class options.setdefault('record_class', Deposit) record_class = obj_or_import_string(options['record_class']) for rule in records_rest_url_rules(endpoint, **options): blueprint.add_url_rule(**rule) search_class_kwargs = {} if options.get('search_index'): search_class_kwargs['index'] = options['search_index'] if options.get('search_type'): search_class_kwargs['doc_type'] = options['search_type'] ctx = dict( read_permission_factory=obj_or_import_string( options.get('read_permission_factory_imp') ), create_permission_factory=obj_or_import_string( options.get('create_permission_factory_imp') ), update_permission_factory=obj_or_import_string( options.get('update_permission_factory_imp') ), delete_permission_factory=obj_or_import_string( options.get('delete_permission_factory_imp') ), record_class=record_class, search_class=partial(search_class, **search_class_kwargs), default_media_type=options.get('default_media_type'), ) deposit_actions = DepositActionResource.as_view( DepositActionResource.view_name.format(endpoint), serializers=serializers, pid_type=options['pid_type'], ctx=ctx, ) blueprint.add_url_rule( '{0}/actions/<any(publish,edit,discard):action>'.format( options['item_route'] ), view_func=deposit_actions, methods=['POST'], ) deposit_files = DepositFilesResource.as_view( DepositFilesResource.view_name.format(endpoint), serializers=files_serializers, pid_type=options['pid_type'], ctx=ctx, ) blueprint.add_url_rule( file_list_route, view_func=deposit_files, methods=['GET', 'POST', 'PUT'], ) deposit_file = DepositFileResource.as_view( DepositFileResource.view_name.format(endpoint), serializers=files_serializers, pid_type=options['pid_type'], ctx=ctx, ) blueprint.add_url_rule( file_item_route, view_func=deposit_file, methods=['GET', 'PUT', 'DELETE'], ) return blueprint
from flask import Blueprint from . import views, admin_views, errors main = Blueprint('main', __name__) main.add_url_rule('/', 'index', views.list_posts) main.add_url_rule('/posts/', 'posts', views.list_posts) main.add_url_rule('/posts/<slug>/', 'post_detail', views.post_detail) main.add_url_rule('/post/<slug>/', 'post_detail_fix', views.post_detail, defaults={'fix':True}) main.add_url_rule('/pages/<slug>/', 'page_detail', views.post_detail, defaults={'post_type':'page'}) main.add_url_rule('/archive/', 'archive', views.archive) main.add_url_rule('/users/<username>/', 'author_detail', views.author_detail) main.add_url_rule('/atom/', 'recent_feed', views.recent_feed) main.add_url_rule('/sitemap.xml/', 'sitemap', views.sitemap) main.errorhandler(404)(errors.page_not_found) main.add_url_rule('/<path:invalid_path>', 'handle_unmatchable', errors.handle_unmatchable) blog_admin = Blueprint('blog_admin', __name__) blog_admin.add_url_rule('/', view_func=admin_views.AdminIndex.as_view('index')) blog_admin.add_url_rule('/posts/', view_func=admin_views.PostsList.as_view('posts')) blog_admin.add_url_rule('/new-post/', view_func=admin_views.Post.as_view('new_post')) blog_admin.add_url_rule('/pages/', view_func=admin_views.PostsList.as_view('pages'), defaults={'post_type':'page'}) blog_admin.add_url_rule('/new-page/', view_func=admin_views.Post.as_view('new_page'), defaults={'post_type':'page'}) blog_admin.add_url_rule('/posts/<slug>/', view_func=admin_views.Post.as_view('edit_post')) blog_admin.add_url_rule('/su/posts/', view_func=admin_views.SuPostsList.as_view('su_posts')) blog_admin.add_url_rule('/su/posts/<slug>/', view_func=admin_views.SuPost.as_view('su_post_edit')) blog_admin.errorhandler(404)(errors.admin_page_not_found)
def make_blueprint(config): api = Blueprint('api', __name__) @api.route('/') def get_endpoints(): endpoints = {'sources_url': '/api/v1/sources', 'current_user_url': '/api/v1/user', 'submissions_url': '/api/v1/submissions', 'replies_url': '/api/v1/replies', 'auth_token_url': '/api/v1/token'} return jsonify(endpoints), 200 # Before every post, we validate the payload before processing the request @api.before_request def validate_data(): if request.method == 'POST': # flag, star, and logout can have empty payloads if not request.data: dataless_endpoints = [ 'add_star', 'remove_star', 'flag', 'logout', ] for endpoint in dataless_endpoints: if request.endpoint == 'api.' + endpoint: return return abort(400, 'malformed request') # other requests must have valid JSON payload else: try: json.loads(request.data.decode('utf-8')) except (ValueError): return abort(400, 'malformed request') @api.route('/token', methods=['POST']) def get_token(): creds = json.loads(request.data.decode('utf-8')) username = creds.get('username', None) passphrase = creds.get('passphrase', None) one_time_code = creds.get('one_time_code', None) if username is None: return abort(400, 'username field is missing') if passphrase is None: return abort(400, 'passphrase field is missing') if one_time_code is None: return abort(400, 'one_time_code field is missing') try: journalist = Journalist.login(username, passphrase, one_time_code) token_expiry = datetime.utcnow() + timedelta( seconds=TOKEN_EXPIRATION_MINS * 60) response = jsonify({ 'token': journalist.generate_api_token(expiration=TOKEN_EXPIRATION_MINS * 60), 'expiration': token_expiry.isoformat() + 'Z', 'journalist_uuid': journalist.uuid, 'journalist_first_name': journalist.first_name, 'journalist_last_name': journalist.last_name, }) # Update access metadata journalist.last_access = datetime.utcnow() db.session.add(journalist) db.session.commit() return response, 200 except (LoginThrottledException, InvalidUsernameException, BadTokenException, WrongPasswordException): return abort(403, 'Token authentication failed.') @api.route('/sources', methods=['GET']) @token_required def get_all_sources(): sources = Source.query.filter_by(pending=False).all() return jsonify( {'sources': [source.to_json() for source in sources]}), 200 @api.route('/sources/<source_uuid>', methods=['GET', 'DELETE']) @token_required def single_source(source_uuid): if request.method == 'GET': source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify(source.to_json()), 200 elif request.method == 'DELETE': source = get_or_404(Source, source_uuid, column=Source.uuid) utils.delete_collection(source.filesystem_id) return jsonify({'message': 'Source and submissions deleted'}), 200 @api.route('/sources/<source_uuid>/add_star', methods=['POST']) @token_required def add_star(source_uuid): source = get_or_404(Source, source_uuid, column=Source.uuid) utils.make_star_true(source.filesystem_id) db.session.commit() return jsonify({'message': 'Star added'}), 201 @api.route('/sources/<source_uuid>/remove_star', methods=['DELETE']) @token_required def remove_star(source_uuid): source = get_or_404(Source, source_uuid, column=Source.uuid) utils.make_star_false(source.filesystem_id) db.session.commit() return jsonify({'message': 'Star removed'}), 200 @api.route('/sources/<source_uuid>/flag', methods=['POST']) @token_required def flag(source_uuid): source = get_or_404(Source, source_uuid, column=Source.uuid) source.flagged = True db.session.commit() return jsonify({'message': 'Source flagged for reply'}), 200 @api.route('/sources/<source_uuid>/submissions', methods=['GET']) @token_required def all_source_submissions(source_uuid): source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify( {'submissions': [submission.to_json() for submission in source.submissions]}), 200 @api.route('/sources/<source_uuid>/submissions/<submission_uuid>/download', # noqa methods=['GET']) @token_required def download_submission(source_uuid, submission_uuid): get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) # Mark as downloaded submission.downloaded = True db.session.commit() return utils.serve_file_with_etag(submission) @api.route('/sources/<source_uuid>/replies/<reply_uuid>/download', methods=['GET']) @token_required def download_reply(source_uuid, reply_uuid): get_or_404(Source, source_uuid, column=Source.uuid) reply = get_or_404(Reply, reply_uuid, column=Reply.uuid) return utils.serve_file_with_etag(reply) @api.route('/sources/<source_uuid>/submissions/<submission_uuid>', methods=['GET', 'DELETE']) @token_required def single_submission(source_uuid, submission_uuid): if request.method == 'GET': get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) return jsonify(submission.to_json()), 200 elif request.method == 'DELETE': get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) utils.delete_file_object(submission) return jsonify({'message': 'Submission deleted'}), 200 @api.route('/sources/<source_uuid>/replies', methods=['GET', 'POST']) @token_required def all_source_replies(source_uuid): if request.method == 'GET': source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify( {'replies': [reply.to_json() for reply in source.replies]}), 200 elif request.method == 'POST': source = get_or_404(Source, source_uuid, column=Source.uuid) if request.json is None: abort(400, 'please send requests in valid JSON') if 'reply' not in request.json: abort(400, 'reply not found in request body') user = get_user_object(request) data = request.json if not data['reply']: abort(400, 'reply should not be empty') source.interaction_count += 1 try: filename = current_app.storage.save_pre_encrypted_reply( source.filesystem_id, source.interaction_count, source.journalist_filename, data['reply']) except NotEncrypted: return jsonify( {'message': 'You must encrypt replies client side'}), 400 # issue #3918 filename = path.basename(filename) reply = Reply(user, source, filename) reply_uuid = data.get('uuid', None) if reply_uuid is not None: # check that is is parseable try: UUID(reply_uuid) except ValueError: abort(400, "'uuid' was not a valid UUID") reply.uuid = reply_uuid try: db.session.add(reply) db.session.add(source) db.session.commit() except IntegrityError as e: db.session.rollback() if 'UNIQUE constraint failed: replies.uuid' in str(e): abort(409, 'That UUID is already in use.') else: raise e return jsonify({'message': 'Your reply has been stored', 'uuid': reply.uuid, 'filename': reply.filename}), 201 @api.route('/sources/<source_uuid>/replies/<reply_uuid>', methods=['GET', 'DELETE']) @token_required def single_reply(source_uuid, reply_uuid): get_or_404(Source, source_uuid, column=Source.uuid) reply = get_or_404(Reply, reply_uuid, column=Reply.uuid) if request.method == 'GET': return jsonify(reply.to_json()), 200 elif request.method == 'DELETE': utils.delete_file_object(reply) return jsonify({'message': 'Reply deleted'}), 200 @api.route('/submissions', methods=['GET']) @token_required def get_all_submissions(): submissions = Submission.query.all() return jsonify({'submissions': [submission.to_json() for submission in submissions]}), 200 @api.route('/replies', methods=['GET']) @token_required def get_all_replies(): replies = Reply.query.all() return jsonify( {'replies': [reply.to_json() for reply in replies]}), 200 @api.route('/user', methods=['GET']) @token_required def get_current_user(): user = get_user_object(request) return jsonify(user.to_json()), 200 @api.route('/logout', methods=['POST']) @token_required def logout(): user = get_user_object(request) auth_token = request.headers.get('Authorization').split(" ")[1] utils.revoke_token(user, auth_token) return jsonify({'message': 'Your token has been revoked.'}), 200 def _handle_api_http_exception(error): # Workaround for no blueprint-level 404/5 error handlers, see: # https://github.com/pallets/flask/issues/503#issuecomment-71383286 response = jsonify({'error': error.name, 'message': error.description}) return response, error.code for code in default_exceptions: api.errorhandler(code)(_handle_api_http_exception) return api
def make_blueprint(config: SDConfig) -> Blueprint: api = Blueprint('api', __name__) @api.route('/') def get_endpoints() -> Tuple[flask.Response, int]: endpoints = { 'sources_url': '/api/v1/sources', 'current_user_url': '/api/v1/user', 'all_users_url': '/api/v1/users', 'submissions_url': '/api/v1/submissions', 'replies_url': '/api/v1/replies', 'seen_url': '/api/v1/seen', 'auth_token_url': '/api/v1/token' } return jsonify(endpoints), 200 # Before every post, we validate the payload before processing the request @api.before_request def validate_data() -> None: if request.method == 'POST': # flag, star, and logout can have empty payloads if not request.data: dataless_endpoints = [ 'add_star', 'remove_star', 'flag', 'logout', ] for endpoint in dataless_endpoints: if request.endpoint == 'api.' + endpoint: return abort(400, 'malformed request') # other requests must have valid JSON payload else: try: json.loads(request.data.decode('utf-8')) except (ValueError): abort(400, 'malformed request') @api.route('/token', methods=['POST']) def get_token() -> Tuple[flask.Response, int]: creds = json.loads(request.data.decode('utf-8')) username = creds.get('username', None) passphrase = creds.get('passphrase', None) one_time_code = creds.get('one_time_code', None) if username is None: abort(400, 'username field is missing') if passphrase is None: abort(400, 'passphrase field is missing') if one_time_code is None: abort(400, 'one_time_code field is missing') try: journalist = Journalist.login(username, passphrase, one_time_code) token_expiry = datetime.utcnow() + timedelta( seconds=TOKEN_EXPIRATION_MINS * 60) response = jsonify({ 'token': journalist.generate_api_token( expiration=TOKEN_EXPIRATION_MINS * 60), 'expiration': token_expiry.isoformat() + 'Z', 'journalist_uuid': journalist.uuid, 'journalist_first_name': journalist.first_name, 'journalist_last_name': journalist.last_name, }) # Update access metadata journalist.last_access = datetime.utcnow() db.session.add(journalist) db.session.commit() return response, 200 except (LoginThrottledException, InvalidUsernameException, BadTokenException, WrongPasswordException): return abort(403, 'Token authentication failed.') @api.route('/sources', methods=['GET']) @token_required def get_all_sources() -> Tuple[flask.Response, int]: sources = Source.query.filter_by(pending=False, deleted_at=None).all() return jsonify({'sources': [source.to_json() for source in sources]}), 200 @api.route('/sources/<source_uuid>', methods=['GET', 'DELETE']) @token_required def single_source(source_uuid: str) -> Tuple[flask.Response, int]: if request.method == 'GET': source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify(source.to_json()), 200 elif request.method == 'DELETE': source = get_or_404(Source, source_uuid, column=Source.uuid) utils.delete_collection(source.filesystem_id) return jsonify({'message': 'Source and submissions deleted'}), 200 else: abort(405) @api.route('/sources/<source_uuid>/add_star', methods=['POST']) @token_required def add_star(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) utils.make_star_true(source.filesystem_id) db.session.commit() return jsonify({'message': 'Star added'}), 201 @api.route('/sources/<source_uuid>/remove_star', methods=['DELETE']) @token_required def remove_star(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) utils.make_star_false(source.filesystem_id) db.session.commit() return jsonify({'message': 'Star removed'}), 200 @api.route('/sources/<source_uuid>/flag', methods=['POST']) @token_required def flag(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) source.flagged = True db.session.commit() return jsonify({'message': 'Source flagged for reply'}), 200 @api.route('/sources/<source_uuid>/submissions', methods=['GET']) @token_required def all_source_submissions(source_uuid: str) -> Tuple[flask.Response, int]: source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify({ 'submissions': [submission.to_json() for submission in source.submissions] }), 200 @api.route("/sources/<source_uuid>/submissions/<submission_uuid>/download", methods=["GET"]) @token_required def download_submission(source_uuid: str, submission_uuid: str) -> flask.Response: get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) return utils.serve_file_with_etag(submission) @api.route('/sources/<source_uuid>/replies/<reply_uuid>/download', methods=['GET']) @token_required def download_reply(source_uuid: str, reply_uuid: str) -> flask.Response: get_or_404(Source, source_uuid, column=Source.uuid) reply = get_or_404(Reply, reply_uuid, column=Reply.uuid) return utils.serve_file_with_etag(reply) @api.route('/sources/<source_uuid>/submissions/<submission_uuid>', methods=['GET', 'DELETE']) @token_required def single_submission(source_uuid: str, submission_uuid: str) -> Tuple[flask.Response, int]: if request.method == 'GET': get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) return jsonify(submission.to_json()), 200 elif request.method == 'DELETE': get_or_404(Source, source_uuid, column=Source.uuid) submission = get_or_404(Submission, submission_uuid, column=Submission.uuid) utils.delete_file_object(submission) return jsonify({'message': 'Submission deleted'}), 200 else: abort(405) @api.route('/sources/<source_uuid>/replies', methods=['GET', 'POST']) @token_required def all_source_replies(source_uuid: str) -> Tuple[flask.Response, int]: if request.method == 'GET': source = get_or_404(Source, source_uuid, column=Source.uuid) return jsonify( {'replies': [reply.to_json() for reply in source.replies]}), 200 elif request.method == 'POST': source = get_or_404(Source, source_uuid, column=Source.uuid) if request.json is None: abort(400, 'please send requests in valid JSON') if 'reply' not in request.json: abort(400, 'reply not found in request body') user = _authenticate_user_from_auth_header(request) data = request.json if not data['reply']: abort(400, 'reply should not be empty') source.interaction_count += 1 try: filename = current_app.storage.save_pre_encrypted_reply( source.filesystem_id, source.interaction_count, source.journalist_filename, data['reply']) except NotEncrypted: return jsonify( {'message': 'You must encrypt replies client side'}), 400 # issue #3918 filename = path.basename(filename) reply = Reply(user, source, filename) reply_uuid = data.get('uuid', None) if reply_uuid is not None: # check that is is parseable try: UUID(reply_uuid) except ValueError: abort(400, "'uuid' was not a valid UUID") reply.uuid = reply_uuid try: db.session.add(reply) db.session.flush() seen_reply = SeenReply(reply_id=reply.id, journalist_id=user.id) db.session.add(seen_reply) db.session.add(source) db.session.commit() except IntegrityError as e: db.session.rollback() if 'UNIQUE constraint failed: replies.uuid' in str(e): abort(409, 'That UUID is already in use.') else: raise e return jsonify({ 'message': 'Your reply has been stored', 'uuid': reply.uuid, 'filename': reply.filename }), 201 else: abort(405) @api.route('/sources/<source_uuid>/replies/<reply_uuid>', methods=['GET', 'DELETE']) @token_required def single_reply(source_uuid: str, reply_uuid: str) -> Tuple[flask.Response, int]: get_or_404(Source, source_uuid, column=Source.uuid) reply = get_or_404(Reply, reply_uuid, column=Reply.uuid) if request.method == 'GET': return jsonify(reply.to_json()), 200 elif request.method == 'DELETE': utils.delete_file_object(reply) return jsonify({'message': 'Reply deleted'}), 200 else: abort(405) @api.route('/submissions', methods=['GET']) @token_required def get_all_submissions() -> Tuple[flask.Response, int]: submissions = Submission.query.all() return jsonify({ 'submissions': [ submission.to_json() for submission in submissions if submission.source ] }), 200 @api.route('/replies', methods=['GET']) @token_required def get_all_replies() -> Tuple[flask.Response, int]: replies = Reply.query.all() return jsonify({ 'replies': [reply.to_json() for reply in replies if reply.source] }), 200 @api.route("/seen", methods=["POST"]) @token_required def seen() -> Tuple[flask.Response, int]: """ Lists or marks the source conversation items that the journalist has seen. """ user = _authenticate_user_from_auth_header(request) if request.method == "POST": if request.json is None or not isinstance(request.json, collections.abc.Mapping): abort(400, "Please send requests in valid JSON.") if not any(map(request.json.get, ["files", "messages", "replies"])): abort(400, "Please specify the resources to mark seen.") # gather everything to be marked seen. if any don't exist, # reject the request. targets = set() # type: Set[Union[Submission, Reply]] for file_uuid in request.json.get("files", []): f = Submission.query.filter( Submission.uuid == file_uuid).one_or_none() if f is None or not f.is_file: abort(404, "file not found: {}".format(file_uuid)) targets.add(f) for message_uuid in request.json.get("messages", []): m = Submission.query.filter( Submission.uuid == message_uuid).one_or_none() if m is None or not m.is_message: abort(404, "message not found: {}".format(message_uuid)) targets.add(m) for reply_uuid in request.json.get("replies", []): r = Reply.query.filter(Reply.uuid == reply_uuid).one_or_none() if r is None: abort(404, "reply not found: {}".format(reply_uuid)) targets.add(r) # now mark everything seen. utils.mark_seen(list(targets), user) return jsonify({"message": "resources marked seen"}), 200 abort(405) @api.route('/user', methods=['GET']) @token_required def get_current_user() -> Tuple[flask.Response, int]: user = _authenticate_user_from_auth_header(request) return jsonify(user.to_json()), 200 @api.route('/users', methods=['GET']) @token_required def get_all_users() -> Tuple[flask.Response, int]: users = Journalist.query.all() return jsonify( {'users': [user.to_json(all_info=False) for user in users]}), 200 @api.route('/logout', methods=['POST']) @token_required def logout() -> Tuple[flask.Response, int]: user = _authenticate_user_from_auth_header(request) auth_token = request.headers['Authorization'].split(" ")[1] utils.revoke_token(user, auth_token) return jsonify({'message': 'Your token has been revoked.'}), 200 def _handle_api_http_exception( error: werkzeug.exceptions.HTTPException ) -> Tuple[flask.Response, int]: # Workaround for no blueprint-level 404/5 error handlers, see: # https://github.com/pallets/flask/issues/503#issuecomment-71383286 response = jsonify({'error': error.name, 'message': error.description}) return response, error.code # type: ignore for code in default_exceptions: api.errorhandler(code)(_handle_api_http_exception) return api
@bp.route('/abort/<code>', methods=['GET']) @bp.route('/abort/<code>/<message>', methods=['GET']) def route_abort(code, message=None): """ Custom abort route """ if message: abort(int(code), message) abort(int(code)) @bp.route('/except/<err>', methods=['GET']) @bp.route('/except/<err>/<message>', methods=['GET']) def route_except(err, message=None): """ Custom exception route """ exception = eval(err) if message: raise exception(str(message)) raise exception() @bp.route("/<path:invalid_path>", methods=['GET', 'POST', 'PATCH', 'PUT', 'DELETE', 'OPTIONS']) def route404(*args, **kwargs): """ Catch all route within blueprint to force use of 404 errorhandler. """ abort(404) # Register errorhandler for specific HTTP codes for code in (400, 401, 403, 404, 405, 409, 410, 412, 413, 418, 429, 500, 501, 502, 503, 504, 505): bp.errorhandler(code)(handle_abort)
from flask import Blueprint import activity routes = Blueprint("routes", __name__) activity.routes = routes @routes.record def record(state): routes.db = state.app.config.get("database") if routes.db is None: raise Exception("This blueprint expects you to provide database access through database") routes.route("/", methods=["GET"])(activity.home) routes.errorhandler(Exception)(activity.error)
verify_username = db.execute( "SELECT username FROM users WHERE username = :username", { "username": username }).fetchone() if email: verify_email = db.execute( "SELECT email FROM users WHERE email = :email", { "email": email }).fetchone() if verify_email and verify_username: return jsonify("Username and email already taken.") if verify_username: return jsonify("Username already taken.") if verify_email: return jsonify("Email already taken.") if verify_username: return jsonify("Username already taken.") return jsonify(True) def errorhandler(e): """Handle error""" if not isinstance(e, HTTPException): e = InternalServerError() return apology(e.name, e.code) # Listen for errors for code in default_exceptions: auth.errorhandler(code)(errorhandler)
TARGET_OFFICE_DISTRICT, TARGET_OFFICE_BUSY) from ..campaign.models import Campaign, Target from ..political_data.lookup import locate_targets, validate_location from ..political_data.geocode import LocationError from ..schedule.models import ScheduleCall from ..schedule.views import schedule_created, schedule_deleted from ..admin.models import Blocklist from ..admin.views import admin_phone from .decorators import abortJSON, stripANSI call = Blueprint('call', __name__, url_prefix='/call') cors(call) call_methods = ['GET', 'POST'] csrf.exempt(call) call.errorhandler(400)(abortJSON) call.errorhandler(429)(abortJSON) def play_or_say(r, audio, voice='alice', lang='en-US', **kwargs): """ Take twilio response and play or say message from an AudioRecording Can use mustache templates to render keyword arguments """ if audio: # check to ensure lang is in list of valid locales if lang not in TWILIO_TTS_LANGUAGES: if '-' in lang: lang, country = lang.split('-') else:
from flask import Blueprint from . import views from main import errors accounts = Blueprint('accounts', __name__) accounts.add_url_rule('/login/', 'login', views.login, methods=['GET', 'POST']) accounts.add_url_rule('/logout/', 'logout', views.logout) accounts.add_url_rule('/registration/', 'register', views.register, methods=['GET', 'POST']) accounts.add_url_rule('/registration/su', 'register_su', views.register, defaults={'create_su':True}, methods=['GET', 'POST']) accounts.add_url_rule('/add-user/', 'add_user', views.add_user, methods=['GET', 'POST']) accounts.add_url_rule('/users/', view_func=views.Users.as_view('users')) accounts.add_url_rule('/users/edit/<username>', view_func=views.User.as_view('edit_user')) accounts.add_url_rule('/su-users/', view_func=views.SuUsers.as_view('su_users')) accounts.add_url_rule('/su-users/edit/<username>', view_func=views.SuUser.as_view('su_edit_user')) accounts.add_url_rule('/user/settings/', view_func=views.Profile.as_view('settings')) accounts.add_url_rule('/user/password/', view_func=views.Password.as_view('password')) accounts.errorhandler(403)(errors.handle_forbidden)