class EntryLockResource(Resource): @marshal_with(fields.entry_lock, envelope="lock") def get(self, entry_id, logbook_id=None): "Check for a lock" entry = Entry.get(Entry.id == entry_id) lock = entry.get_lock(request.environ["REMOTE_ADDR"]) if lock: return lock raise EntryLock.DoesNotExist @use_args({"steal": Boolean(missing=False)}) @marshal_with(fields.entry_lock, envelope="lock") def post(self, args, entry_id, logbook_id=None): "Acquire (optionally stealing) a lock" entry = Entry.get(Entry.id == entry_id) return entry.get_lock(ip=request.environ["REMOTE_ADDR"], acquire=True, steal=args["steal"]) @use_args({"lock_id": Integer()}) @marshal_with(fields.entry_lock, envelope="lock") def delete(self, args, entry_id=None, logbook_id=None): "Cancel a lock" if "lock_id" in args: lock = EntryLock.get(EntryLock.id == args["lock_id"]) else: entry = Entry.get(Entry.id == entry_id) lock = entry.get_lock() lock.cancel(request.environ["REMOTE_ADDR"]) return lock
class LogbooksResource(Resource): "Handle requests for logbooks" @use_args({"parent": Integer()}) @marshal_with(fields.logbook, envelope="logbook") def get(self, args, logbook_id=None, revision_n=None): "Fetch a given logbook" if logbook_id: logbook = Logbook.get(Logbook.id == logbook_id) if revision_n is not None: return logbook.get_revision(revision_n) return logbook # Get either the direct children of a given parent, or else the # global list of top-level (no parent) logbooks parent_id = args.get("parent") if parent_id: return Logbook.get(Logbook.id == parent_id) children = (Logbook.select().where(Logbook.parent == None)) return dict(children=children) @send_signal(new_logbook) @use_args(logbook_args) @marshal_with(fields.logbook, envelope="logbook") def post(self, args, logbook_id=None): "Create a new logbook" logbook = Logbook(name=args["name"], parent=args.get("parent_id"), description=args.get("description"), template=args.get("template"), attributes=args.get("attributes", []), metadata=args.get("metadata", {}), archived=args["archived"]) if logbook_id: parent = Logbook.get(Logbook.id == logbook_id) logbook.parent = parent logbook.save() return logbook @send_signal(edit_logbook) @use_args(logbook_args) @marshal_with(fields.logbook, envelope="logbook") def put(self, args, logbook_id): "Update an existing logbook" logbook = Logbook.get(Logbook.id == logbook_id) logbook.make_change(**args).save() logbook.save() return logbook
if not request.is_json: return make_resp(NO_JSON) try: project_schema.context["project_id"] = project.id project = project_schema.load(request.get_json(), instance=project) project.last_modified = datetime.datetime.utcnow() project_schema.context.pop("project_id") except ValidationError as errors: return errors.messages, 422 db.session.commit() return jsonify(data=project_schema.dump(project)), 200 elif request.method == "DELETE": if project.user != get_user(): return make_resp(FORBIDDEN) db.session.delete(project) db.session.commit() return make_resp(({"msg": "success"}, 200)) @projects_bp.route("/uniquity-check/project-name/", methods=["GET"]) @use_args( { "name": String(required=True), "project_id": Integer(required=False) }, locations=("querystring", )) def project_name_check(args) -> Tuple[Any, int]: return jsonify(taken=Project.query.filter( Project.name == args.get("name", "").lower(), Project.id != args.get("project_id", 0)).first() is not None), 200
user = user_schema.load(request.get_json(), instance=user) user_schema.context.pop("user_id") except ValidationError as errors: return errors.messages, 422 db.session.commit() return jsonify(data=user_schema.dump(user)), 200 elif request.method == "DELETE": if user != get_user(): return make_resp(FORBIDDEN) db.session.delete(user) db.session.commit() return make_resp(({"msg": "success"}, 200)) @users_bp.route("/uniquity-check/username/", methods=["GET"]) @use_args({"username": String(required=True), "user_id": Integer(required=False)}, locations=("querystring",)) def username_check(args) -> Tuple[Any, int]: return jsonify( taken=User.query.filter( User.username == args.get("username", "").lower(), User.id != args.get("user_id", 0) ).first() is not None), 200 @users_bp.route("/uniquity-check/email/", methods=["GET"]) @use_args({"email": String(required=True), "user_id": Integer(required=False)}, locations=("querystring",)) def email_check(args) -> Tuple[Any, int]: return jsonify( taken=User.query.filter( User.email == args.get("email", "").lower(), User.id != args.get("user_id", 0)
from flask import request, send_file from flask_restful import Resource, marshal, marshal_with, abort from webargs.fields import (Integer, Str, Boolean, Dict, List, Nested, Email, LocalDateTime) from webargs.flaskparser import use_args from ..db import Entry, Logbook, EntryLock from ..attachments import handle_img_tags from ..export import export_entries_as_pdf from ..actions import new_entry, edit_entry from . import fields, send_signal entry_args = { "id": Integer(allow_none=True), "logbook_id": Integer(allow_none=True), "title": Str(allow_none=True), "content": Str(), "content_type": Str(missing="text/html"), "authors": List(Nested({ "name": Str(), "login": Str(allow_none=True), "email": Email(allow_none=True) }), validate=lambda a: len(a) > 0),
class TextsRes(Resource): POST_MAX_N_TAGS = 16 POST_ARGS = { 'tags': DelimitedList(Str()), 'content': Str(), } TAGS_BLACKLIST = {} GET_MAX_N_RESULTS = 1000 GET_ARGS = { 'any_tags': DelimitedList(Str()), 'all_tags': DelimitedList(Str()), 'no_tags': DelimitedList(Str()), 'date_from': Date(), 'date_to': Date(), 'max_n_results': \ Integer(validate=lambda n: n >= 0, missing=GET_MAX_N_RESULTS), 'offset': \ Integer(validate=lambda n: n >= 0, missing=0), 'fields': DelimitedList(Str()), } @staticmethod def parse_post_args(req): args = parser.parse(TextsRes.POST_ARGS, req) if 'tags' in args: if len(args['tags']) > TextsRes.POST_MAX_N_TAGS: raise ValidationError('too many tags (limit={})'.format( TextsRes.POST_MAX_N_TAGS)) for tag in args['tags']: if tag in TextsRes.TAGS_BLACKLIST: raise ValidationError('"{}" is blacklisted'.format(tag)) args['tags'] = serialize_tags(get_tags(args['tags'])) return args @staticmethod def filter_texts(args): #sorting in decreasing order by creation time query = Text.query.order_by(-Text.created_at) if 'date_to' in args: query = query.filter(func.DATE(Text.created_at) <= args['date_to']) if 'date_from' in args: query = query.filter( func.DATE(Text.created_at) >= args['date_from']) if 'all_tags' in args: tags = Tag.query.filter(Tag.content.in_(args['all_tags'])).all() if len(tags) < len(args['all_tags']): return [], None #dirty hack TODO: get a better solution for t in tags: query = query.filter(Text.tags.contains(t)) elif 'any_tags' in args: query = query.join(Tag, Text.tags).join( Tag.query.join(Text, Tag.texts).filter( Tag.content.in_(args['any_tags']))) if 'no_tags' in args: tags = Tag.query.filter(Tag.content.in_(args['no_tags'])).all() #new dirty hack TODO: get a better solution for t in tags: query = query.filter(~Text.tags.contains(t)) query = query.offset(args['offset']) if query.count() <= args['max_n_results']: offset = None else: offset = args['offset'] + args['max_n_results'] texts = query.limit(args['max_n_results']).all() return texts, offset @staticmethod def parse_get_args(req): args = parser.parse(TextsRes.GET_ARGS, req, locations=('querystring', )) return args @jwt_required def post(self): """ Create new text resource. .. :quickref: Text creation; Create new text. **Example request**: .. sourcecode:: http POST /texts HTTP/1.1 Host: example.com Accept: application/json Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhb **Example response**: .. sourcecode:: http HTTP/1.1 201 CREATED Content-Type: application/json { "text": { "content": "Bom dia!", "text_id": 1, "tags": [ "bomdia" ], "updated_at": null, "created_at": "2018-09-15T22:53:26+00:00" }, } :reqheader Authorization: access token of logged in user (required) :form content: the text contents (required) :form tags: comma-separated list of tags :resheader Content-Type: application/json :status 201: resource created :returns: :class:`memedata.models.Text` """ try: args = TextsRes.parse_post_args(request) text = TextSchema().load(args) except ValidationError as e: return mk_errors(400, fmt_validation_error_messages(e.messages)) db.session.add(text) db.session.commit() return TextSchema().dump(text), 201 @jwt_required def get(self): """ Return collection of texts. .. :quickref: Get Texts; Get collection of texts. **Example request**: .. sourcecode:: http GET /texts HTTP/1.1 Host: example.com Accept: application/json Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhb **Example response**: .. sourcecode:: http HTTP/1.1 200 OK Content-Type: application/json { "texts": [ { "content": "Bom dia!", "text_id": 1, "tags": [ "bomdia" ], "updated_at": null, "created_at": "2018-09-15T22:53:26+00:00" }, { "content": "Eu adoro as manhãs", "text_id": 32, "tags": [ "jesus", "sexta" ], "updated_at": null, "created_at": "2018-09-15T22:53:26+00:00" }, ], "offset": 2 } :reqheader Authorization: access token of logged in user (required) :query string fields: comma-separated list of fields to get for each \ text. :query string date_from: only texts created after specified date \ (inclusive). :query string date_to: only texts created before specified date. :query string any_tags: texts with at least one tags in specified list. :query string all_tags: texts only containing all specified tags. :query string no_tags: texts only not containing any of specified tags. :query int offset: pagination offset to start getting results :query int max_n_results: maximum number of results to return. :resheader Content-Type: application/json :status 200: texts found :returns: :class:`memedata.models.Text` """ try: args = TextsRes.parse_get_args(request) except ValidationError as e: return mk_errors(400, fmt_validation_error_messages(e.messages)) texts, offset = TextsRes.filter_texts(args) objs = TextSchema(many=True).dump(texts) objs = filter_fields(objs, args.get('fields')) objs['offset'] = offset return objs
from flask_restful import Resource, marshal_with from webargs.fields import Integer, Str, Boolean, Dict, List, Nested from webargs.flaskparser import use_args from ..db import Logbook from ..actions import new_logbook, edit_logbook from . import fields, send_signal logbook_args = { "parent_id": Integer(allow_none=True), "name": Str(), "description": Str(allow_none=True), "template": Str(allow_none=True), "attributes": List(Nested({ "name": Str(), "type": Str( validate=lambda t: t in ["text", "number", "boolean", "option", "multioption"]), "required": Boolean(), "options": List(Str(), missing=None) })), "metadata": Dict(), "archived": Boolean(missing=False) } class LogbooksResource(Resource):
from flask import request, send_file from flask_restful import Resource, marshal, marshal_with, abort from webargs.fields import (Integer, Str, Boolean, Dict, List, Nested, Email, LocalDateTime) from webargs.flaskparser import use_args from ..db import Entry, Logbook, EntryLock from ..attachments import handle_img_tags from ..export import export_entries_as_pdf from ..actions import new_entry, edit_entry from . import fields, send_signal entry_args = { "id": Integer(allow_none=True), "logbook_id": Integer(allow_none=True), "title": Str(allow_none=True), "content": Str(), "content_type": Str(missing="text/html"), "authors": List(Nested({ "name": Str(), "login": Str(allow_none=True), "email": Email(allow_none=True) }), validate=lambda a: len(a) > 0), "created_at": LocalDateTime(), "last_changed_at": LocalDateTime(allow_none=True), "follows_id": Integer(allow_none=True), "attributes": Dict(), "archived": Boolean(), "metadata": Dict(),
from flask_restful import Resource, marshal_with from webargs.fields import Integer, Str, Boolean, Dict, List, Nested from webargs.flaskparser import use_args from ..db import Logbook from ..actions import new_logbook, edit_logbook from . import fields, send_signal logbook_args = { "parent_id": Integer(allow_none=True), "name": Str(), "description": Str(allow_none=True), "template": Str(allow_none=True), "attributes": List( Nested({ "name": Str(), "type": Str(validate=lambda t: t in ["text", "number", "boolean", "option", "multioption"]), "required": Boolean(), "options": List(Str()) })), "metadata":