From 4f95cb7f2f6ad872535eca0d85361ca5fe0726fa Mon Sep 17 00:00:00 2001 From: marcsello Date: Sat, 28 Nov 2020 19:24:58 +0100 Subject: [PATCH 1/3] implemented /content --- src/app.py | 4 ++-- src/views/__init__.py | 1 + src/views/contentview.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/views/contentview.py diff --git a/src/app.py b/src/app.py index d391bc3..05b244e 100644 --- a/src/app.py +++ b/src/app.py @@ -10,7 +10,7 @@ from flask_mail import Mail from utils import Config from utils import health_database_status, init_security_real_good from utils import storage -from views import ItemView, ProfileView, UploadView, IndexView +from views import ItemView, ProfileView, UploadView, IndexView, ContentView from models import db @@ -45,7 +45,7 @@ CORS(app) Mail(app) storage.init_app(app) -for view in [ItemView, ProfileView, UploadView, IndexView]: +for view in [ItemView, ProfileView, UploadView, IndexView, ContentView]: view.register(app, trailing_slash=False) health.add_check(health_database_status) diff --git a/src/views/__init__.py b/src/views/__init__.py index 22493e9..ab1ce67 100644 --- a/src/views/__init__.py +++ b/src/views/__init__.py @@ -2,3 +2,4 @@ from .profileview import ProfileView from .uploadview import UploadView from .itemview import ItemView from .indexview import IndexView +from .contentview import ContentView \ No newline at end of file diff --git a/src/views/contentview.py b/src/views/contentview.py new file mode 100644 index 0000000..a17b8fb --- /dev/null +++ b/src/views/contentview.py @@ -0,0 +1,37 @@ +#!/usr/bin/env python3 +from flask import abort, Response, current_app +from flask_classful import FlaskView +from flask_security import login_required, current_user + +from utils import storage +from minio.error import NoSuchKey + +from models import db, Item, Purchase + + +class ContentView(FlaskView): + """ + This is just a simple content proxy with access control + """ + + def _stream_from_minio(self, bucket: str, filename: str): + try: + data = storage.connection.get_object(bucket, filename) + except NoSuchKey: + abort(404) + + return Response(data.stream(), mimetype=data.headers['Content-type']) + + def preview(self, id_: int): + i = Item.query.get_or_404(id_) + + return self._stream_from_minio(current_app.config['MINIO_PREVIEW_BUCKET_NAME'], str(i.id)) + + @login_required + def caff(self, id_: int): + p = Purchase.query.filter(db.and_(Purchase.purchaser_id == current_user.id, Purchase.item_id == id_)).first() + + if not p: + abort(403) + + return self._stream_from_minio(current_app.config['MINIO_CAFF_BUCKET_NAME'], str(p.item.id)) From beb259b4d80e71feb70b0fe61f492688834d6081 Mon Sep 17 00:00:00 2001 From: marcsello Date: Sat, 28 Nov 2020 20:52:46 +0100 Subject: [PATCH 2/3] Added filename setting for the caff endpoint --- src/views/contentview.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/views/contentview.py b/src/views/contentview.py index a17b8fb..1a2e556 100644 --- a/src/views/contentview.py +++ b/src/views/contentview.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import string from flask import abort, Response, current_app from flask_classful import FlaskView from flask_security import login_required, current_user @@ -14,18 +15,22 @@ class ContentView(FlaskView): This is just a simple content proxy with access control """ - def _stream_from_minio(self, bucket: str, filename: str): + def _stream_from_minio(self, bucket: str, id_: int, filename: str = None): try: - data = storage.connection.get_object(bucket, filename) + data = storage.connection.get_object(bucket, str(id_)) except NoSuchKey: abort(404) - return Response(data.stream(), mimetype=data.headers['Content-type']) + headers = {} + if filename: + headers['Content-Disposition'] = f'attachment; filename="{filename}"' + + return Response(data.stream(), mimetype=data.headers['Content-type'], headers=headers) def preview(self, id_: int): i = Item.query.get_or_404(id_) - return self._stream_from_minio(current_app.config['MINIO_PREVIEW_BUCKET_NAME'], str(i.id)) + return self._stream_from_minio(current_app.config['MINIO_PREVIEW_BUCKET_NAME'], i.id) @login_required def caff(self, id_: int): @@ -34,4 +39,11 @@ class ContentView(FlaskView): if not p: abort(403) - return self._stream_from_minio(current_app.config['MINIO_CAFF_BUCKET_NAME'], str(p.item.id)) + filename = ''.join(filter(lambda x: x in string.ascii_lowercase, p.item.name)) + + if not filename: + filename = str(p.item.id) + + filename += f'_{p.id}.caff' + + return self._stream_from_minio(current_app.config['MINIO_CAFF_BUCKET_NAME'], p.item.id, filename) From 6da7ec2d6718a53d5111ee1a489698c017c409a8 Mon Sep 17 00:00:00 2001 From: marcsello Date: Sat, 28 Nov 2020 20:55:25 +0100 Subject: [PATCH 3/3] Fixed filenames missing some letters --- src/views/contentview.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/views/contentview.py b/src/views/contentview.py index 1a2e556..602d544 100644 --- a/src/views/contentview.py +++ b/src/views/contentview.py @@ -39,7 +39,8 @@ class ContentView(FlaskView): if not p: abort(403) - filename = ''.join(filter(lambda x: x in string.ascii_lowercase, p.item.name)) + allowed_chars = string.ascii_lowercase + string.ascii_uppercase + string.digits + filename = ''.join(filter(lambda x: x in allowed_chars, p.item.name)).lower() if not filename: filename = str(p.item.id)