commit 73c2865f715bbc12ce377bb451e0906717627bdd
parent 42ddf7cfd1f3b6a7547dc0ebc3484970b6ad8d20
Author: ashermorgan <59518073+ashermorgan@users.noreply.github.com>
Date: Sat, 24 Feb 2024 17:14:00 -0800
Implement /slides/ route
Diffstat:
3 files changed, 106 insertions(+), 4 deletions(-)
diff --git a/songs2slides/__init__.py b/songs2slides/__init__.py
@@ -3,7 +3,7 @@ from flask import Flask
def create_app():
app = Flask(__name__)
- with app.app_context():
- from songs2slides import routes
+ from . import routes
+ app.register_blueprint(routes.bp)
return app
diff --git a/songs2slides/routes.py b/songs2slides/routes.py
@@ -1,5 +1,54 @@
-from flask import current_app as app
+from flask import abort, Blueprint, request, send_file
+import tempfile
-@app.route('/')
+from songs2slides import core
+
+bp = Blueprint('main', __name__)
+
+def parse_form(form):
+ """
+ Parse song data from a form
+
+ Parameters
+ ----------
+ form : flask.Request.form
+ The form data
+
+ Returns
+ -------
+ list of core.SongData
+ The parsed song information
+ """
+
+ songs = []
+ try:
+ i = 1
+ while f'title-{i}' in request.form:
+ songs += [core.SongData(
+ form[f'title-{i}'],
+ form[f'artist-{i}'],
+ form.get(f'lyrics-{i}', None)
+ )]
+ i += 1
+ except:
+ abort(400)
+ else:
+ return songs
+
+@bp.route('/')
def index():
return '<p>Hello world</p>'
+
+@bp.post('/slides/')
+def slides():
+ # Parse form data
+ songs = parse_form(request.form)
+
+ # Assemble slides
+ slides = core.assemble_slides(songs, lines_per_slide = None)
+
+ # Create and send powerpoint
+ with tempfile.NamedTemporaryFile(suffix='.pptx') as f:
+ core.create_pptx(slides, f.name)
+ return send_file(f.name, as_attachment=True,
+ download_name='slides.pptx')
diff --git a/tests/test_routes.py b/tests/test_routes.py
@@ -0,0 +1,53 @@
+import unittest
+from unittest.mock import patch, call
+
+from songs2slides import create_app, core
+
+class TestRoutes(unittest.TestCase):
+ def setUp(self):
+ self.app = create_app()
+ self.client = self.app.test_client()
+
+ def test_slides_basic(self):
+ with patch('songs2slides.core.assemble_slides') as mocked_assemble, \
+ patch('songs2slides.core.create_pptx') as mocked_create, \
+ patch('songs2slides.routes.send_file') as mocked_send:
+
+ # Send request
+ self.client.post('/slides/', data={
+ 'title-1': 'T1',
+ 'artist-1': 'A1',
+ 'lyrics-1': 'L1',
+ 'title-2': 'T2',
+ 'artist-2': 'A2',
+ 'lyrics-2': 'L2',
+ })
+
+ # Assert mocks called correctly
+ mocked_assemble.assert_called_with([
+ core.SongData('T1', 'A1', 'L1'),
+ core.SongData('T2', 'A2', 'L2'),
+ ],
+ lines_per_slide = None
+ )
+ file = mocked_create.call_args.args[1]
+ mocked_send.assert_called_with(file, as_attachment=True,
+ download_name='slides.pptx')
+
+ def test_slides_mising_artist(self):
+ with patch('songs2slides.core.assemble_slides') as mocked_assemble:
+
+ # Send request
+ res = self.client.post('/slides/', data={
+ 'title-1': 'T1',
+ 'artist-1': 'A1',
+ 'lyrics-1': 'L1',
+ 'title-2': 'T2',
+ 'lyrics-2': 'L2',
+ })
+
+ # Assert response has 400 status code
+ self.assertEqual(res.status_code, 400)
+
+ # Assert assemble_slides not called
+ mocked_assemble.assert_not_called()