aboutsummaryrefslogtreecommitdiff
path: root/newspipe/web/views/api
diff options
context:
space:
mode:
authorCédric Bonhomme <cedric@cedricbonhomme.org>2020-02-26 15:20:54 +0100
committerCédric Bonhomme <cedric@cedricbonhomme.org>2020-02-26 15:20:54 +0100
commitc0d48f8a060fa30107183ad024e8c03cfee0eb26 (patch)
treee1aab8c092be0c2bd1e51d6ac09187096490652f /newspipe/web/views/api
parentRemoved sendgrid dependency. (diff)
downloadnewspipe-c0d48f8a060fa30107183ad024e8c03cfee0eb26.tar.gz
newspipe-c0d48f8a060fa30107183ad024e8c03cfee0eb26.tar.bz2
newspipe-c0d48f8a060fa30107183ad024e8c03cfee0eb26.zip
added a little black magic
Diffstat (limited to 'newspipe/web/views/api')
-rw-r--r--newspipe/web/views/api/v2/__init__.py2
-rw-r--r--newspipe/web/views/api/v2/article.py32
-rw-r--r--newspipe/web/views/api/v2/category.py15
-rw-r--r--newspipe/web/views/api/v2/common.py64
-rw-r--r--newspipe/web/views/api/v2/feed.py34
-rw-r--r--newspipe/web/views/api/v3/__init__.py2
-rw-r--r--newspipe/web/views/api/v3/article.py36
-rw-r--r--newspipe/web/views/api/v3/common.py28
-rw-r--r--newspipe/web/views/api/v3/feed.py24
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)
bgstack15