From 6ec316eefe23051e9e89c6dd84669f3d68697740 Mon Sep 17 00:00:00 2001 From: Noor Syed Date: Thu, 19 Jan 2023 12:06:11 -0500 Subject: [PATCH] RDISCROWD-5567 Enhance task guidelines images (#803) * added upload_task_guidelines_image route * add security checks * add errors to response * implement uploading and file size check * remove test flash * add file size tests * fix typo in test description * added multiple file uploads test * use send 413 response code on large file * refactor errors to error * switch to small images * remove added files * Delete setuplogins.py * use magic number for max image upload size * edit settings_local template * edit settings_test template * use default value for MAX_IMAGE_UPLOAD_SIZE_MB * initial push for edge case tests * refactor and fix edge cases test * bump theme SHA Co-authored-by: nsyed22 --- dump.rdb | Bin 0 -> 4710 bytes pybossa/settings_local.py.tmpl | 2 + pybossa/themes/default | 2 +- pybossa/view/projects.py | 57 ++++++++++++- settings_test.py.tmpl | 2 + test/files/small-image1.jpg | Bin 0 -> 3623 bytes test/files/small-image2.jpg | Bin 0 -> 5156 bytes test/test_web.py | 151 +++++++++++++++++++++++++++++++++ 8 files changed, 212 insertions(+), 2 deletions(-) create mode 100644 dump.rdb create mode 100644 test/files/small-image1.jpg create mode 100644 test/files/small-image2.jpg diff --git a/dump.rdb b/dump.rdb new file mode 100644 index 0000000000000000000000000000000000000000..c847861cf44fd1122c50e4f8b00a6dbaebfac20b GIT binary patch literal 4710 zcmds*TWl0n7{{mWZtpI%SX)a?hoqsD^=#&Tsge}s5?UonL8>p?Gc#w}WoKu~T&Oew ztHuXqQDe47jJ_D5HfjJb!N&!xNyQk5#*p9x2@gaQAFxkUVm;gGZrReMi<+3aFS~n^ zo%x^hoA3MozumQU%Z^@(qU4z>8)-2I96)xEk5CbDrrKXnVy=_!nhC0IEP>8__{bS` zrqXke1`;T7?$p{!Vx|^aIvBDMOeh9Q6Mqta)DVHNy}xsxrF0^NRVbuGfHYA6oUZ6V zrUezSqQdGjt%@3?LxBWx;X|Xrv3kOP9ZDrDW2TGj1JFo4nf}O$R68!TU8F^!ON0#Q zxY0p`7ZilQH|Q{Ccs7cv&@dFJ#-k=oAfghPn*Rg56~{B&sOuW(*>Zd(*K;aWXsXCS zTDfJ%24ZH&Q3sLc;e{yH?KC)^sv^f(bj@lN@6(sDmZ2CHP&Am4LPbE8**co`S8#|#c~`N$=o4=%>5qnP;>~{F-wc7bNAiQp1>Tu zM0-a-gD&ja`uuzG{`dEtB}$q%bqB|G+?!KbJ0?da4!&}H;`qdk;KbHrH#?3^ z-5@V@96sGUa@p?fWqO?Pwx4!(9Q&Yxn7Y+eRWoeaab)}Fl4Bzwfu<-O6G1!$I8o(+ zBGNM8cnT?kPRk4heKxI_&HYQU=_Zc06Dx;~NHe^&K&P_eb~>OaI+p1U8V9p@w)uFb z?g5W8J>AXN8*_ZFO*M@z&4kcD@KI4b|?YJ5+wmm6%faYh?V7K`HVhYvV!;s zvcysgeDbTOqZmGhHJoMhn9t_h;@Q08{C*+F<>l)S{J1n1R@4MWKmx9OfyP`|4oDJ1 z0iG8XT1PCW%c@^DEx2y#ma3bcM^{eK2n-`|g`m*IKuN$%GdD90Hw&lRhjXELIA1wy z*y-+F)AiGD_2wXLzuw%iG$cXeC?xYL&_qcC93?RT$~p%$9my;dRHRGN{|OSs7OtFd zF^~|ZWMuJd@$r0LJf6N@%*Q#Ab)C~Ajj!i{sa=Z`LDpmK+$Y~{&u@Neb370)Aqb5u zYh6tcZH%I-P}U$2S&0LjDsZ?9Y8sHCC^f1`RXL;!>o1OhGirHTwo#JnnhG|`bhtLJ zZprYPrRp{v4sk361rZ{k2rM>3vab$E8mj|_lU0u4kitVf9d2Fj0V~TqVd-$g(k@HF zss)$5N}R0C3rgfkLLvE8i-S^nZxbiT6elYTP#B5@oWij{fwTZbvaN)Z$WN*e&8)xJ zu&G^}t!>69o=rJ-9Qe+^ci?aTM+bhD2)7j4I?j-I>l;e(*8e$|qj_AeEaGw{!=>hS zF63(j-M_a)oekE`S6Ng?NGt35Vl*%|k?Z{%k`?pOF_mo2PmZ+IN%Ii_dx^-Vl7UQi zO(iS*#75&Ftb2wrw>TI`24bderEom1GNaIRhLP>0b|ynM8i+YKE@$HIfQ45AHZq~W{nagd$zBK+6CuKVt{%bU-4ecJU| z0PkR&7$sT{rS2|2i1qUvLzdo`(;vh$f=z}3bL#u+TbI*bkrhwY1?I$)6+vG-SsC=j zlh3SLEPnLOlE5C)D8<}jZ@pXB*p}y8IW7e|?_B%Ao`BoWveVM|ffba-MTVyfPD_zu$n5uUd$AYB zrR_eQ$>Qlq)jex^b{)BGUb;2)U|9h|`NoY0raO&$xytD)T|t$@N-|rha*E1)j)(tz pSX4UqlKGDGy!cXYeSAFi#HBLg^OnXh^T5pR{$=/tasks/taskpresenterimageupload', methods=['GET', 'POST']) +@login_required +@admin_or_subadmin_required +@csrf.exempt +def upload_task_guidelines_image(short_name): + error = False + return_code = 200 + project = project_by_shortname(short_name) + + imgurls = [] + if is_editor_disabled(): + flash(gettext('Task presenter editor disabled!'), 'error') + error = True + return_code = 400 + elif not is_admin_or_owner(project): + flash(gettext('Ooops! Only project owners can upload files.'), 'error') + error = True + return_code = 400 + else: + for file in request.files.getlist("image"): + file_size_mb = file.seek(0, os.SEEK_END) / 1024 / 1024 + file.seek(0, os.SEEK_SET) + file.filename = secure_filename(file.filename) + if file_size_mb < current_app.config.get('MAX_IMAGE_UPLOAD_SIZE_MB', 5): + container = "user_%s" % current_user.id + uploader.upload_file(file, container=container) + imgurls.append(get_avatar_url( + current_app.config.get('UPLOAD_METHOD'), + file.filename, + container, + current_app.config.get('AVATAR_ABSOLUTE') + )) + else: + flash(gettext('File must be smaller than ' + str(current_app.config.get('MAX_IMAGE_UPLOAD_SIZE_MB', 5)) + ' MB.')) + error = True + return_code = 413 + + response = { + "imgurls" : imgurls, + "error": error + } + + return jsonify(response), return_code + @blueprint.route('//tasks/taskpresentereditor', methods=['GET', 'POST']) @login_required @admin_or_subadmin_required diff --git a/settings_test.py.tmpl b/settings_test.py.tmpl index fd205679ae..bcf8c3a92c 100644 --- a/settings_test.py.tmpl +++ b/settings_test.py.tmpl @@ -245,3 +245,5 @@ COMPLETED_TASK_CLEANUP_DAYS = [ (90, "90 days"), (180, "180 days") ] + +MAX_IMAGE_UPLOAD_SIZE_MB = 5 diff --git a/test/files/small-image1.jpg b/test/files/small-image1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..61630bf23d87229fe20ae728cad51292cf7ba9fa GIT binary patch literal 3623 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 B(dhsH literal 0 HcmV?d00001 diff --git a/test/files/small-image2.jpg b/test/files/small-image2.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ea61c63560f0b1698ef933f4cfcf5d58880cc6f6 GIT binary patch literal 5156 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 c!fWIS4_nd7Pd0n8G}r~m)} literal 0 HcmV?d00001 diff --git a/test/test_web.py b/test/test_web.py index d8997cd57a..2df77511b9 100644 --- a/test/test_web.py +++ b/test/test_web.py @@ -28,6 +28,7 @@ from test import db, Fixtures, with_context, with_context_settings, \ FakeResponse, mock_contributions_guard, with_request_context from test.helper import web +from test.test_authorization import mock_current_user from unittest.mock import patch, Mock, call, MagicMock from flask import redirect from itsdangerous import BadSignature @@ -4693,6 +4694,156 @@ def test_48_task_presenter_editor_works_json(self, mock): assert data['form']['guidelines'] == 'Some guidelines!', data + @with_context + @patch('pybossa.view.projects.uploader.upload_file', return_value=True) + def test_task_presenter_large_image_upload(self, mock): + """Test API /tasks/taskpresenterimageupload should not upload images with size > 5 MB""" + print("running test_task_presenter_large_image_upload...") + user = UserFactory.create(id=500) + project = ProjectFactory.create( + short_name='test_project', + name='Test Project', + info={ + 'total': 150, + 'task_presenter': 'foo', + 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), + 'kpi': 0.5, + 'product': 'abc', + 'subproduct': 'def', + }, + owner=user) + headers = [('Authorization', user.api_key)] + with open('./test/files/small-image1.jpg', 'rb') as img: + imgStringIO = BytesIO(img.read()) + with patch.dict(self.flask_app.config, {'MAX_IMAGE_UPLOAD_SIZE_MB': 0}): + # Call API method to upload image. + res = self.app.post('/project/{}/tasks/taskpresenterimageupload'.format(project.short_name), headers=headers, data={'image': (imgStringIO, 'large-image.jpg')}) + res_data = json.loads(res.data) + assert res.status_code == 413, "POST image upload should yield 413" + assert len(res_data['imgurls']) == 0, "Successful count of uploaded images 0." + assert res_data['error'] == True, "There should be an error for a file larger than 5 MB." + + @with_context + @patch('pybossa.view.projects.uploader.upload_file', return_value=True) + def test_task_presenter_image_upload(self, mock): + """Test API /tasks/taskpresenterimageupload to upload a task presenter guidelines image""" + print("running test_task_presenter_image_upload...") + user = UserFactory.create(id=500) + project = ProjectFactory.create( + short_name='test_project', + name='Test Project', + info={ + 'total': 150, + 'task_presenter': 'foo', + 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), + 'kpi': 0.5, + 'product': 'abc', + 'subproduct': 'def', + }, + owner=user) + headers = [('Authorization', user.api_key)] + with open('./test/files/small-image1.jpg', 'rb') as img: + imgStringIO = BytesIO(img.read()) + # Call API method to upload image. + res = self.app.post('/project/{}/tasks/taskpresenterimageupload'.format(project.short_name), headers=headers, data={'image': (imgStringIO, 'large-image.jpg')}) + res_data = json.loads(res.data) + assert res.status_code == 200, "POST image upload should be successful" + assert len(res_data['imgurls']) == 1, "Successful count of uploaded images 1." + assert res_data['error'] == False, "There should be no errors for normal file upload" + + @with_context + @patch('pybossa.view.projects.uploader.upload_file', return_value=True) + def test_task_presenter_multiple_image_upload(self, mock): + """Test API /tasks/taskpresenterimageupload to upload multiple task presenter guidelines images""" + print("running test_task_presenter_multiple_image_upload...") + user = UserFactory.create(id=500) + project = ProjectFactory.create( + short_name='test_project', + name='Test Project', + info={ + 'total': 150, + 'task_presenter': 'foo', + 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), + 'kpi': 0.5, + 'product': 'abc', + 'subproduct': 'def', + }, + owner=user) + headers = [('Authorization', user.api_key)] + with open('./test/files/small-image1.jpg', 'rb') as img1: + imgStringIO1 = BytesIO(img1.read()) + with open('./test/files/small-image2.jpg', 'rb') as img2: + imgStringIO2 = BytesIO(img2.read()) + # Call API method to upload image. + res = self.app.post('/project/{}/tasks/taskpresenterimageupload'.format(project.short_name), headers=headers, data={'image': + [(imgStringIO1, 'img1.jpg'), (imgStringIO2, 'img2.jpg')] + }) + res_data = json.loads(res.data) + assert res.status_code == 200, "POST image upload should be successful" + assert len(res_data['imgurls']) == 2, "Successful count of uploaded images 2." + assert res_data['error'] == False, "There should be no errors for normal file upload" + + @with_context + @patch('pybossa.view.projects.is_admin_or_owner', return_value=False) + def test_task_presenter_image_upload_user_not_owner_or_admin(self, mock): + """Test API /tasks/taskpresenterimageupload to upload a task presenter guidelines image""" + print("running test_task_presenter_image_upload_user_not_owner_or_admin...") + user = UserFactory.create(id=500) + project = ProjectFactory.create( + short_name='test_project', + name='Test Project', + info={ + 'total': 150, + 'task_presenter': 'foo', + 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), + 'kpi': 0.5, + 'product': 'abc', + 'subproduct': 'def', + }, + owner=user) + headers = [('Authorization', user.api_key)] + with open('./test/files/small-image1.jpg', 'rb') as img: + imgStringIO = BytesIO(img.read()) + # Call API method to upload image. + res = self.app.post('/project/{}/tasks/taskpresenterimageupload'.format(project.short_name), headers=headers, data={'image': (imgStringIO, 'large-image.jpg')}) + res_data = json.loads(res.data) + assert res.status_code == 400, "POST image upload should be successful" + assert len(res_data['imgurls']) == 0, "Image should not be uploaded." + assert res_data['error'] == True, "There should be an error since the user is not owner or admin" + + mock_authenticated=mock_current_user(anonymous=False, admin=False, id=2) + + @with_context + @patch('pybossa.view.projects.is_editor_disabled', return_value=True) + def test_task_presenter_image_upload_task_presenter_disabled(self, disable_editor): + + """Test API /tasks/taskpresenterimageupload to upload a task presenter guidelines image""" + print("running test_task_presenter_image_upload_task_presenter_disabled...") + user = UserFactory.create(id=2, admin=False) + project = ProjectFactory.create( + short_name='test_project', + name='Test Project', + info={ + 'total': 150, + 'task_presenter': 'foo', + 'data_classification': dict(input_data="L4 - public", output_data="L4 - public"), + 'kpi': 0.5, + 'product': 'abc', + 'subproduct': 'def', + }, + owner=user) + + headers = [('Authorization', user.api_key)] + with open('./test/files/small-image1.jpg', 'rb') as img: + imgStringIO = BytesIO(img.read()) + with patch.dict(self.flask_app.config, {'DISABLE_TASK_PRESENTER_EDITOR': True}): + # Call API method to upload image. + res = self.app.post('/project/{}/tasks/taskpresenterimageupload'.format(project.short_name), headers=headers, data={'image': (imgStringIO, 'large-image.jpg')}) + res_data = json.loads(res.data) + assert res.status_code == 400, "POST image upload should be successful" + assert len(res_data['imgurls']) == 0, "Image should not be uploaded." + assert res_data['error'] == True, "There should be an error since the task presenter is disabled" + @with_context @patch('pybossa.ckan.requests.get') @patch('pybossa.view.projects.uploader.upload_file', return_value=True)