diff options
-rw-r--r-- | testapi/etc/config.ini | 2 | ||||
-rw-r--r-- | testapi/opnfv_testapi/common/check.py | 14 | ||||
-rw-r--r-- | testapi/opnfv_testapi/common/constants.py | 1 | ||||
-rw-r--r-- | testapi/opnfv_testapi/common/message.py | 8 | ||||
-rw-r--r-- | testapi/opnfv_testapi/handlers/base_handlers.py | 2 | ||||
-rw-r--r-- | testapi/opnfv_testapi/handlers/result_handlers.py | 48 | ||||
-rw-r--r-- | testapi/opnfv_testapi/models/result_models.py | 4 | ||||
-rw-r--r-- | testapi/opnfv_testapi/router/url_mappings.py | 1 | ||||
-rw-r--r-- | testapi/opnfv_testapi/tests/unit/common/test_config.py | 2 | ||||
-rw-r--r-- | testapi/opnfv_testapi/tests/unit/executor.py | 14 | ||||
-rw-r--r-- | testapi/opnfv_testapi/tests/unit/handlers/test_project.py | 17 | ||||
-rw-r--r-- | testapi/opnfv_testapi/tests/unit/handlers/test_result.py | 39 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/components/pods/podsController.js | 11 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/components/projects/projectsController.js | 12 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html | 2 | ||||
-rw-r--r-- | testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js | 26 |
16 files changed, 84 insertions, 119 deletions
diff --git a/testapi/etc/config.ini b/testapi/etc/config.ini index 86cb0ca..5f568a7 100644 --- a/testapi/etc/config.ini +++ b/testapi/etc/config.ini @@ -15,7 +15,7 @@ port = 8000 results_per_page = 20 # With debug_on set to true, error traces will be shown in HTTP responses -debug = True +debug = False token_check = False authenticate = True diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py index 1a66dd7..7f866dd 100644 --- a/testapi/opnfv_testapi/common/check.py +++ b/testapi/opnfv_testapi/common/check.py @@ -47,6 +47,20 @@ def is_authorized(method): return wrapper +def is_allowed(method): + @functools.wraps(method) + def wrapper(self, *args, **kwargs): + if self.table == 'projects': + query_data = {} + query_data['project_name'] = kwargs.get('query')['name'] + data = yield dbapi.db_find_one('testcases', query_data) + if data: + raises.Unauthorized(message.tied_with_resource()) + ret = yield gen.coroutine(method)(self, *args, **kwargs) + raise gen.Return(ret) + return wrapper + + def valid_token(method): @functools.wraps(method) def wrapper(self, *args, **kwargs): diff --git a/testapi/opnfv_testapi/common/constants.py b/testapi/opnfv_testapi/common/constants.py index 70c9223..c7f82d9 100644 --- a/testapi/opnfv_testapi/common/constants.py +++ b/testapi/opnfv_testapi/common/constants.py @@ -1,4 +1,3 @@ TESTAPI_ID = 'testapi_id' CSRF_TOKEN = 'csrf_token' -ROLE = 'role' TESTAPI_USERS = ['opnfv-testapi-users'] diff --git a/testapi/opnfv_testapi/common/message.py b/testapi/opnfv_testapi/common/message.py index b92b7f0..52cc2ad 100644 --- a/testapi/opnfv_testapi/common/message.py +++ b/testapi/opnfv_testapi/common/message.py @@ -10,10 +10,6 @@ not_found_base = 'Could Not Found' exist_base = 'Already Exists' -def key_error(key): - return "KeyError: '{}'".format(key) - - def no_body(): return 'No Body' @@ -64,3 +60,7 @@ def must_int(name): def no_permission(): return 'You do not have permission to perform this action' + + +def tied_with_resource(): + return 'Selected resource is associated with other resources' diff --git a/testapi/opnfv_testapi/handlers/base_handlers.py b/testapi/opnfv_testapi/handlers/base_handlers.py index 537077d..ed4aeb2 100644 --- a/testapi/opnfv_testapi/handlers/base_handlers.py +++ b/testapi/opnfv_testapi/handlers/base_handlers.py @@ -179,6 +179,7 @@ class GenericApiHandler(web.RequestHandler): @gen.coroutine @check.not_exist @check.is_authorized + @check.is_allowed def _delete(self, data, query=None): yield dbapi.db_delete(self.table, query) self.finish_request() @@ -189,6 +190,7 @@ class GenericApiHandler(web.RequestHandler): @check.not_exist @check.updated_one_not_exist @check.is_authorized + @check.is_allowed def _update(self, data, query=None, **kwargs): data = self.table_cls.from_dict(data) update_req = self._update_requests(data) diff --git a/testapi/opnfv_testapi/handlers/result_handlers.py b/testapi/opnfv_testapi/handlers/result_handlers.py index b0691cd..74acb2e 100644 --- a/testapi/opnfv_testapi/handlers/result_handlers.py +++ b/testapi/opnfv_testapi/handlers/result_handlers.py @@ -8,12 +8,9 @@ ############################################################################## from datetime import datetime from datetime import timedelta -import json -import logging from bson import objectid -from opnfv_testapi.common import constants from opnfv_testapi.common import message from opnfv_testapi.common import raises from opnfv_testapi.common.config import CONF @@ -41,7 +38,6 @@ class GenericResultHandler(base_handlers.GenericApiHandler): query = dict() date_range = dict() - query['public'] = {'$not': {'$eq': 'false'}} for k in self.request.query_arguments.keys(): v = self.get_query_argument(k) if k == 'project' or k == 'pod' or k == 'case': @@ -60,13 +56,6 @@ class GenericResultHandler(base_handlers.GenericApiHandler): date_range.update({'$lt': str(v)}) elif 'build_id' in k: query[k] = self.get_int(k, v) - elif k == 'signed': - username = self.get_secure_cookie(constants.TESTAPI_ID) - role = self.get_secure_cookie(constants.ROLE) - if role: - del query['public'] - if role != "reviewer": - query['user'] = username elif k not in ['last', 'page', 'descend']: query[k] = v if date_range: @@ -121,10 +110,9 @@ class ResultsCLHandler(GenericResultHandler): - criteria : the global criteria status passed or failed - trust_indicator : evaluate the stability of the test case to avoid running systematically long and stable test case - - signed : get logined user result GET /results/project=functest&case=vPing&version=Arno-R1 \ - &pod=pod_name&period=15&signed + &pod=pod_name&period=15 @return 200: all test results consist with query, empty list if no result is found @rtype: L{TestResults} @@ -184,10 +172,6 @@ class ResultsCLHandler(GenericResultHandler): @type trust_indicator: L{float} @in trust_indicator: query @required trust_indicator: False - @param signed: user results or all results - @type signed: L{string} - @in signed: query - @required signed: False @param descend: true, newest2oldest; false, oldest2newest @type descend: L{string} @in descend: query @@ -231,36 +215,8 @@ class ResultsCLHandler(GenericResultHandler): values_check=values_check) -class ResultsUploadHandler(ResultsCLHandler): - @swagger.operation(nickname="uploadTestResult") - def post(self): - """ - @description: upload and create a test result - @param body: result to be created - @type body: L{ResultCreateRequest} - @in body: body - @rtype: L{CreateResponse} - @return 200: result is created. - @raise 404: pod/project/testcase not exist - @raise 400: body/pod_name/project_name/case_name not provided - """ - logging.info('file upload') - fileinfo = self.request.files['file'][0] - is_public = self.get_body_argument('public') - logging.warning('public:%s', is_public) - logging.info('results is :%s', fileinfo['filename']) - logging.info('results is :%s', fileinfo['body']) - self.json_args = json.loads(fileinfo['body']).copy() - self.json_args['public'] = is_public - - openid = self.get_secure_cookie(constants.TESTAPI_ID) - if openid: - self.json_args['user'] = openid - - super(ResultsUploadHandler, self).post() - - class ResultsGURHandler(GenericResultHandler): + @swagger.operation(nickname='getTestResultById') def get(self, result_id): """ diff --git a/testapi/opnfv_testapi/models/result_models.py b/testapi/opnfv_testapi/models/result_models.py index 1dbe729..f8379d8 100644 --- a/testapi/opnfv_testapi/models/result_models.py +++ b/testapi/opnfv_testapi/models/result_models.py @@ -62,8 +62,6 @@ class ResultCreateRequest(base_models.ModelBase): build_tag=None, scenario=None, criteria=None, - user=None, - public="true", trust_indicator=None): self.pod_name = pod_name self.project_name = project_name @@ -76,8 +74,6 @@ class ResultCreateRequest(base_models.ModelBase): self.build_tag = build_tag self.scenario = scenario self.criteria = criteria - self.user = user - self.public = public self.trust_indicator = trust_indicator if trust_indicator else TI(0) def __eq__(self, other): diff --git a/testapi/opnfv_testapi/router/url_mappings.py b/testapi/opnfv_testapi/router/url_mappings.py index b9dd231..8f01a66 100644 --- a/testapi/opnfv_testapi/router/url_mappings.py +++ b/testapi/opnfv_testapi/router/url_mappings.py @@ -49,7 +49,6 @@ mappings = [ # Push results with mandatory request payload parameters # (project, case, and pod) (r"/api/v1/results", result_handlers.ResultsCLHandler), - (r'/api/v1/results/upload', result_handlers.ResultsUploadHandler), (r"/api/v1/results/([^/]+)", result_handlers.ResultsGURHandler), (r"/api/v1/deployresults", deploy_handlers.DeployResultsHandler), (r"/api/v1/deployresults/([^/]+)", deploy_handlers.DeployResultHandler), diff --git a/testapi/opnfv_testapi/tests/unit/common/test_config.py b/testapi/opnfv_testapi/tests/unit/common/test_config.py index 6d160ce..8e4966f 100644 --- a/testapi/opnfv_testapi/tests/unit/common/test_config.py +++ b/testapi/opnfv_testapi/tests/unit/common/test_config.py @@ -11,7 +11,7 @@ def test_config_normal(mocker, config_normal): assert CONF.mongo_url == 'mongodb://127.0.0.1:27017/' assert CONF.mongo_dbname == 'test_results_collection' assert CONF.api_port == 8000 - assert CONF.api_debug is True + assert CONF.api_debug is False assert CONF.api_token_check is False assert CONF.api_authenticate is True assert CONF.ui_url == 'http://localhost:8000' diff --git a/testapi/opnfv_testapi/tests/unit/executor.py b/testapi/opnfv_testapi/tests/unit/executor.py index 743c076..d08782c 100644 --- a/testapi/opnfv_testapi/tests/unit/executor.py +++ b/testapi/opnfv_testapi/tests/unit/executor.py @@ -43,20 +43,6 @@ def mock_valid_lfid(): return _mock_valid_lfid -def upload(excepted_status, excepted_response): - def _upload(create_request): - @functools.wraps(create_request) - def wrap(self): - request = create_request(self) - status, body = self.upload(request) - if excepted_status == httplib.OK: - getattr(self, excepted_response)(body) - else: - self.assertIn(excepted_response, body) - return wrap - return _upload - - def create(excepted_status, excepted_response): def _create(create_request): @functools.wraps(create_request) diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_project.py b/testapi/opnfv_testapi/tests/unit/handlers/test_project.py index cbd1a4e..884dd68 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_project.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_project.py @@ -12,6 +12,7 @@ import urllib from opnfv_testapi.common import message from opnfv_testapi.models import project_models +from opnfv_testapi.models import testcase_models as tcm from opnfv_testapi.tests.unit import executor from opnfv_testapi.tests.unit.handlers import test_base as base @@ -23,6 +24,9 @@ class TestProjectBase(base.TestBase): 'qtip-ssh test') self.req_e = project_models.ProjectCreateRequest('functest', 'functest test') + self.testcase_d = tcm.TestcaseCreateRequest.from_dict( + self.load_json('testcase_d')) + self.project = 'qtip' self.get_res = project_models.Project self.list_res = project_models.Projects self.update_res = project_models.Project @@ -150,6 +154,13 @@ class TestProjectUpdate(TestProjectBase): return self.req_d, self.req_d.name @executor.mock_valid_lfid() + @executor.update(httplib.UNAUTHORIZED, message.tied_with_resource()) + def test_updateNotAllowed(self): + self.create_help('/api/v1/projects/%s/cases', self.testcase_d, self.req_d.name) + req = project_models.ProjectUpdateRequest('apex', 'apex test') + return req, self.req_d.name + + @executor.mock_valid_lfid() @executor.update(httplib.OK, '_assert_update') def test_success(self): req = project_models.ProjectUpdateRequest('apex', 'apex test') @@ -178,6 +189,12 @@ class TestProjectDelete(TestProjectBase): return 'notFound' @executor.mock_valid_lfid() + @executor.delete(httplib.UNAUTHORIZED, message.tied_with_resource()) + def test_deleteNotAllowed(self): + self.create_help('/api/v1/projects/%s/cases', self.testcase_d, self.req_d.name) + return self.req_d.name + + @executor.mock_valid_lfid() @executor.delete(httplib.OK, '_assert_delete') def test_success(self): return self.req_d.name diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py index f1f055e..c07d792 100644 --- a/testapi/opnfv_testapi/tests/unit/handlers/test_result.py +++ b/testapi/opnfv_testapi/tests/unit/handlers/test_result.py @@ -10,7 +10,6 @@ import copy from datetime import datetime from datetime import timedelta import httplib -import json import urllib from opnfv_testapi.common import message @@ -46,22 +45,6 @@ class TestResultBase(base.TestBase): _, res = self.create_d() return res.href.split('/')[-1] - def upload(self, req): - if req and not isinstance(req, str) and hasattr(req, 'format'): - req = req.format() - res = self.fetch(self.basePath + '/upload', - method='POST', - body=json.dumps(req), - headers=self.headers) - - return self._get_return(res, self.create_res) - - -class TestResultUpload(TestResultBase): - @executor.upload(httplib.BAD_REQUEST, message.key_error('file')) - def test_filenotfind(self): - return None - class TestResultCreate(TestResultBase): @executor.create(httplib.BAD_REQUEST, message.no_body()) @@ -197,16 +180,6 @@ class TestResultGet(TestResultBase): def test_queryLast(self): return self._set_query(last=1) - @executor.query(httplib.OK, '_query_success', 4) - def test_queryPublic(self): - self._create_public_data() - return self._set_query() - - @executor.query(httplib.OK, '_query_success', 1) - def test_queryPrivate(self): - self._create_private_data() - return self._set_query(public='false') - @executor.query(httplib.OK, '_query_period_one', 1) def test_combination(self): return self._set_query('pod', @@ -266,18 +239,6 @@ class TestResultGet(TestResultBase): self.create(req) return req - def _create_public_data(self, **kwargs): - req = copy.deepcopy(self.req_d) - req.public = 'true' - self.create(req) - return req - - def _create_private_data(self, **kwargs): - req = copy.deepcopy(self.req_d) - req.public = 'false' - self.create(req) - return req - def _set_query(self, *args, **kwargs): def get_value(arg): if arg in ['pod', 'project', 'case']: diff --git a/testapi/opnfv_testapi/ui/components/pods/podsController.js b/testapi/opnfv_testapi/ui/components/pods/podsController.js index 95e3571..38e084d 100644 --- a/testapi/opnfv_testapi/ui/components/pods/podsController.js +++ b/testapi/opnfv_testapi/ui/components/pods/podsController.js @@ -137,7 +137,6 @@ function batchDelete(){ var index; var checkedBox = []; - console.log(ctrl.checkBox) for(index in ctrl.checkBox){ if(!ctrl.showError){ if(ctrl.checkBox[index]){ @@ -153,7 +152,13 @@ * message */ function openBatchDeleteModal() { - confirmModal("Delete",ctrl.batchDelete); + var deleteObjects = [] + for(var index in ctrl.checkBox){ + if(ctrl.checkBox[index]){ + deleteObjects.push(ctrl.data.pods[index].name) + } + } + confirmModal("Delete", 'pods', ctrl.batchDelete, deleteObjects); } /** @@ -162,7 +167,7 @@ */ function openDeleteModal(name) { console.log(name) - confirmModal("Delete", ctrl.podDelete, name); + confirmModal("Delete", 'pod', ctrl.podDelete, name); } /** diff --git a/testapi/opnfv_testapi/ui/components/projects/projectsController.js b/testapi/opnfv_testapi/ui/components/projects/projectsController.js index 940c1e2..0d0ec99 100644 --- a/testapi/opnfv_testapi/ui/components/projects/projectsController.js +++ b/testapi/opnfv_testapi/ui/components/projects/projectsController.js @@ -204,7 +204,15 @@ * message */ function openBatchDeleteModal() { - confirmModal("Delete",ctrl.batchDelete); + var deleteObjects = [] + ctrl.checkBox.forEach(function(project, index){ + if(!ctrl.showError){ + if(project){ + deleteObjects.push(ctrl.data.projects[index].name) + } + } + }); + confirmModal("Delete", 'projects', ctrl.batchDelete, deleteObjects); } /** @@ -212,7 +220,7 @@ * message */ function openDeleteModal(name) { - confirmModal("Delete", ctrl.projectDelete, name); + confirmModal("Delete",'projects', ctrl.projectDelete, name); } ctrl.listProjects(); diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html b/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html index e5397e0..417af37 100644 --- a/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModal.html @@ -10,7 +10,7 @@ </div> <div class="Delete" ng-class="{ 'hidden': confirmModal.data.text!='Delete' }"> <div class="form-group"> - <label for="confirmText"> You are about to delete.</label> + <label for="confirmText"> You are about to delete following {{confirmModal.data.resource}} : {{confirmModal.deleteObjects}} </label> <br> Do you want to proceed? </div> diff --git a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js index 42cf873..c115a3c 100644 --- a/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js +++ b/testapi/opnfv_testapi/ui/shared/alerts/confirmModalFactory.js @@ -11,7 +11,7 @@ * Opens confirm modal dialog with input textbox */ function confirmModal($uibModal) { - return function(text, successHandler, name) { + return function(text, resource, successHandler, name) { $uibModal.open({ templateUrl: 'testapi-ui/shared/alerts/confirmModal.html', controller: 'CustomConfirmModalController as confirmModal', @@ -20,8 +20,10 @@ data: function () { return { text: text, + resource: resource, successHandler: successHandler, name: name + }; } } @@ -44,8 +46,26 @@ ctrl.confirm = confirm; ctrl.cancel = cancel; - + ctrl.buildDeleteObjects = buildDeleteObjects; ctrl.data = angular.copy(data); + + function buildDeleteObjects(){ + ctrl.deleteObjects = ''; + if (typeof ctrl.data.name === 'string') { + ctrl.deleteObjects = ctrl.data.name + } + else{ + for(var index in ctrl.data.name){ + if(index==0){ + ctrl.deleteObjects += ctrl.data.name[index] + } + else{ + ctrl.deleteObjects += ", "+ ctrl.data.name[index] + } + + } + } + } /** * Initiate confirmation and call the success handler with the * input text. @@ -63,5 +83,7 @@ function cancel() { $uibModalInstance.dismiss('cancel'); } + + ctrl.buildDeleteObjects(); } })(); |