Skip to content

Instantly share code, notes, and snippets.

@klinkin
Last active December 20, 2015 13:39
Show Gist options
  • Save klinkin/6140977 to your computer and use it in GitHub Desktop.
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
#!/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)
#!/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
#!/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
#!/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
#!/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()
#!/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