Last active
December 20, 2015 13:39
-
-
Save klinkin/6140977 to your computer and use it in GitHub Desktop.
Setup Pre/Post functions for many resources in Flask-Restless extension
https://github.com/jfinkels/flask-restless/issues/235
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from flask import Flask | |
__all__ = ["create_app"] | |
def create_app(): | |
app = Flask("mcnmapi") | |
configure_blueprints(app) | |
return app | |
def configure_blueprints(app): | |
from mcnmapi.blueprints.partner_api import get_api_blueprints as partner_bps | |
for blueprint in partner_bps(): | |
app.register_blueprint(blueprint) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from mcnmapi.extensions import partner_api_manager | |
from .constants import PARTNER_API_V1_URL_PREFIX | |
from mcnmapi.blueprints import add_cors_header | |
from .resources import (CorporationResource, ...) | |
RESOURCES = [ | |
CorporationResource, | |
... | |
... | |
] | |
def get_api_blueprints(): | |
api_blueprints = [] | |
for ResourceClass in RESOURCES: | |
resource = ResourceClass() | |
options = dict(model=resource.model, | |
collection_name=resource.name, | |
url_prefix=PARTNER_API_V1_URL_PREFIX, | |
methods=resource.methods, | |
allow_patch_many=resource.allow_patch_many, | |
results_per_page=resource.results_per_page, | |
max_results_per_page=resource.results_per_page, | |
exclude_columns=resource.exclude_columns, | |
include_columns=resource.include_columns, | |
preprocessors=resource.preprocessors, | |
postprocessors=resource.postprocessors | |
) | |
bp = partner_api_manager.create_api_blueprint(**options) | |
bp.after_request(add_cors_header) | |
api_blueprints.append(bp) | |
return api_blueprints |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from flask import current_app | |
from werkzeug.local import LocalProxy | |
from flask.ext.security import current_user | |
from .util import check_auth, check_role | |
from mcnmapi.models import Store, Offer | |
from mcnmapi.rqueue.tasks import index_offer, index_store | |
# Convenient references | |
_security = LocalProxy(lambda: current_app.extensions['security']) | |
_datastore = LocalProxy(lambda: _security.datastore) | |
class PostPostProcessor(object): | |
@staticmethod | |
def make_function(model, rules=['read', 'update', 'delete']): | |
def post_postprocessor(result=None, **kw): | |
check_auth() | |
check_role('storeadmin') | |
obj = model.by_id(result.get('id')) | |
# установливаем права текущему пользователю на этот объект | |
for rule in rules: | |
current_user.permit(verb=rule, obj=obj) | |
_datastore.commit() | |
if model == Store: | |
index_store.delay(obj) | |
elif model == Offer: | |
index_offer.delay(obj) | |
return post_postprocessor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from flask.ext.security import current_user | |
from flask.ext.restless import ProcessingException | |
from .util import check_auth | |
class GetSinglePermission(object): | |
@staticmethod | |
def make_function(model, rule='read'): | |
def get_single_preprocessor(instance_id=None, **kw): | |
check_auth() | |
obj = model.by_id(instance_id) | |
if not obj: | |
raise ProcessingException(status_code=404, message='Object not found') | |
perm = current_user.may(verb=rule, obj=obj) | |
if not perm: | |
raise ProcessingException(status_code=403, message='Permission denied') | |
return get_single_preprocessor | |
class GetManyPermission(object): | |
@staticmethod | |
def make_function(model, rule='read'): | |
def get_many_preprocessor(search_params=None, **kw): | |
check_auth() | |
can_read_list = current_user.can_list(verb=rule, model=model) | |
if not can_read_list: | |
raise ProcessingException(status_code=200, message=[]) | |
ids = [obj.id for obj in can_read_list] | |
if 'filters' not in search_params: | |
search_params['filters'] = [{u'name': u'id', u'op': u'in', u'val': ids}] | |
else: | |
search_params['filters'].append({u'name': u'id', u'op': u'in', u'val': ids}) | |
return get_many_preprocessor | |
class PatchSinglePermission(object): | |
@staticmethod | |
def make_function(model, rule='update'): | |
def patch_single_preprocessor(instance_id=None, data=None, **kw): | |
check_auth() | |
obj = model.by_id(instance_id) | |
if not obj: | |
raise ProcessingException(status_code=404, message='Object not found') | |
perm = current_user.may(verb=rule, obj=obj) | |
if not perm: | |
raise ProcessingException(status_code=403, message='Permission denied') | |
return patch_single_preprocessor | |
class PutSinglePermission(object): | |
@staticmethod | |
def make_function(model, rule='update'): | |
def put_single_preprocessor(instance_id=None, data=None, **kw): | |
check_auth() | |
obj = model.by_id(instance_id) | |
if not obj: | |
raise ProcessingException(status_code=404, message='Object not found') | |
perm = current_user.may(verb=rule, obj=obj) | |
if not perm: | |
raise ProcessingException(status_code=403, message='Permission denied') | |
return put_single_preprocessor | |
class PatchManyPermission(object): | |
@staticmethod | |
def make_function(model, rule='update'): | |
def patch_many_preprocessor(search_params=None, data=None, **kw): | |
check_auth() | |
can_read_list = current_user.can_list(verb=rule, model=model) | |
if not can_read_list: | |
raise ProcessingException(status_code=200, message=[]) | |
ids = [obj.id for obj in can_read_list] | |
if 'filters' not in search_params: | |
search_params['filters'] = [{u'name': u'id', u'op': u'in', u'val': ids}] | |
else: | |
search_params['filters'].append({u'name': u'id', u'op': u'in', u'val': ids}) | |
return patch_many_preprocessor | |
class PostPermission(object): | |
@staticmethod | |
def make_function(model, rule='create'): | |
def post_preprocessor(data=None, **kw): | |
check_auth() | |
return post_preprocessor | |
class DeletePermission(object): | |
@staticmethod | |
def make_function(model, rule='delete'): | |
def delete_preprocessor(instance_id=None, **kw): | |
check_auth() | |
obj = model.by_id(instance_id) | |
if not obj: | |
raise ProcessingException(status_code=404, message='Object not found') | |
perm = current_user.may(verb=rule, obj=obj) | |
if not perm: | |
raise ProcessingException(status_code=403, message='Permission denied') | |
return delete_preprocessor |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from ..processors.pre import (GetSinglePermission, GetManyPermission, | |
PatchSinglePermission, PatchManyPermission, | |
PutSinglePermission, PostPermission ,DeletePermission) | |
from ..processors.post import PostPostProcessor | |
from mcnmapi.models import Corporation | |
from ..constants import READONLY_METHODS, WITHOUT_DELETE, ALL_METHODS | |
from ..processors.filters import GetSingleFilterByRole, GetManyFilterByRole | |
from ..processors.util import check_auth | |
class Resource(object): | |
def __init__(self, *args, **kwargs): | |
self.methods = READONLY_METHODS | |
self.allow_patch_many = False | |
self.results_per_page = 50 | |
self.max_results_per_page = 100 | |
self.exclude_columns = None | |
self.include_columns = None | |
self.preprocessors = None | |
self.postprocessors = None | |
def make_preprocessors(self): | |
return { | |
'GET_SINGLE' : [GetSinglePermission.make_function(model=self.model)], | |
'GET_MANY' : [GetManyPermission.make_function(model=self.model)], | |
'PATCH_SINGLE' : [PatchSinglePermission.make_function(model=self.model)], | |
'PATCH_MANY' : [PatchManyPermission.make_function(model=self.model)], | |
'PUT_SINGLE' : [PutSinglePermission.make_function(model=self.model)], | |
'POST' : [PostPermission.make_function(model=self.model)], | |
'DELETE' : [DeletePermission.make_function(model=self.model)] | |
} | |
def make_postprocessors(self): | |
return { | |
'POST' : [PostPostProcessor.make_function(model=self.model)] | |
} | |
class CorporationResource(Resource): | |
""" | |
""" | |
def __init__(self, *args, **kwargs): | |
super(CorporationResource, self).__init__(*args, **kwargs) | |
self.name = 'corporations' | |
self.model = Corporation | |
self.methods = ['GET', 'PUT', 'PATCH'] | |
self.preprocessors = self.make_preprocessors() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# -*- coding: utf-8 -*- | |
from flask.ext.security import current_user | |
from flask.ext.restless import ProcessingException | |
def check_auth(): | |
if not current_user.is_authenticated(): | |
raise ProcessingException(status_code=401, message='Not authenticated!') | |
def check_role(role): | |
if not current_user.has_role(role) and not current_user.corporation: | |
raise ProcessingException(status_code=403, message='Permissions denied!') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment