diff options
Diffstat (limited to 'newspipe/web/views/api')
-rw-r--r-- | newspipe/web/views/api/v2/__init__.py | 2 | ||||
-rw-r--r-- | newspipe/web/views/api/v2/article.py | 32 | ||||
-rw-r--r-- | newspipe/web/views/api/v2/category.py | 15 | ||||
-rw-r--r-- | newspipe/web/views/api/v2/common.py | 64 | ||||
-rw-r--r-- | newspipe/web/views/api/v2/feed.py | 34 | ||||
-rw-r--r-- | newspipe/web/views/api/v3/__init__.py | 2 | ||||
-rw-r--r-- | newspipe/web/views/api/v3/article.py | 36 | ||||
-rw-r--r-- | newspipe/web/views/api/v3/common.py | 28 | ||||
-rw-r--r-- | newspipe/web/views/api/v3/feed.py | 24 |
9 files changed, 125 insertions, 112 deletions
diff --git a/newspipe/web/views/api/v2/__init__.py b/newspipe/web/views/api/v2/__init__.py index 46760261..ef587e72 100644 --- a/newspipe/web/views/api/v2/__init__.py +++ b/newspipe/web/views/api/v2/__init__.py @@ -1,3 +1,3 @@ from web.views.api.v2 import article, feed, category -__all__ = ['article', 'feed', 'category'] +__all__ = ["article", "feed", "category"] diff --git a/newspipe/web/views/api/v2/article.py b/newspipe/web/views/api/v2/article.py index 2be286c6..8da6c6dd 100644 --- a/newspipe/web/views/api/v2/article.py +++ b/newspipe/web/views/api/v2/article.py @@ -6,8 +6,12 @@ from flask_restful import Api from web.views.common import api_permission from web.controllers import ArticleController -from web.views.api.v2.common import (PyAggAbstractResource, - PyAggResourceNew, PyAggResourceExisting, PyAggResourceMulti) +from web.views.api.v2.common import ( + PyAggAbstractResource, + PyAggResourceNew, + PyAggResourceExisting, + PyAggResourceMulti, +) class ArticleNewAPI(PyAggResourceNew): @@ -24,30 +28,32 @@ class ArticlesAPI(PyAggResourceMulti): class ArticlesChallenge(PyAggAbstractResource): controller_cls = ArticleController - attrs = {'ids': {'type': list, 'default': []}} + attrs = {"ids": {"type": list, "default": []}} @api_permission.require(http_exception=403) def get(self): - parsed_args = self.reqparse_args(right='read') + parsed_args = self.reqparse_args(right="read") # collecting all attrs for casting purpose - attrs = self.controller_cls._get_attrs_desc('admin') - for id_dict in parsed_args['ids']: + attrs = self.controller_cls._get_attrs_desc("admin") + for id_dict in parsed_args["ids"]: keys_to_ignore = [] for key in id_dict: if key not in attrs: keys_to_ignore.append(key) - if issubclass(attrs[key]['type'], datetime): + if issubclass(attrs[key]["type"], datetime): id_dict[key] = dateutil.parser.parse(id_dict[key]) for key in keys_to_ignore: del id_dict[key] - result = list(self.controller.challenge(parsed_args['ids'])) + result = list(self.controller.challenge(parsed_args["ids"])) return result or None, 200 if result else 204 + api = Api(current_app, prefix=API_ROOT) -api.add_resource(ArticleNewAPI, '/article', endpoint='article_new.json') -api.add_resource(ArticleAPI, '/article/<int:obj_id>', endpoint='article.json') -api.add_resource(ArticlesAPI, '/articles', endpoint='articles.json') -api.add_resource(ArticlesChallenge, '/articles/challenge', - endpoint='articles_challenge.json') +api.add_resource(ArticleNewAPI, "/article", endpoint="article_new.json") +api.add_resource(ArticleAPI, "/article/<int:obj_id>", endpoint="article.json") +api.add_resource(ArticlesAPI, "/articles", endpoint="articles.json") +api.add_resource( + ArticlesChallenge, "/articles/challenge", endpoint="articles_challenge.json" +) diff --git a/newspipe/web/views/api/v2/category.py b/newspipe/web/views/api/v2/category.py index 70fda1ea..a830624d 100644 --- a/newspipe/web/views/api/v2/category.py +++ b/newspipe/web/views/api/v2/category.py @@ -3,9 +3,11 @@ from flask import current_app from flask_restful import Api from web.controllers.category import CategoryController -from web.views.api.v2.common import (PyAggResourceNew, - PyAggResourceExisting, - PyAggResourceMulti) +from web.views.api.v2.common import ( + PyAggResourceNew, + PyAggResourceExisting, + PyAggResourceMulti, +) class CategoryNewAPI(PyAggResourceNew): @@ -21,7 +23,6 @@ class CategoriesAPI(PyAggResourceMulti): api = Api(current_app, prefix=API_ROOT) -api.add_resource(CategoryNewAPI, '/category', endpoint='category_new.json') -api.add_resource(CategoryAPI, '/category/<int:obj_id>', - endpoint='category.json') -api.add_resource(CategoriesAPI, '/categories', endpoint='categories.json') +api.add_resource(CategoryNewAPI, "/category", endpoint="category_new.json") +api.add_resource(CategoryAPI, "/category/<int:obj_id>", endpoint="category.json") +api.add_resource(CategoriesAPI, "/categories", endpoint="categories.json") diff --git a/newspipe/web/views/api/v2/common.py b/newspipe/web/views/api/v2/common.py index 8a53d7e6..81248422 100644 --- a/newspipe/web/views/api/v2/common.py +++ b/newspipe/web/views/api/v2/common.py @@ -26,8 +26,12 @@ from flask import request from flask_restful import Resource, reqparse from flask_login import current_user -from web.views.common import admin_permission, api_permission, \ - login_user_bundle, jsonify +from web.views.common import ( + admin_permission, + api_permission, + login_user_bundle, + jsonify, +) from web.controllers import UserController logger = logging.getLogger(__name__) @@ -50,6 +54,7 @@ def authenticate(func): if current_user.is_authenticated: return func(*args, **kwargs) raise Unauthorized() + return wrapper @@ -64,8 +69,9 @@ class PyAggAbstractResource(Resource): return self.controller_cls() return self.controller_cls(current_user.id) - def reqparse_args(self, right, req=None, strict=False, default=True, - allow_empty=False): + def reqparse_args( + self, right, req=None, strict=False, default=True, allow_empty=False + ): """ strict: bool if True will throw 400 error if args are defined and not in request @@ -89,42 +95,41 @@ class PyAggAbstractResource(Resource): if self.attrs is not None: attrs = self.attrs elif admin_permission.can(): - attrs = self.controller_cls._get_attrs_desc('admin') + attrs = self.controller_cls._get_attrs_desc("admin") elif api_permission.can(): - attrs = self.controller_cls._get_attrs_desc('api', right) + attrs = self.controller_cls._get_attrs_desc("api", right) else: - attrs = self.controller_cls._get_attrs_desc('base', right) + attrs = self.controller_cls._get_attrs_desc("base", right) assert attrs, "No defined attrs for %s" % self.__class__.__name__ for attr_name, attr in attrs.items(): if not default and attr_name not in in_values: continue else: - parser.add_argument(attr_name, location='json', - default=in_values[attr_name]) + parser.add_argument( + attr_name, location="json", default=in_values[attr_name] + ) return parser.parse_args(req=request.args, strict=strict) class PyAggResourceNew(PyAggAbstractResource): - @api_permission.require(http_exception=403) def post(self): """Create a single new object""" - return self.controller.create(**self.reqparse_args(right='write')), 201 + return self.controller.create(**self.reqparse_args(right="write")), 201 class PyAggResourceExisting(PyAggAbstractResource): - def get(self, obj_id=None): """Retrieve a single object""" return self.controller.get(id=obj_id) def put(self, obj_id=None): """update an object, new attrs should be passed in the payload""" - args = self.reqparse_args(right='write', default=False) + args = self.reqparse_args(right="write", default=False) if not args: raise BadRequest() - return self.controller.update({'id': obj_id}, args), 200 + return self.controller.update({"id": obj_id}, args), 200 def delete(self, obj_id=None): """delete a object""" @@ -133,19 +138,18 @@ class PyAggResourceExisting(PyAggAbstractResource): class PyAggResourceMulti(PyAggAbstractResource): - def get(self): """retrieve several objects. filters can be set in the payload on the different fields of the object, and a limit can be set in there as well """ args = {} try: - limit = request.json.pop('limit', 10) - order_by = request.json.pop('order_by', None) + limit = request.json.pop("limit", 10) + order_by = request.json.pop("order_by", None) except Exception: - args = self.reqparse_args(right='read', default=False) - limit = request.args.get('limit', 10) - order_by = request.args.get('order_by', None) + args = self.reqparse_args(right="read", default=False) + limit = request.args.get("limit", 10) + order_by = request.args.get("order_by", None) query = self.controller.read(**args) if order_by: query = query.order_by(order_by) @@ -163,10 +167,11 @@ class PyAggResourceMulti(PyAggAbstractResource): class Proxy: pass + for attrs in request.json: try: Proxy.json = attrs - args = self.reqparse_args('write', req=Proxy, default=False) + args = self.reqparse_args("write", req=Proxy, default=False) obj = self.controller.create(**args) results.append(obj) except Exception as error: @@ -188,20 +193,21 @@ class PyAggResourceMulti(PyAggAbstractResource): class Proxy: pass + for obj_id, attrs in request.json: try: Proxy.json = attrs - args = self.reqparse_args('write', req=Proxy, default=False) - result = self.controller.update({'id': obj_id}, args) + args = self.reqparse_args("write", req=Proxy, default=False) + result = self.controller.update({"id": obj_id}, args) if result: - results.append('ok') + results.append("ok") else: - results.append('nok') + results.append("nok") except Exception as error: results.append(str(error)) - if results.count('ok') == 0: # all failed => 500 + if results.count("ok") == 0: # all failed => 500 status = 500 - elif results.count('ok') != len(results): # some failed => 206 + elif results.count("ok") != len(results): # some failed => 206 status = 206 return results, status @@ -212,11 +218,11 @@ class PyAggResourceMulti(PyAggAbstractResource): for obj_id in request.json: try: self.controller.delete(obj_id) - results.append('ok') + results.append("ok") except Exception as error: status = 206 results.append(error) # if no operation succeeded, it's not partial anymore, returning err 500 - if status == 206 and results.count('ok') == 0: + if status == 206 and results.count("ok") == 0: status = 500 return results, status diff --git a/newspipe/web/views/api/v2/feed.py b/newspipe/web/views/api/v2/feed.py index a0691277..1e4fabf2 100644 --- a/newspipe/web/views/api/v2/feed.py +++ b/newspipe/web/views/api/v2/feed.py @@ -3,14 +3,14 @@ from flask import current_app from flask_restful import Api from web.views.common import api_permission -from web.controllers.feed import (FeedController, - DEFAULT_MAX_ERROR, - DEFAULT_LIMIT) +from web.controllers.feed import FeedController, DEFAULT_MAX_ERROR, DEFAULT_LIMIT -from web.views.api.v2.common import PyAggAbstractResource, \ - PyAggResourceNew, \ - PyAggResourceExisting, \ - PyAggResourceMulti +from web.views.api.v2.common import ( + PyAggAbstractResource, + PyAggResourceNew, + PyAggResourceExisting, + PyAggResourceMulti, +) class FeedNewAPI(PyAggResourceNew): @@ -27,21 +27,21 @@ class FeedsAPI(PyAggResourceMulti): class FetchableFeedAPI(PyAggAbstractResource): controller_cls = FeedController - attrs = {'max_error': {'type': int, 'default': DEFAULT_MAX_ERROR}, - 'limit': {'type': int, 'default': DEFAULT_LIMIT}} + attrs = { + "max_error": {"type": int, "default": DEFAULT_MAX_ERROR}, + "limit": {"type": int, "default": DEFAULT_LIMIT}, + } @api_permission.require(http_exception=403) def get(self): - args = self.reqparse_args(right='read', allow_empty=True) - result = [feed for feed - in self.controller.list_fetchable(**args)] + args = self.reqparse_args(right="read", allow_empty=True) + result = [feed for feed in self.controller.list_fetchable(**args)] return result or None, 200 if result else 204 api = Api(current_app, prefix=API_ROOT) -api.add_resource(FeedNewAPI, '/feed', endpoint='feed_new.json') -api.add_resource(FeedAPI, '/feed/<int:obj_id>', endpoint='feed.json') -api.add_resource(FeedsAPI, '/feeds', endpoint='feeds.json') -api.add_resource(FetchableFeedAPI, '/feeds/fetchable', - endpoint='fetchable_feed.json') +api.add_resource(FeedNewAPI, "/feed", endpoint="feed_new.json") +api.add_resource(FeedAPI, "/feed/<int:obj_id>", endpoint="feed.json") +api.add_resource(FeedsAPI, "/feeds", endpoint="feeds.json") +api.add_resource(FetchableFeedAPI, "/feeds/fetchable", endpoint="fetchable_feed.json") diff --git a/newspipe/web/views/api/v3/__init__.py b/newspipe/web/views/api/v3/__init__.py index 76aa1f19..5066b0b6 100644 --- a/newspipe/web/views/api/v3/__init__.py +++ b/newspipe/web/views/api/v3/__init__.py @@ -1,3 +1,3 @@ from web.views.api.v3 import article -__all__ = ['article'] +__all__ = ["article"] diff --git a/newspipe/web/views/api/v3/article.py b/newspipe/web/views/api/v3/article.py index 4cf35648..04d19552 100644 --- a/newspipe/web/views/api/v3/article.py +++ b/newspipe/web/views/api/v3/article.py @@ -35,6 +35,7 @@ from web.controllers import ArticleController, FeedController from web.views.api.v3.common import AbstractProcessor from web.views.api.v3.common import url_prefix, auth_func + class ArticleProcessor(AbstractProcessor): """Concrete processors for the Article Web service. """ @@ -43,7 +44,7 @@ class ArticleProcessor(AbstractProcessor): try: article = ArticleController(current_user.id).get(id=instance_id) except NotFound: - raise ProcessingException(description='No such article.', code=404) + raise ProcessingException(description="No such article.", code=404) self.is_authorized(current_user, article) def post_preprocessor(self, data=None, **kw): @@ -52,7 +53,7 @@ class ArticleProcessor(AbstractProcessor): try: feed = FeedController(current_user.id).get(id=data["feed_id"]) except NotFound: - raise ProcessingException(description='No such feed.', code=404) + raise ProcessingException(description="No such feed.", code=404) self.is_authorized(current_user, feed) data["category_id"] = feed.category_id @@ -61,24 +62,23 @@ class ArticleProcessor(AbstractProcessor): try: article = ArticleController(current_user.id).get(id=instance_id) except NotFound: - raise ProcessingException(description='No such article.', code=404) + raise ProcessingException(description="No such article.", code=404) self.is_authorized(current_user, article) + article_processor = ArticleProcessor() -blueprint_article = manager.create_api_blueprint(models.Article, - url_prefix=url_prefix, - methods=['GET', 'POST', 'PUT', 'DELETE'], - preprocessors=dict(GET_SINGLE=[auth_func, - article_processor.get_single_preprocessor], - GET_MANY=[auth_func, - article_processor.get_many_preprocessor], - POST=[auth_func, - article_processor.post_preprocessor], - PUT_SINGLE=[auth_func, - article_processor.put_single_preprocessor], - PUT_MANY=[auth_func, - article_processor.put_many_preprocessor], - DELETE=[auth_func, - article_processor.delete_preprocessor])) +blueprint_article = manager.create_api_blueprint( + models.Article, + url_prefix=url_prefix, + methods=["GET", "POST", "PUT", "DELETE"], + preprocessors=dict( + GET_SINGLE=[auth_func, article_processor.get_single_preprocessor], + GET_MANY=[auth_func, article_processor.get_many_preprocessor], + POST=[auth_func, article_processor.post_preprocessor], + PUT_SINGLE=[auth_func, article_processor.put_single_preprocessor], + PUT_MANY=[auth_func, article_processor.put_many_preprocessor], + DELETE=[auth_func, article_processor.delete_preprocessor], + ), +) application.register_blueprint(blueprint_article) diff --git a/newspipe/web/views/api/v3/common.py b/newspipe/web/views/api/v3/common.py index d5e94a3f..5467ee30 100644 --- a/newspipe/web/views/api/v3/common.py +++ b/newspipe/web/views/api/v3/common.py @@ -33,7 +33,8 @@ from werkzeug.exceptions import NotFound from web.controllers import ArticleController, UserController from web.views.common import login_user_bundle -url_prefix = '/api/v3' +url_prefix = "/api/v3" + def auth_func(*args, **kw): if request.authorization: @@ -41,24 +42,23 @@ def auth_func(*args, **kw): try: user = ucontr.get(nickname=request.authorization.username) except NotFound: - raise ProcessingException("Couldn't authenticate your user", - code=401) + raise ProcessingException("Couldn't authenticate your user", code=401) if not ucontr.check_password(user, request.authorization.password): - raise ProcessingException("Couldn't authenticate your user", - code=401) + raise ProcessingException("Couldn't authenticate your user", code=401) if not user.is_active: raise ProcessingException("User is deactivated", code=401) login_user_bundle(user) if not current_user.is_authenticated: - raise ProcessingException(description='Not authenticated!', code=401) + raise ProcessingException(description="Not authenticated!", code=401) + -class AbstractProcessor(): +class AbstractProcessor: """Abstract processors for the Web services. """ def is_authorized(self, user, obj): if user.id != obj.user_id: - raise ProcessingException(description='Not Authorized', code=401) + raise ProcessingException(description="Not Authorized", code=401) def get_single_preprocessor(self, instance_id=None, **kw): # Check if the user is authorized to modify the specified @@ -69,13 +69,11 @@ class AbstractProcessor(): """Accepts a single argument, `search_params`, which is a dictionary containing the search parameters for the request. """ - filt = dict(name="user_id", - op="eq", - val=current_user.id) + filt = dict(name="user_id", op="eq", val=current_user.id) # Check if there are any filters there already. if "filters" not in search_params: - search_params["filters"] = [] + search_params["filters"] = [] search_params["filters"].append(filt) @@ -95,13 +93,11 @@ class AbstractProcessor(): is a dictionary representing the fields to change on the matching instances and the values to which they will be set. """ - filt = dict(name="user_id", - op="eq", - val=current_user.id) + filt = dict(name="user_id", op="eq", val=current_user.id) # Check if there are any filters there already. if "filters" not in search_params: - search_params["filters"] = [] + search_params["filters"] = [] search_params["filters"].append(filt) diff --git a/newspipe/web/views/api/v3/feed.py b/newspipe/web/views/api/v3/feed.py index 2cbbafd9..9d2c9180 100644 --- a/newspipe/web/views/api/v3/feed.py +++ b/newspipe/web/views/api/v3/feed.py @@ -33,6 +33,7 @@ from web.controllers import FeedController from web.views.api.v3.common import AbstractProcessor from web.views.api.v3.common import url_prefix, auth_func + class FeedProcessor(AbstractProcessor): """Concrete processors for the Feed Web service. """ @@ -43,16 +44,19 @@ class FeedProcessor(AbstractProcessor): feed = FeedController(current_user.id).get(id=instance_id) self.is_authorized(current_user, feed) + feed_processor = FeedProcessor() -blueprint_feed = manager.create_api_blueprint(models.Feed, - url_prefix=url_prefix, - methods=['GET', 'POST', 'PUT', 'DELETE'], - preprocessors=dict(GET_SINGLE=[auth_func, - feed_processor.get_single_preprocessor], - GET_MANY=[auth_func, - feed_processor.get_many_preprocessor], - PUT_SINGLE=[auth_func], - POST=[auth_func], - DELETE=[auth_func])) +blueprint_feed = manager.create_api_blueprint( + models.Feed, + url_prefix=url_prefix, + methods=["GET", "POST", "PUT", "DELETE"], + preprocessors=dict( + GET_SINGLE=[auth_func, feed_processor.get_single_preprocessor], + GET_MANY=[auth_func, feed_processor.get_many_preprocessor], + PUT_SINGLE=[auth_func], + POST=[auth_func], + DELETE=[auth_func], + ), +) application.register_blueprint(blueprint_feed) |