diff options
Diffstat (limited to 'opnfv_testapi/resources')
-rw-r--r-- | opnfv_testapi/resources/application_handlers.py | 84 | ||||
-rw-r--r-- | opnfv_testapi/resources/handlers.py | 15 | ||||
-rw-r--r-- | opnfv_testapi/resources/result_handlers.py | 40 | ||||
-rw-r--r-- | opnfv_testapi/resources/review_handlers.py | 119 | ||||
-rw-r--r-- | opnfv_testapi/resources/review_models.py | 39 | ||||
-rw-r--r-- | opnfv_testapi/resources/test_handlers.py | 47 |
6 files changed, 299 insertions, 45 deletions
diff --git a/opnfv_testapi/resources/application_handlers.py b/opnfv_testapi/resources/application_handlers.py index 7cecd3e..7d823b8 100644 --- a/opnfv_testapi/resources/application_handlers.py +++ b/opnfv_testapi/resources/application_handlers.py @@ -6,15 +6,20 @@ # which accompanies this distribution, and is available at # http://www.apache.org/licenses/LICENSE-2.0 ############################################################################## +from datetime import datetime import logging import json +import os from tornado import web from tornado import gen from bson import objectid +from slugify import slugify +from PIL import Image from opnfv_testapi.common.config import CONF from opnfv_testapi.common import utils +from opnfv_testapi.db import api as dbapi from opnfv_testapi.resources import handlers from opnfv_testapi.resources import application_models from opnfv_testapi.tornado_swagger import swagger @@ -34,19 +39,28 @@ class ApplicationsLogoHandler(GenericApplicationHandler): @web.asynchronous @gen.coroutine def post(self): - role = self.get_secure_cookie(auth_const.ROLE) - if role.find('administrator') == -1: - msg = 'Only administrator is allowed to upload logos' - self.finish_request({'code': '-1', 'msg': msg}) - return - fileinfo = self.request.files['file'][0] - fname = fileinfo['filename'] + company_logo_name = self.request.arguments['company_name'][0] + extension_name = fileinfo['filename'].split('.')[-1] + company_logo_name = slugify(company_logo_name) + fileinfo['filename'] = company_logo_name location = 'media/companies/' - fh = open(location + fname, 'w') + full_name_path = location + company_logo_name + '.' + extension_name + fh = open(full_name_path, 'w') fh.write(fileinfo['body']) - msg = 'Successfully uploaded logo: ' + fname - resp = {'code': '1', 'msg': msg} + fh.close() + img = Image.open(full_name_path) + if (img.size[0] > 165) or (img.size[1] > 40): + os.remove(full_name_path) + msg = 'The size of the image is not according to the compliance' \ + ' program. Please try again, loading an image with proper' \ + ' dimensions (Max Values: 165px width and 40px height).' + self.finish_request({'code': 403, 'msg': msg}) + return + + msg = 'Successfully uploaded logo: ' + company_logo_name + resp = {'code': 0, 'msg': msg, + 'filename': company_logo_name + '.' + extension_name} self.finish_request(resp) @@ -130,6 +144,8 @@ class ApplicationsCLHandler(GenericApplicationHandler): openid = self.get_secure_cookie(auth_const.OPENID) if openid: self.json_args['owner'] = openid + if self.is_onap: + self.json_args['is_onap'] = 'true' self._post() @@ -138,22 +154,21 @@ class ApplicationsCLHandler(GenericApplicationHandler): miss_fields = [] carriers = [] - role = self.get_secure_cookie(auth_const.ROLE) - if role.find('administrator') == -1: - self.finish_request({'code': '403', 'msg': 'Only administrator \ - is allowed to submit application.'}) - return - - query = {"openid": self.json_args['user_id']} - table = "users" - ret, msg = yield self._check_if_exists(table=table, query=query) + query = {'openid': self.json_args['owner']} + ret, msg = yield self._check_if_exists(table='users', query=query) logging.debug('ret:%s', ret) if not ret: - self.finish_request({'code': '403', 'msg': msg}) + self.finish_request({'code': 403, 'msg': msg}) + return + query = {'test_id': self.json_args['test_id']} + ret, _ = yield self._check_if_exists(table=self.table, query=query) + if ret: + msg = 'An application for these test results already exists' + self.finish_request({'code': 403, 'msg': msg}) return self._create(miss_fields=miss_fields, carriers=carriers) - self._send_email() + # self._send_email() def _send_email(self): @@ -173,7 +188,6 @@ This is a new application: Primary Email: {}, Primary Address: {}, Primary Phone: {}, - User ID Type: {}, User ID: {} Best Regards, @@ -188,19 +202,26 @@ CVP Team data.prim_email, data.prim_address, data.prim_phone, - data.id_type, - data.user_id) + data.owner) utils.send_email(subject, content) class ApplicationsGURHandler(GenericApplicationHandler): @swagger.operation(nickname="deleteAppById") + @gen.coroutine def delete(self, id): query = {'_id': objectid.ObjectId(id)} + application = yield dbapi.db_find_one(self.table, query) + test_id = application['test_id'] + t_query = {'id': test_id} + yield dbapi.db_delete('reviews', {'test_id': test_id}) + yield dbapi.db_update('tests', t_query, + {'$set': {'status': 'private'}}) self._delete(query=query) @swagger.operation(nickname="updateApplicationById") + @web.asynchronous def put(self, application_id): """ @description: update a single application by id @@ -222,12 +243,23 @@ class ApplicationsGURHandler(GenericApplicationHandler): logging.error('except:%s', e) return - @web.asynchronous @gen.coroutine def update(self, application_id, item, value): self.json_args = {} self.json_args[item] = value - query = {'_id': application_id, 'owner': + query = {'_id': objectid.ObjectId(application_id), 'owner': self.get_secure_cookie(auth_const.OPENID)} db_keys = ['_id', 'owner'] + if item == 'approved': + if value == 'true': + status = 'verified' + self.json_args['approve_date'] = str(datetime.now()) + else: + status = 'review' + self.json_args['approve_date'] = '' + application = yield dbapi.db_find_one(self.table, query) + test_id = application['test_id'] + t_query = {'id': test_id} + yield dbapi.db_update('tests', t_query, + {'$set': {'status': status}}) self._update(query=query, db_keys=db_keys) diff --git a/opnfv_testapi/resources/handlers.py b/opnfv_testapi/resources/handlers.py index e8c81f3..559e689 100644 --- a/opnfv_testapi/resources/handlers.py +++ b/opnfv_testapi/resources/handlers.py @@ -41,6 +41,7 @@ DEFAULT_REPRESENTATION = "application/json" class GenericApiHandler(web.RequestHandler): def __init__(self, application, request, **kwargs): + self.is_onap = False super(GenericApiHandler, self).__init__(application, request, **kwargs) self.json_args = None self.table = None @@ -52,6 +53,9 @@ class GenericApiHandler(web.RequestHandler): self.db_scenarios = 'scenarios' self.auth = self.settings["auth"] + def initialize(self, is_onap=False): + self.is_onap = is_onap + def get_int(self, key, value): try: value = int(value) @@ -97,6 +101,11 @@ class GenericApiHandler(web.RequestHandler): if role.find("reviewer") != -1: query['$or'].append({"status": {"$ne": "private"}}) + elif k == 'status': + if v.startswith('{'): + query[k] = json.loads(v) + else: + query[k] = v elif k not in ['last', 'page', 'descend', 'per_page']: query[k] = v if date_range: @@ -107,6 +116,8 @@ class GenericApiHandler(web.RequestHandler): if 'start_date' in query and '$lt' not in query['start_date']: query['start_date'].update({'$lt': str(datetime.now())}) + query['is_onap'] = 'true' if self.is_onap else None + logging.debug("query:%s", query) raise gen.Return((query)) @@ -184,7 +195,7 @@ class GenericApiHandler(web.RequestHandler): if query and table: data = yield dbapi.db_find_one(table, query) if data: - raise gen.Return((True, 'Data alreay exists. %s' % (query))) + raise gen.Return((True, 'Data already exists. %s' % (query))) raise gen.Return((False, 'Data does not exist. %s' % (query))) # @web.asynchronous @@ -214,7 +225,7 @@ class GenericApiHandler(web.RequestHandler): if res_op is None: res = {self.table: data} else: - res = res_op(data, *args) + res = yield res_op(data, *args) if page > 0: res.update({ 'pagination': { diff --git a/opnfv_testapi/resources/result_handlers.py b/opnfv_testapi/resources/result_handlers.py index 38109ad..9501bfd 100644 --- a/opnfv_testapi/resources/result_handlers.py +++ b/opnfv_testapi/resources/result_handlers.py @@ -20,6 +20,7 @@ from bson import objectid from opnfv_testapi.common.config import CONF from opnfv_testapi.common import message from opnfv_testapi.common import raises +from opnfv_testapi.db import api as dbapi from opnfv_testapi.resources import handlers from opnfv_testapi.resources import result_models from opnfv_testapi.tornado_swagger import swagger @@ -41,6 +42,7 @@ class GenericResultHandler(handlers.GenericApiHandler): raises.BadRequest(message.must_int(key)) return value + @gen.coroutine def set_query(self): query = dict() date_range = dict() @@ -82,11 +84,15 @@ class GenericResultHandler(handlers.GenericApiHandler): if 'start_date' in query and '$lt' not in query['start_date']: query['start_date'].update({'$lt': str(datetime.now())}) - return query + query['is_onap'] = 'true' if self.is_onap else None + + raise gen.Return((query)) class ResultsCLHandler(GenericResultHandler): @swagger.operation(nickname="queryTestResults") + @web.asynchronous + @gen.coroutine def get(self): """ @description: Retrieve result(s) for a test project @@ -195,7 +201,8 @@ class ResultsCLHandler(GenericResultHandler): 'per_page': CONF.api_results_per_page } - self._list(query=self.set_query(), **limitations) + query = yield self.set_query() + yield self._list(query=query, **limitations) @swagger.operation(nickname="createTestResult") def post(self): @@ -267,10 +274,19 @@ class ResultsUploadHandler(ResultsCLHandler): results = results.split('\n') result_ids = [] version = '' + vnf_type = None + vnf_checksum = None for result in results: if result == '': continue self.json_args = json.loads(result).copy() + openid = self.get_secure_cookie(auth_const.OPENID) + if openid: + self.json_args['owner'] = openid + if self.is_onap: + self.json_args['is_onap'] = 'true' + vnf_type = self.json_args['vnf_type'] + vnf_checksum = self.json_args['vnf_checksum'] # the result files used in the first release of OVP did not # specify an OVP version if (self.json_args['version'] == 'master' @@ -288,14 +304,30 @@ class ResultsUploadHandler(ResultsCLHandler): with open(log_filename, "wb") as tar_out: tar_out.write(fileinfo['body']) resp = {'id': test_id, 'results': result_ids, 'version': version} + if vnf_type: + resp['vnf_type'] = vnf_type + resp['vnf_checksum'] = vnf_checksum self.finish_request(resp) class ResultsGURHandler(GenericResultHandler): @swagger.operation(nickname='DeleteTestResultById') + @gen.coroutine def delete(self, result_id): - query = {'_id': objectid.ObjectId(result_id)} - self._delete(query=query) + curr_user = self.get_secure_cookie(auth_const.OPENID) + curr_user_role = self.get_secure_cookie(auth_const.ROLE) + if curr_user is not None: + query = {'_id': objectid.ObjectId(result_id)} + test_data = yield dbapi.db_find_one(self.table, query) + if not test_data: + raises.NotFound(message.not_found(self.table, query)) + if curr_user == test_data['owner'] or \ + curr_user_role.find('administrator') != -1: + self._delete(query=query) + else: + raises.Forbidden(message.no_auth()) + else: + raises.Unauthorized(message.no_auth()) @swagger.operation(nickname='getTestResultById') def get(self, result_id): diff --git a/opnfv_testapi/resources/review_handlers.py b/opnfv_testapi/resources/review_handlers.py new file mode 100644 index 0000000..9731e0f --- /dev/null +++ b/opnfv_testapi/resources/review_handlers.py @@ -0,0 +1,119 @@ +############################################################################## +# Copyright (c) 2019 Intracom Telecom +# mokats@intracom-telecom.com +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +from datetime import datetime +import logging + +from tornado import web, gen + +from opnfv_testapi.common.config import CONF +from opnfv_testapi.common import message, raises +from opnfv_testapi.db import api as dbapi +from opnfv_testapi.resources import handlers, review_models +from opnfv_testapi.tornado_swagger import swagger +from opnfv_testapi.ui.auth import constants as auth_const + + +class GenericReviewHandler(handlers.GenericApiHandler): + def __init__(self, review, request, **kwargs): + super(GenericReviewHandler, self).__init__(review, request, **kwargs) + self.table = 'reviews' + self.table_cls = review_models.Review + + +class ReviewsCLHandler(GenericReviewHandler): + @swagger.operation(nickname="queryReviews") + @web.asynchronous + @gen.coroutine + def get(self): + def descend_limit(): + descend = self.get_query_argument('descend', 'true') + return -1 if descend.lower() == 'true' else 1 + + def last_limit(): + return self.get_int('last', self.get_query_argument('last', 0)) + + def page_limit(): + return self.get_int('page', self.get_query_argument('page', 0)) + + limitations = { + 'sort': {'_id': descend_limit()}, + 'last': last_limit(), + 'page': page_limit(), + 'per_page': CONF.api_results_per_page + } + + query = yield self.set_query() + yield self._list(query=query, **limitations) + logging.debug('list end') + + @swagger.operation(nickname="createReview") + @web.asynchronous + def post(self): + openid = self.get_secure_cookie(auth_const.OPENID) + if openid: + self.json_args['reviewer_openid'] = openid + + if self.json_args['outcome'] is None: + self._del() + else: + self._post() + + @gen.coroutine + def _post(self): + query = {'openid': self.json_args['reviewer_openid']} + user = yield dbapi.db_find_one('users', query) + if not user: + raises.Forbidden(message.unauthorized()) + role = self.get_secure_cookie(auth_const.ROLE) + if 'reviewer' not in role.split(','): + raises.Unauthorized(message.no_auth()) + test = yield dbapi.db_find_one( + 'tests', {'id': self.json_args['test_id']}) + if test['owner'] == self.json_args['reviewer_openid']: + self.finish_request({'code': 403, + 'msg': 'No permision to review own results'}) + return + query = { + 'reviewer_openid': self.json_args['reviewer_openid'], + 'test_id': self.json_args['test_id'] + } + review = yield dbapi.db_find_one(self.table, query) + if review: + if review['outcome'] != self.json_args['outcome']: + yield dbapi.db_update(self.table, query, + {'$set': { + 'outcome': self.json_args['outcome'], + 'creation_date': datetime.now()}}) + self.finish_request() + else: + self.json_args['reviewer_name'] = user['fullname'] + self.json_args['reviewer_email'] = user['email'] + self._create(miss_fields=[], carriers=[]) + + @gen.coroutine + def _del(self): + query = {'openid': self.json_args['reviewer_openid']} + user = yield dbapi.db_find_one('users', query) + if not user: + raises.Forbidden(message.unauthorized()) + role = self.get_secure_cookie(auth_const.ROLE) + if 'reviewer' not in role.split(','): + raises.Unauthorized(message.no_auth()) + test = yield dbapi.db_find_one( + 'tests', {'id': self.json_args['test_id']}) + if test['owner'] == self.json_args['reviewer_openid']: + self.finish_request({'code': 403, + 'msg': 'No permision to review own results'}) + return + query = { + 'reviewer_openid': self.json_args['reviewer_openid'], + 'test_id': self.json_args['test_id'] + } + yield dbapi.db_delete(self.table, query) + self.finish_request() diff --git a/opnfv_testapi/resources/review_models.py b/opnfv_testapi/resources/review_models.py new file mode 100644 index 0000000..2aaa62c --- /dev/null +++ b/opnfv_testapi/resources/review_models.py @@ -0,0 +1,39 @@ +############################################################################## +# Copyright (c) 2019 +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Apache License, Version 2.0 +# which accompanies this distribution, and is available at +# http://www.apache.org/licenses/LICENSE-2.0 +############################################################################## +from opnfv_testapi.resources import models +from opnfv_testapi.tornado_swagger import swagger + +from datetime import datetime + + +@swagger.model() +class Review(models.ModelBase): + def __init__(self, _id=None, test_id=None, reviewer_openid=None, + reviewer_email=None, reviewer_name=None, creation_date=None, + outcome=None): + self._id = _id + self.test_id = test_id + self.reviewer_openid = reviewer_openid + self.reviewer_email = reviewer_email + self.reviewer_name = reviewer_name + self.creation_date = datetime.now() + self.outcome = outcome + + +@swagger.model() +class Reviews(models.ModelBase): + """ + @property reviews: + @ptype tests: C{list} of L{Review} + """ + def __init__(self): + self.reviews = list() + + @staticmethod + def attr_parser(): + return {'reviews': Review} diff --git a/opnfv_testapi/resources/test_handlers.py b/opnfv_testapi/resources/test_handlers.py index 5ecb176..7ab20dc 100644 --- a/opnfv_testapi/resources/test_handlers.py +++ b/opnfv_testapi/resources/test_handlers.py @@ -78,10 +78,28 @@ class TestsCLHandler(GenericTestHandler): if curr_user is None: raises.Unauthorized(message.no_auth()) + review = self.request.query_arguments.pop('review', None) query = yield self.set_query() - yield self._list(query=query, **limitations) + if review: + yield self._list(query=query, res_op=self.check_review, + **limitations) + else: + yield self._list(query=query, **limitations) logging.debug('list end') + @gen.coroutine + def check_review(self, data, *args): + current_user = self.get_secure_cookie(auth_const.OPENID) + for test in data: + query = {'reviewer_openid': current_user, 'test_id': test['id']} + ret = yield dbapi.db_find_one('reviews', query) + if ret: + test['voted'] = 'true' + else: + test['voted'] = 'false' + + raise gen.Return({self.table: data}) + @swagger.operation(nickname="createTest") @web.asynchronous def post(self): @@ -111,6 +129,8 @@ class TestsCLHandler(GenericTestHandler): self.finish_request({'code': '403', 'msg': msg}) return + if self.is_onap: + self.json_args['is_onap'] = 'true' self._create(miss_fields=miss_fields, carriers=carriers) @@ -149,7 +169,6 @@ class TestsGURHandler(GenericTestHandler): raise gen.Return('API response validation enabled') @swagger.operation(nickname="deleteTestById") - @web.asynchronous @gen.coroutine def delete(self, test_id): curr_user = self.get_secure_cookie(auth_const.OPENID) @@ -161,6 +180,9 @@ class TestsGURHandler(GenericTestHandler): raises.NotFound(message.not_found(self.table, query)) if curr_user == test_data['owner'] or \ curr_user_role.find('administrator') != -1: + yield dbapi.db_delete('applications', + {'test_id': test_data['id']}) + yield dbapi.db_delete('reviews', {'test_id': test_data['id']}) self._delete(query=query) else: raises.Forbidden(message.no_auth()) @@ -198,7 +220,7 @@ class TestsGURHandler(GenericTestHandler): if query and table: data = yield dbapi.db_find_one(table, query) if data: - raise gen.Return((True, 'Data alreay exists. %s' % (query), + raise gen.Return((True, 'Data already exists. %s' % (query), data.get("openid"))) raise gen.Return((False, 'Data does not exist. %s' % (query), None)) @@ -255,9 +277,9 @@ class TestsGURHandler(GenericTestHandler): return if item == "status": - if value in {'approved', 'not approved'}: + if value == 'verified': if test['status'] == 'private': - msg = 'Not allowed to approve/not approve' + msg = 'Not allowed to verify' self.finish_request({'code': 403, 'msg': msg}) return @@ -272,7 +294,7 @@ class TestsGURHandler(GenericTestHandler): self.finish_request({'code': 403, 'msg': msg}) return - if not test['sut_label']: + if not self.is_onap and not test['sut_label']: msg = 'Please fill out SUT version before submission' self.finish_request({'code': 403, 'msg': msg}) return @@ -284,8 +306,7 @@ class TestsGURHandler(GenericTestHandler): 'id': test['id'], '$or': [ {'status': 'review'}, - {'status': 'approved'}, - {'status': 'not approved'} + {'status': 'verified'} ] } record = yield dbapi.db_find_one("tests", test_query) @@ -311,12 +332,12 @@ class TestsGURHandler(GenericTestHandler): logging.debug('check review') query['user_id'] = user data = yield dbapi.db_find_one('applications', query) - if not data: - logging.debug('not found') + if data: + logging.debug('results are bound to an application') raise gen.Return((False, message.no_auth())) - if value == "approve" or value == "not approved": - logging.debug('check approve') - query['role'] = {"$regex": ".*reviewer.*"} + if value == "verified": + logging.debug('check verify') + query['role'] = {"$regex": ".*administrator.*"} query['openid'] = user data = yield dbapi.db_find_one('users', query) if not data: |