diff options
author | pkaralis <pkaralis@intracom-telecom.com> | 2018-12-06 00:43:12 +0200 |
---|---|---|
committer | Panagiotis Karalis <pkaralis@intracom-telecom.com> | 2019-03-20 15:28:23 +0200 |
commit | d0bbf3b8952379883550c6eb2062476a6d15043e (patch) | |
tree | 106f65b223054077279bda7ff988a73bea314a34 /opnfv_testapi | |
parent | 5f20495d6e3ec984c4e86fd76399ddf0d042b336 (diff) |
Enable Web Portal for ONAP results
The web portal needs to be able to read test results of the ONAP
compliance program and display them.
In order for the above goal to be achieved, the following two parts
should be impacted:
1- A new front-end should be prepared in order to handle and display
the results
2- The REST API should be extended in order to support the aforementioned
operation.
JIRA: DOVETAIL-669
Change-Id: I36bbb6e602a67020d7e27aedbfc776f5cf4f3dc3
Signed-off-by: pkaralis <pkaralis@intracom-telecom.com>
Co-Authored-By: Stamatis Katsaounis <mokats@intracom-telecom.com>
Diffstat (limited to 'opnfv_testapi')
-rw-r--r-- | opnfv_testapi/cmd/server.py | 10 | ||||
-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 | ||||
-rw-r--r-- | opnfv_testapi/router/url_mappings.py | 15 | ||||
-rw-r--r-- | opnfv_testapi/tornado_swagger/swagger.py | 3 | ||||
-rw-r--r-- | opnfv_testapi/ui/auth/sign.py | 17 | ||||
-rw-r--r-- | opnfv_testapi/ui/auth/user.py | 52 |
11 files changed, 388 insertions, 53 deletions
diff --git a/opnfv_testapi/cmd/server.py b/opnfv_testapi/cmd/server.py index fee5877..5dcc60a 100644 --- a/opnfv_testapi/cmd/server.py +++ b/opnfv_testapi/cmd/server.py @@ -31,6 +31,7 @@ TODOs : import tornado.ioloop import logging +import sys from opnfv_testapi.common.config import CONF from opnfv_testapi.router import url_mappings @@ -42,12 +43,19 @@ handler = logging.handlers.RotatingFileHandler( my_logger.setLevel(logging.DEBUG) my_logger.addHandler(handler) +ch = logging.StreamHandler(sys.stdout) +ch.setLevel(logging.DEBUG) +formatter = logging.Formatter( + '%(asctime)s - %(name)s - %(levelname)s - %(message)s') +ch.setFormatter(formatter) +my_logger.addHandler(ch) + def make_app(): swagger.docs(base_url=CONF.swagger_base_url, static_path=CONF.ui_static_path) return swagger.Application( - url_mappings.mappings, + url_mappings.mappings + url_mappings.onap_mappings, debug=CONF.api_debug, auth=CONF.api_authenticate, cookie_secret='opnfv-testapi', 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: diff --git a/opnfv_testapi/router/url_mappings.py b/opnfv_testapi/router/url_mappings.py index 1eb74ad..65c8480 100644 --- a/opnfv_testapi/router/url_mappings.py +++ b/opnfv_testapi/router/url_mappings.py @@ -13,6 +13,7 @@ from opnfv_testapi.resources import test_handlers from opnfv_testapi.resources import application_handlers from opnfv_testapi.resources import pod_handlers from opnfv_testapi.resources import project_handlers +from opnfv_testapi.resources import review_handlers from opnfv_testapi.resources import scenario_handlers from opnfv_testapi.resources import sut_handlers from opnfv_testapi.resources import testcase_handlers @@ -57,3 +58,17 @@ mappings = [ (r'/api/v1/profile', user.ProfileHandler), ] + +onap_mappings = [ + (r'/api/v1/onap/results', result_handlers.ResultsCLHandler, + dict(is_onap=True)), + (r'/api/v1/onap/results/upload', result_handlers.ResultsUploadHandler, + dict(is_onap=True)), + (r'/api/v1/onap/tests', test_handlers.TestsCLHandler, + dict(is_onap=True)), + (r"/api/v1/onap/tests/([^/]+)", test_handlers.TestsGURHandler, + dict(is_onap=True)), + (r'/api/v1/onap/cvp/applications', + application_handlers.ApplicationsCLHandler, dict(is_onap=True)), + (r'/api/v1/onap/reviews', review_handlers.ReviewsCLHandler), +] diff --git a/opnfv_testapi/tornado_swagger/swagger.py b/opnfv_testapi/tornado_swagger/swagger.py index 83f389a..9afdb17 100644 --- a/opnfv_testapi/tornado_swagger/swagger.py +++ b/opnfv_testapi/tornado_swagger/swagger.py @@ -255,7 +255,8 @@ class operation(DocParser): def _parse_args(self, func): argspec = inspect.getargspec(func) - argspec.args.remove("self") + if 'self' in argspec.args: + argspec.args.remove('self') defaults = [] if argspec.defaults: diff --git a/opnfv_testapi/ui/auth/sign.py b/opnfv_testapi/ui/auth/sign.py index dbb40ed..028816a 100644 --- a/opnfv_testapi/ui/auth/sign.py +++ b/opnfv_testapi/ui/auth/sign.py @@ -45,7 +45,8 @@ class SigninHandler(base.BaseHandler): renew=False, extra_login_params=False, server_url=CONF.lfid_url, - service_url=CONF.lfid_return_url + service_url='http://{0}/{1}'.format(self.request.host, + CONF.lfid_return_url) ) redirect_url = client.get_login_url() self.redirect(url=redirect_url, permanent=False) @@ -154,7 +155,8 @@ class SigninReturnCasHandler(base.BaseHandler): renew=False, extra_login_params=False, server_url=CONF.lfid_url, - service_url=CONF.lfid_return_url + service_url='http://{0}/{1}'.format(self.request.host, + CONF.lfid_return_url) ) user, attrs, _ = client.verify_ticket(ticket) logging.debug("user:%s", user) @@ -180,7 +182,7 @@ class SigninReturnCasHandler(base.BaseHandler): self.set_secure_cookie(const.ROLE, role) self.set_secure_cookie('ticket', ticket) - self.redirect("/") + self.redirect('http://{0}'.format(self.request.host)) class SigninReturnJiraHandler(base.BaseHandler): @@ -275,7 +277,12 @@ class SignoutHandler(base.BaseHandler): renew=False, extra_login_params=False, server_url=CONF.lfid_url, - service_url=CONF.lfid_return_url + service_url='http://{0}/{1}'.format(self.request.host, + CONF.lfid_return_url) ) - url = client.get_logout_url(CONF.ui_url) + + self.clear_cookie('ticket') + self.clear_cookie('signin_type') + + url = client.get_logout_url('http://{0}'.format(self.request.host)) self.redirect(url) diff --git a/opnfv_testapi/ui/auth/user.py b/opnfv_testapi/ui/auth/user.py index a695da4..5ac6f43 100644 --- a/opnfv_testapi/ui/auth/user.py +++ b/opnfv_testapi/ui/auth/user.py @@ -10,12 +10,19 @@ from tornado import gen from tornado import web +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 models from opnfv_testapi.ui.auth import base +from opnfv_testapi.ui.auth import constants as auth_const class ProfileHandler(base.BaseHandler): + def __init__(self, application, request, **kwargs): + super(ProfileHandler, self).__init__(application, request, **kwargs) + self.table_cls = User + @web.asynchronous @gen.coroutine def get(self): @@ -28,8 +35,51 @@ class ProfileHandler(base.BaseHandler): "email": user.get('email'), "fullname": user.get('fullname'), "role": user.get('role', 'user'), - "type": self.get_secure_cookie('signin_type') + "type": self.get_secure_cookie('signin_type'), + "companyName": user.get('companyName'), + "companyWebsite": user.get('companyWebsite'), + "primaryContactName": user.get('primaryContactName'), + "primaryBusinessEmail": user.get('primaryBusinessEmail'), + "primaryPostalAddress": user.get('primaryPostalAddress'), + "primaryPhoneNumber": user.get('primaryPhoneNumber') + }) except Exception: pass raises.Unauthorized('Unauthorized') + + @gen.coroutine + def put(self): + db_keys = [] + openid = self.get_secure_cookie(auth_const.OPENID) + + if openid: + query = {'openid': openid} + user = yield dbapi.db_find_one(self.table, query) + if not user: + raises.NotFound(message.not_found(self.table, query)) + + self._update(query=query, db_keys=db_keys) + else: + raises.Unauthorized(message.no_auth()) + + +class User(models.ModelBase): + def __init__(self, _id=None, openid=None, email=None, fullname=None, + role='user', u_type=None, companyName=None, + companyWebsite=None, primaryContactName=None, + primaryBusinessEmail=None, primaryPostalAddress=None, + primaryPhoneNumber=None): + self._id = _id + self.openid = openid + self.email = email + self.fullname = fullname + self.role = role + self.type = u_type + + self.companyName = companyName + self.companyWebsite = companyWebsite + self.primaryContactName = primaryContactName + self.primaryBusinessEmail = primaryBusinessEmail + self.primaryPostalAddress = primaryPostalAddress + self.primaryPhoneNumber = primaryPhoneNumber |