From 2dbc9bc23d3d36f928aed41a5ffd3cc956d1b5e7 Mon Sep 17 00:00:00 2001 From: Mustafa Yontar Date: Mon, 1 Feb 2021 14:35:50 +0300 Subject: [PATCH] remove restapi folder restapi now a submodule --- restapi/Methods.py | 18 ---- restapi/__init__.py | 43 --------- restapi/jwt.py | 9 -- restapi/resource.py | 212 -------------------------------------------- restapi/views.py | 155 -------------------------------- 5 files changed, 437 deletions(-) delete mode 100644 restapi/Methods.py delete mode 100644 restapi/__init__.py delete mode 100644 restapi/jwt.py delete mode 100644 restapi/resource.py delete mode 100644 restapi/views.py diff --git a/restapi/Methods.py b/restapi/Methods.py deleted file mode 100644 index 08d3cbc..0000000 --- a/restapi/Methods.py +++ /dev/null @@ -1,18 +0,0 @@ -class Get: - method = 'GET' - - -class List: - method = 'GET' - - -class Delete: - method = 'DELETE' - - -class Update: - method = 'PUT' - - -class Create: - method = 'POST' diff --git a/restapi/__init__.py b/restapi/__init__.py deleted file mode 100644 index 9d5b8c4..0000000 --- a/restapi/__init__.py +++ /dev/null @@ -1,43 +0,0 @@ -from urllib.parse import urljoin - -from flask import Flask -from mongoengine import Document - -from restapi.views import ApiView -from restapi import Methods - - -class MongoApi: - app: Flask = None - - def __init__(self, app: Flask): - self.app = app - - def register_model(self, model: any, uri: str = None, name: str = None) -> None: - if not getattr(model, '_meta').get('methods'): - raise Exception("{} model methods not set".format(model.__name__)) - if not uri: - uri = model.__name__.lower() - if uri[:-1] != "/": - uri = uri + "/" - if uri[0] != "/": - uri = "/" + uri - if not name: - name = model.__name__ - self.app.add_url_rule( - uri, - methods=(method.method for method in getattr(model, '_meta').get('methods') if - method not in (Methods.Get, Methods.Update)), - view_func=ApiView.as_view(name, model=model)) - - single = [] - if Methods.Update in getattr(model, '_meta').get('methods'): - single.append('PUT') - - if Methods.Get in getattr(model, '_meta').get('methods'): - single.append('GET') - if single: - self.app.add_url_rule( - urljoin(uri, '/'), - methods=single, - view_func=ApiView.as_view("{}_GET_PUT".format(name), model=model)) diff --git a/restapi/jwt.py b/restapi/jwt.py deleted file mode 100644 index b1fe586..0000000 --- a/restapi/jwt.py +++ /dev/null @@ -1,9 +0,0 @@ -from flask import request -from flask_jwt_extended.utils import verify_token_claims -from flask_jwt_extended.view_decorators import _decode_jwt_from_request - - -def get_jwt_from_request(): - jwt_data, jwt_header = _decode_jwt_from_request(request_type='access') - verify_token_claims(jwt_data) - return jwt_data['identity'] diff --git a/restapi/resource.py b/restapi/resource.py deleted file mode 100644 index c66ce7e..0000000 --- a/restapi/resource.py +++ /dev/null @@ -1,212 +0,0 @@ -from bson import ObjectId -from flask import request -from mongoengine import Document, ObjectIdField, ListField, \ - EmbeddedDocumentField, ReferenceField, ImageField, FileField, DecimalField, QuerySet -from base64 import b64encode - -from mongoengine.base import BaseField - - -class Resource: - model: Document = None - qs: dict = {} - eqs: dict = {} - build_reference: bool = False - base64_image: bool = True - base64_image_as_full: bool = False - limit: int = 10 - offset: int = 0 - fields: list = [] - ignore_fields: list = [] - mask_fields: dict = {} - meta: dict = {} - as_pk: str = 'id' - query_document: Document = None - mongo_qs = None - - def __init__(self, model: Document): - self.model = model - self.limit = 10 - if 'no_image' in request.args: - self.base64_image = False - if 'with_sub_docs' in request.args: - self.build_reference = request.args.get('with_sub_docs') - if 'thumb' in request.args: - self.base64_image = True - self.base64_image_as_full = False - if 'full_image' in request.args: - self.base64_image = True - self.base64_image_as_full = True - if 'limit' in request.args: - self.limit = int(request.args.get('limit')) - if 'fields' in request.args: - self.fields = request.args.get('fields') - if 'offset' in request.args: - self.offset = int(request.args.get('offset')) - self.meta = getattr(self.model, '_meta') - - if 'ignore_fields' in self.meta: - self.ignore_fields = self.meta.get('ignore_fields') - if 'with_sub_docs' in self.meta: - self.build_reference = self.meta.get('with_sub_docs') - if 'mask_fields' in self.meta: - self.mask_fields = self.meta.get('mask_fields') - if 'document' in self.meta: - self.model = self.meta.get('document') - if 'query' in self.meta: - self.qs = self.meta.get('query') - if 'as_pk' in self.meta: - self.as_pk = self.meta.get('as_pk') - if 'query_document' in self.meta: - self.query_document = self.meta.get('query_document') - - def external_query(self, qs: dict): - self.eqs = qs - - def query(self, qs: dict) -> None: - - self.qs = qs - - def to_qs(self, pk: str = None) -> tuple: - query = {} - if self.qs: - for key, val in self.qs.items(): - if callable(val): - query.update({key: val()}) - else: - query.update({key: val}) - if self.query_document: - query = {} - if self.eqs: - for key, val in self.eqs.items(): - if callable(val): - query.update({key: val()}) - else: - query.update({key: val}) - data = self.query_document.objects.filter(**query) - field_name = "" - for i in self.model._fields_ordered: - try: - if isinstance(getattr(self.model, i).document_type, self.query_document.__class__): - field_name = i + "__in" - except: - pass - query.clear() - query = {field_name: [i.id for i in data]} - for key, val in self.qs.items(): - if callable(val): - query.update({key: val()}) - else: - query.update({key: val}) - print(query) - data = self.model.objects.filter(**query) - if pk: - data.get(**{self.as_pk: pk}) - return data - - def to_json(self, pk: str = None) -> tuple: - - if self.mongo_qs is None: - self.mongo_qs = self.to_qs(pk) - - data = self.mongo_qs - count = data.count() - if pk: - json_data = self.parse_fields(self.mongo_qs.get(**{self.as_pk:pk}),self.model) - else: - data = data[self.offset:self.limit + self.offset] - json_data = [] - for item in data: - item_data = self.parse_fields(item, self.model) - json_data.append(item_data) - return count, json_data - - def parse_field(self, field: BaseField, value: any) -> any: - - if isinstance(field, ObjectIdField): - return str(value) - elif isinstance(field, ReferenceField): - - if self.build_reference: - return self.parse_fields(value, field.document_type) - if value: - return str(value.id) - else: - return value - - elif isinstance(field, ImageField): - if self.base64_image and value: - if self.base64_image_as_full: - file = b64encode(value.read()).decode("utf-8") - return { - "size": value.size, - "upload_date": value.gridout.upload_date, - "format": value.format, - "base64": file - } - else: - file = b64encode(value.thumbnail.read()).decode("utf-8") - - return { - "upload_date": value.gridout.upload_date, - "format": value.format, - "base64": file - } - else: - if value: - return { - "size": value.size - } - else: - return None - elif isinstance(field, DecimalField): - return float(value) - elif isinstance(field, FileField): - return "file" - elif isinstance(field, ListField): - if isinstance(field.field, EmbeddedDocumentField): - return [self.parse_fields(item, field.field.document_type) for item in value] - elif isinstance(field.field, ReferenceField) and self.build_reference: - return [self.parse_fields(item, field.field.document_type) for item in value] - else: - return [self.parse_field(field.field, item) for item in value] - elif isinstance(value, QuerySet): - if value.count() > 0: - return [self.parse_fields(i, value._document) for i in value] - - else: - return value - - def parse_fields(self, item: Document, model: Document) -> dict: - parsed_item = {} - - fields = list(getattr(model, "_fields_ordered")) - if self.model != model: - in_meta = getattr(model,'_meta') - if in_meta.get('ignore_fields'): - self.ignore_fields += in_meta.get('ignore_fields') - for key, val in model.__dict__.items(): - if isinstance(getattr(model, key), property): - fields.append(key) - for i in fields: - if i not in self.ignore_fields: - field = getattr(model, i) - if i not in self.mask_fields: - if not item is None: - value = getattr(item, i) - else: - value = None - else: - value = getattr(item, i) - if self.mask_fields.get(i) == 'all': - value = '*************' - elif self.mask_fields.get(i) == 'email': - value = '{}****@{}***.{}'.format(value[0], value.split("@")[1][0], - '.'.join(value.split("@")[1].split(".")[1:])) - else: - value = '*************' - if not value is None: - parsed_item.update({i: self.parse_field(field, value)}) - else: - parsed_item.update({i: None}) - return parsed_item diff --git a/restapi/views.py b/restapi/views.py deleted file mode 100644 index e3681ef..0000000 --- a/restapi/views.py +++ /dev/null @@ -1,155 +0,0 @@ -import json -import time - -import mongoengine -from flask import jsonify, request -from flask_views.base import View -from mongoengine import ValidationError, DoesNotExist, InvalidQueryError -from werkzeug.exceptions import Unauthorized, NotFound - -from restapi.resource import Resource - - -class ApiView(View): - model = None - authentication_methods = [] - - def __init__(self, model): - self.start = time.time() - self.model = model - self.resource = Resource(self.model) - - def dispatch_request(self, *args, **kwargs): - # keep all the logic in a helper method (_dispatch_request) so that - # it's easy for subclasses to override this method without them also having to copy/paste all the - # authentication logic, etc. - return self._dispatch_request(*args, **kwargs) - - def _dispatch_request(self, *args, **kwargs): - authorized = True if len(self.authentication_methods) == 0 else False - for authentication_method in self.authentication_methods: - if authentication_method().authorized(): - authorized = True - if not authorized: - return {'error': 'Unauthorized'}, '401 Unauthorized' - - try: - return super(ApiView, self).dispatch_request(*args, **kwargs) - except mongoengine.queryset.DoesNotExist as e: - return {'error': 'Empty query: ' + str(e)}, '404 Not Found' - except ValidationError as e: - return e.args[0], '400 Bad Request' - except Unauthorized: - return {'error': 'Unauthorized'}, '401 Unauthorized' - except NotFound as e: - return {'error': str(e)}, '404 Not Found' - - def get(self, *args, **kwargs): - """ - TODO: check permissions - :param args: - :param kwargs: - :return: - """ - if 'pk' in kwargs: - try: - qs = self.resource.to_qs(pk=kwargs.get('pk')) - count, data = self.resource.to_json(pk=kwargs.get('pk')) - response = { - 'response': data, - 'status': True, - 'info': { - 'took': time.time() - self.start - }, - } - except (ValidationError, DoesNotExist) as e: - kwargs.update({'code': 404}) - response = { - "status": False, - "errors": "Object not found" - } - else: - if "query" in request.args and self.model._meta.get('can_query'): - self.resource.external_query(json.loads(request.args.get('query'))) - count, data = self.resource.to_json() - response = { - 'response': data, - 'info': { - 'offset': self.resource.offset, - 'limit': self.resource.limit, - 'status': True, - 'total': count, - 'took': time.time() - self.start - }, - } - - return jsonify(response), kwargs.get('code', 200) - - def post(self, *args, **kwargs): - """ - TODO: check permissions - - :param args: - :param kwargs: - :return: - """ - try: - item = self.model(**request.json) - item.validate() - except ValidationError as v: - return jsonify({ - 'status': False, - 'errors': [{"field": field, "error": str(error)} for field, error in v.__dict__.get('errors').items() if - isinstance(error, ValidationError) and field[0] != "_"] - }), 400 - except Exception as e: - return jsonify({ - 'status': False, - 'errors': str(e) - }), 400 - data = item.save() - return self.get(pk=data.id, code=201) - - def put(self, *args, **kwargs): - """ - TODO: check permissions - - :param args: - :param kwargs: - :return: - """ - if "pk" not in kwargs: - return jsonify({ - 'status': False, - "error": "Method not allowed" - }), 403 - else: - try: - self.model.objects(id=kwargs.get('pk')).update(**request.json) - return self.get(pk=kwargs.get('pk')) - except ValidationError as v: - print(v.__dict__) - return jsonify({ - 'status': False, - 'errors': [{"field": v.__dict__.get('field_name'), "error": v.__dict__.get('_message')}] - }), 400 - except InvalidQueryError as e: - return jsonify({ - 'status': False, - 'errors': str(e) - }), 400 - - def has_read_permission(self, request, qs): - return qs - - def has_add_permission(self, request, obj): - return True - - def has_change_permission(self, request, obj): - return True - - def has_delete_permission(self, request, obj): - return True - - def delete(self, *args, **kwargs): - "delete method"