From 5f20495d6e3ec984c4e86fd76399ddf0d042b336 Mon Sep 17 00:00:00 2001
From: Stamatis Katsaounis <mokats@intracom-telecom.com>
Date: Wed, 5 Dec 2018 12:40:42 +0200
Subject: Prepare Web Portal for ONAP integration

This patch applies all the required changes in order to support a
second web portal container with the onap web portal content.

Change-Id: I2f59776313bf2067dbdfb04445620b5241716ebb
Signed-off-by: Stamatis Katsaounis <mokats@intracom-telecom.com>
---
 opnfv_testapi/ui/root.py | 10 ----------
 1 file changed, 10 deletions(-)
 delete mode 100644 opnfv_testapi/ui/root.py

(limited to 'opnfv_testapi')

diff --git a/opnfv_testapi/ui/root.py b/opnfv_testapi/ui/root.py
deleted file mode 100644
index 7f970b2..0000000
--- a/opnfv_testapi/ui/root.py
+++ /dev/null
@@ -1,10 +0,0 @@
-from opnfv_testapi.resources.handlers import GenericApiHandler
-from opnfv_testapi.common.config import CONF
-
-
-class RootHandler(GenericApiHandler):
-    def get_template_path(self):
-        return CONF.ui_static_path
-
-    def get(self):
-        self.render('testapi-ui/index.html')
-- 
cgit 


From d0bbf3b8952379883550c6eb2062476a6d15043e Mon Sep 17 00:00:00 2001
From: pkaralis <pkaralis@intracom-telecom.com>
Date: Thu, 6 Dec 2018 00:43:12 +0200
Subject: 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>
---
 opnfv_testapi/cmd/server.py                     |  10 +-
 opnfv_testapi/resources/application_handlers.py |  84 +++++++++++------
 opnfv_testapi/resources/handlers.py             |  15 ++-
 opnfv_testapi/resources/result_handlers.py      |  40 +++++++-
 opnfv_testapi/resources/review_handlers.py      | 119 ++++++++++++++++++++++++
 opnfv_testapi/resources/review_models.py        |  39 ++++++++
 opnfv_testapi/resources/test_handlers.py        |  47 +++++++---
 opnfv_testapi/router/url_mappings.py            |  15 +++
 opnfv_testapi/tornado_swagger/swagger.py        |   3 +-
 opnfv_testapi/ui/auth/sign.py                   |  17 +++-
 opnfv_testapi/ui/auth/user.py                   |  52 ++++++++++-
 11 files changed, 388 insertions(+), 53 deletions(-)
 create mode 100644 opnfv_testapi/resources/review_handlers.py
 create mode 100644 opnfv_testapi/resources/review_models.py

(limited to 'opnfv_testapi')

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
-- 
cgit