aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Xu <xudan16@huawei.com>2019-04-11 06:39:25 +0000
committerGerrit Code Review <gerrit@opnfv.org>2019-04-11 06:39:25 +0000
commitdbcc039303c7f010348814694b8f75d621aa51e3 (patch)
tree2ecc14d87b24166c2e6d49f33103b63e1ca4c6fd
parentd32ce7d109fb36277681629c8e648777664862b2 (diff)
parent71bdc6752f47b7da7282f786570fbe717973fb6d (diff)
Merge "Enhanced OVP Web Portal"
-rw-r--r--3rd_party/static/testapi-ui/app.js24
-rw-r--r--3rd_party/static/testapi-ui/assets/css/cvp-style.css28
-rw-r--r--3rd_party/static/testapi-ui/components/application/application.html231
-rw-r--r--3rd_party/static/testapi-ui/components/application/applicationController.js198
-rw-r--r--3rd_party/static/testapi-ui/components/profile/profile.html61
-rw-r--r--3rd_party/static/testapi-ui/components/profile/profileController.js26
-rw-r--r--3rd_party/static/testapi-ui/components/results/modal/applicationModal.html191
-rw-r--r--3rd_party/static/testapi-ui/components/results/modal/applicationView.html107
-rw-r--r--3rd_party/static/testapi-ui/components/results/modal/reviewsModal.html41
-rw-r--r--3rd_party/static/testapi-ui/components/results/results.html57
-rw-r--r--3rd_party/static/testapi-ui/components/results/resultsController.js262
-rw-r--r--3rd_party/static/testapi-ui/index.html4
-rw-r--r--3rd_party/static/testapi-ui/shared/header/header.html7
-rw-r--r--opnfv_testapi/resources/test_handlers.py5
-rw-r--r--opnfv_testapi/router/url_mappings.py1
15 files changed, 892 insertions, 351 deletions
diff --git a/3rd_party/static/testapi-ui/app.js b/3rd_party/static/testapi-ui/app.js
index edf7663..55603aa 100644
--- a/3rd_party/static/testapi-ui/app.js
+++ b/3rd_party/static/testapi-ui/app.js
@@ -55,11 +55,11 @@
templateUrl: 'testapi-ui/components/guidelines/guidelines.html',
controller: 'GuidelinesController as ctrl'
}).
- // state('communityResults', {
- // url: '/community_results',
- // templateUrl: 'testapi-ui/components/results/results.html',
- // controller: 'ResultsController as ctrl'
- // }).
+ state('communityResults', {
+ url: '/community_results',
+ templateUrl: 'testapi-ui/components/results/results.html',
+ controller: 'ResultsController as ctrl'
+ }).
state('userResults', {
url: '/user_results',
templateUrl: 'testapi-ui/components/results/results.html',
@@ -173,12 +173,26 @@
$rootScope.auth.doSignIn = doSignIn;
$rootScope.auth.doSignOut = doSignOut;
$rootScope.auth.doSignCheck = doSignCheck;
+ $rootScope.auth.canReview = canReview;
var sign_in_url = testapiApiUrl + '/auth/signin';
var sign_out_url = testapiApiUrl + '/auth/signout';
var profile_url = testapiApiUrl + '/profile';
+ function canReview(user) {
+ if (typeof user.role == undefined) {
+ return false;
+ } else if (user.role.indexOf('administrator') != -1) {
+ return true;
+ } else if (user.role.indexOf('reviewer') != -1) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
/** This function initiates a sign in. */
function doSignIn(type) {
$rootScope.auth.type = type;
diff --git a/3rd_party/static/testapi-ui/assets/css/cvp-style.css b/3rd_party/static/testapi-ui/assets/css/cvp-style.css
index ed1d938..e6d3ab1 100644
--- a/3rd_party/static/testapi-ui/assets/css/cvp-style.css
+++ b/3rd_party/static/testapi-ui/assets/css/cvp-style.css
@@ -2,6 +2,15 @@
font-size: 18px;
}
+.nav>li>a:hover,
+.nav>li>a:focus,
+.nav>li.active,
+.nav>li.active>a {
+ background-color: #27CFC3;
+ color: #1C1C1C;
+}
+
+
table {
font-size: 15px;
}
@@ -96,3 +105,22 @@ table .btn.medium {
a {
cursor: pointer;
}
+
+.btn-success-cust {
+color: #fff;
+background-color: #27CFC3;
+border-color: #27CFC3;
+}
+
+.btn-success-cust:focus, .btn-success-cust:hover {
+border-color: #1FA79C;
+background-color: #1FA79C;
+}
+
+input:invalid {
+ border: 2px dashed red;
+}
+
+input:valid {
+ border: 2px solid black;
+}
diff --git a/3rd_party/static/testapi-ui/components/application/application.html b/3rd_party/static/testapi-ui/components/application/application.html
index 0b45ab3..5e78546 100644
--- a/3rd_party/static/testapi-ui/components/application/application.html
+++ b/3rd_party/static/testapi-ui/components/application/application.html
@@ -1,207 +1,4 @@
<div class="container-fluid common-main-container">
- <div class="top-site-banner">
- <div class="container">
- <p class="p1">Complete this application then start your CVP journey</p>
- </div>
- </div>
-
- <div class="row" style="margin-top: 20px;">
- <div class="col-lg-12 container">
- <form id="OsLogoProgramForm_Form" action="/brand/logo-request/Form" method="post"
- enctype="application/x-www-form-urlencoded">
- <p id="OsLogoProgramForm_Form_error" class="message" style="display: none;"></p>
- <fieldset>
- <div class="field text col-md-4">
- <label class="left" >Organization name</label>
- <i uib-tooltip="Organization name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.organization_name" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Organization website (if public)</label>
- <i uib-tooltip="Organization website if it is public"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.organization_web" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="col-md-4"></div>
- <div class="field email text col-md-4">
- <label class="left">Product name and/or identifier</label>
- <i uib-tooltip="Product name and/or identifier" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="email text form-control" ng-model="ctrl.product_name" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Product specifications</label>
- <i uib-tooltip="A link of product specifications"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.product_spec" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Product public documentation</label>
- <i uib-tooltip="A link of product public documentation"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.product_documentation" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Product categories</label>
- <i uib-tooltip="Product categories" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <select class="form-control" ng-model="ctrl.product_categories">
- <option value="soft&hard">software and hardware</option>
- <option value="soft&3rd">software and third party hardware</option>
- </select>
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary contact name</label>
- <i uib-tooltip="Primary contact name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_name" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary business email</label>
- <i uib-tooltip="Only the Business email address should be used for official communication with OPNFV CVP"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_email" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary postal address</label>
- <i uib-tooltip="Primary postal address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_address" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Primary phone number</label>
- <i uib-tooltip="Primary phone number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.prim_phone" required="required"
- aria-required="true">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Description</label>
- <i uib-tooltip="Product Description" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.description">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">SUT Version</label>
- <i uib-tooltip="SUT Version" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.sut_version">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">SUT HW Version</label>
- <i uib-tooltip="SUT HW Version - leave blank if not applicable"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.sut_hw_version">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">OVP Version</label>
- <i uib-tooltip="OVP Version" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.ovp_version">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">OVP Category</label>
- <i uib-tooltip="OVP Category" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.ovp_category">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Company Logo</label>
- <i uib-tooltip="Company Logo" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.company_logo">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Approve Date</label>
- <i uib-tooltip="Approve Date - YYYY-MM-DD" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.approve_date">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Approved</label>
- <i uib-tooltip="Approved - insert true or false" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.approved">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Test ID</label>
- <i uib-tooltip="Test ID - enter approved test_id"
- class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <input type="text" class="text form-control" ng-model="ctrl.test_id">
- </div>
- </div>
- <div class="field text col-md-4">
- <label class="left">Location</label>
- <i uib-tooltip="Location" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <div class="middleColumn">
- <select class="form-control" ng-model="ctrl.lab_location">
- <option value="internal">internal vendor lab</option>
- <option value="third">third-party lab</option>
- </select>
- </div>
- </div>
- <div ng-if="ctrl.lab_location=='third'" class="field text">
- <div class="field text col-md-4">
- <label class="left">Lab Name</label>
- <i uib-tooltip="Lab Name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <input type="text" class="text form-control" ng-model="ctrl.lab_name">
- </div>
- <div class="field text col-md-4">
- <label class="left">Lab Email</label>
- <i uib-tooltip="Lab Email" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <input type="text" class="text form-control" ng-model="ctrl.lab_email">
- </div>
- <div class="field text col-md-4">
- <label class="left">Lab Address</label>
- <i uib-tooltip="Lab Address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <input type="text" class="text form-control" ng-model="ctrl.lab_address">
- </div>
- <div class="field text col-md-4">
- <label class="left">Lab Phone Number</label>
- <i uib-tooltip="Lab Phone Number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
- <input type="text" class="text form-control" ng-model="ctrl.lab_phone">
- </div>
- </div>
- </fieldset>
- </form>
- </div>
- </div>
- <div class="Actions">
- <button class="btn btn-success cvp-btn" ng-click="ctrl.openConfirmModal()">Submit</button>
- </div>
<div class="results-table" style="margin-top: 30px; overflow: scroll;">
<table class="table table-striped table-hover">
<thead>
@@ -217,7 +14,7 @@
<th>Primary business email</th>
<th>Primary postal address</th>
<th>Primary phone number</th>
- <th>Owner</th>
+ <th>User ID</th>
<th>Description</th>
<th>SUT version</th>
<th>SUT HW version</th>
@@ -225,7 +22,6 @@
<th>OVP category</th>
<th>Company logo</th>
<th>Approve date</th>
- <th>Approved</th>
<th>Test ID</th>
<th>Location</th>
<th>Operation</th>
@@ -284,7 +80,6 @@
<td>{{ app.ovp_category }}</td>
<td>{{ app.company_logo }}</td>
<td>{{ app.approve_date }}</td>
- <td>{{ app.approved }}</td>
<td>{{ app.test_id }}</td>
<td>
<span popover-enable="app.lab_location != 'internal'" uib-popover-template="ctrl.lab_tpl"
@@ -293,7 +88,13 @@
<i ng-if="app.lab_location != 'internal'" class="glyphicon glyphicon-info-sign opnfv-blue"></i>
</td>
<td>
- <a ng-click="ctrl.deleteApp(app._id)" class="badge badge-info">
+ <a ng-click="ctrl.toggleApproveApp(app._id, 'true')" class="badge badge-info"
+ ng-if="app.approved == 'false'"
+ data-toggle="tooltip" title="Approve Application">
+ <i class="glyphicon glyphicon-ok" ></i>
+ </a>
+ <a ng-click="ctrl.deleteApp(app._id)" class="badge badge-info"
+ data-toggle="tooltip" title="Delete Application">
<i class="glyphicon glyphicon-remove" ></i>
</a>
</td>
@@ -315,20 +116,4 @@
</uib-pagination>
</div>
</div>
-
- <div>
- <br>
- <h3>Company Logo Upload for Directory</h3>
- <form enctype="multipart/form-data" method="post">
- <div class="form-group col-m-3">
- <input class="form-contrl btn btn-success cvp-btn medium accent-color regular-button" file-model="logoFile"
- type="file">
- </div>
- <div class="form-group col-m-3">
- <a class="btn btn-success cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadLogo()">
- <span>Upload Logo</span>
- </a>
- </div>
- </form>
- </div>
</div>
diff --git a/3rd_party/static/testapi-ui/components/application/applicationController.js b/3rd_party/static/testapi-ui/components/application/applicationController.js
index e2a4f75..6ae157e 100644
--- a/3rd_party/static/testapi-ui/components/application/applicationController.js
+++ b/3rd_party/static/testapi-ui/components/application/applicationController.js
@@ -28,35 +28,36 @@
$uibModal, testapiApiUrl, raiseAlert, ngDialog, $scope) {
var ctrl = this;
- ctrl.uploadLogo = uploadLogo;
+// ctrl.uploadLogo = uploadLogo;
function init() {
- ctrl.organization_name = null;
- ctrl.organization_web = null;
- ctrl.product_name = null;
- ctrl.product_spec = null;
- ctrl.product_documentation = null;
- ctrl.product_categories = "soft&hard";
- ctrl.prim_name = null;
- ctrl.prim_email = null;
- ctrl.prim_address = null;
- ctrl.prim_phone = null;
- ctrl.description = null;
- ctrl.sut_version = null;
- ctrl.sut_hw_version = null;
- ctrl.ovp_version = "2018.01";
- ctrl.ovp_category = "Infrastructure";
- ctrl.company_logo = null;
- ctrl.approve_date = null;
- ctrl.approved = "false";
- ctrl.test_id = null;
- ctrl.lab_location = "internal";
- ctrl.lab_name = null;
- ctrl.lab_email = null;
- ctrl.lab_address = null;
- ctrl.lab_phone = null;
ctrl.applications = [];
- ctrl.showApplications = [];
+// ctrl.organization_name = null;
+// ctrl.organization_web = null;
+// ctrl.product_name = null;
+// ctrl.product_spec = null;
+// ctrl.product_documentation = null;
+// ctrl.product_categories = "soft&hard";
+// ctrl.prim_name = null;
+// ctrl.prim_email = null;
+// ctrl.prim_address = null;
+// ctrl.prim_phone = null;
+// ctrl.description = null;
+// ctrl.sut_version = null;
+// ctrl.sut_hw_version = null;
+// ctrl.ovp_version = "2018.01";
+// ctrl.ovp_category = "Infrastructure";
+// ctrl.company_logo = null;
+// ctrl.approve_date = null;
+// ctrl.approved = "false";
+// ctrl.test_id = null;
+// ctrl.lab_location = "internal";
+// ctrl.lab_name = null;
+// ctrl.lab_email = null;
+// ctrl.lab_address = null;
+// ctrl.lab_phone = null;
+// ctrl.applications = [];
+// ctrl.showApplications = [];
ctrl.totalItems = null;
ctrl.currentPage = 1;
@@ -70,52 +71,52 @@
}
- ctrl.submitForm = function() {
- var data = {
- "organization_name": ctrl.organization_name,
- "organization_web": ctrl.organization_web,
- "product_name": ctrl.product_name,
- "product_spec": ctrl.product_spec,
- "product_documentation": ctrl.product_documentation,
- "product_categories": ctrl.product_categories,
- "prim_name": ctrl.prim_name,
- "prim_email": ctrl.prim_email,
- "prim_address": ctrl.prim_address,
- "prim_phone": ctrl.prim_phone,
- "description": ctrl.description,
- "sut_version": ctrl.sut_version,
- "sut_hw_version": ctrl.sut_hw_version,
- "ovp_version": ctrl.ovp_version,
- "ovp_category": ctrl.ovp_category,
- "company_logo": ctrl.company_logo,
- "approve_date": ctrl.approve_date,
- "approved": ctrl.approved,
- "test_id": ctrl.test_id,
- "lab_location": ctrl.lab_location,
- "lab_email": ctrl.lab_email,
- "lab_address": ctrl.lab_address,
- "lab_phone": ctrl.lab_phone
- };
- $http.post(testapiApiUrl + "/cvp/applications", data).then(function(resp) {
- if (resp.data.code && resp.data.code != 0) {
- alert(resp.data.msg);
- return;
- }
- getApplication();
- }, function(error) {
- });
- }
-
- ctrl.openConfirmModal = function() {
- var resp = confirm("Are you sure to submit?");
- if (resp) {
- ctrl.submitForm();
- }
- }
-
- ctrl.cancelSubmit = function() {
- ngDialog.close();
- }
+// ctrl.submitForm = function() {
+// var data = {
+// "organization_name": ctrl.organization_name,
+// "organization_web": ctrl.organization_web,
+// "product_name": ctrl.product_name,
+// "product_spec": ctrl.product_spec,
+// "product_documentation": ctrl.product_documentation,
+// "product_categories": ctrl.product_categories,
+// "prim_name": ctrl.prim_name,
+// "prim_email": ctrl.prim_email,
+// "prim_address": ctrl.prim_address,
+// "prim_phone": ctrl.prim_phone,
+// "description": ctrl.description,
+// "sut_version": ctrl.sut_version,
+// "sut_hw_version": ctrl.sut_hw_version,
+// "ovp_version": ctrl.ovp_version,
+// "ovp_category": ctrl.ovp_category,
+// "company_logo": ctrl.company_logo,
+// "approve_date": ctrl.approve_date,
+// "approved": ctrl.approved,
+// "test_id": ctrl.test_id,
+// "lab_location": ctrl.lab_location,
+// "lab_email": ctrl.lab_email,
+// "lab_address": ctrl.lab_address,
+// "lab_phone": ctrl.lab_phone
+// };
+// $http.post(testapiApiUrl + "/cvp/applications", data).then(function(resp) {
+// if (resp.data.code && resp.data.code != 0) {
+// alert(resp.data.msg);
+// return;
+// }
+// getApplication();
+// }, function(error) {
+// });
+// }
+
+// ctrl.openConfirmModal = function() {
+// var resp = confirm("Are you sure to submit?");
+// if (resp) {
+// ctrl.submitForm();
+// }
+// }
+//
+// ctrl.cancelSubmit = function() {
+// ngDialog.close();
+// }
ctrl.updatePage = function() {
getApplication();
@@ -136,23 +137,52 @@
});
}
- function uploadLogo() {
- var file = $scope.logoFile;
- var fd = new FormData();
- fd.append('file', file);
+ ctrl.toggleApproveApp = function(id, approved) {
+ if (approved === 'true') {
+ var text = 'Are you sure you want to approve this application?';
+ } else {
+ var text = 'Are you sure you want to remove approval of this application?';
+ }
+
+ var resp = confirm(text);
+ if (!resp)
+ return;
- $http.post(testapiApiUrl + "/cvp/applications/uploadlogo", fd, {
+ var updateUrl = testapiApiUrl + "/cvp/applications/" + id;
+ var data = {};
+ data['item'] = 'approved';
+ data['approved'] = approved;
+
+ $http.put(updateUrl, JSON.stringify(data), {
transformRequest: angular.identity,
- headers: {'Content-Type': undefined}
- }).then(function(resp) {
- if (resp.data.code && resp.data.code != 0) {
- alert(resp.data.msg);
- return;
- }
+ headers: {'Content-Type': 'application/json'}}).then(function(ret) {
+ if (ret.data.code && ret.data.code != 0) {
+ alert(ret.data.msg);
+ return;
+ }
+ getApplication();
}, function(error) {
+ alert('Error when update data');
});
+ }
- };
+// function uploadLogo() {
+// var file = $scope.logoFile;
+// var fd = new FormData();
+// fd.append('file', file);
+//
+// $http.post(testapiApiUrl + "/cvp/applications/uploadlogo", fd, {
+// transformRequest: angular.identity,
+// headers: {'Content-Type': undefined}
+// }).then(function(resp) {
+// if (resp.data.code && resp.data.code != 0) {
+// alert(resp.data.msg);
+// return;
+// }
+// }, function(error) {
+// });
+//
+// };
function getApplication() {
$http.get(testapiApiUrl + "/cvp/applications?page=" + ctrl.currentPage + "&signed&per_page=" + ctrl.itemsPerPage).then(function(response) {
diff --git a/3rd_party/static/testapi-ui/components/profile/profile.html b/3rd_party/static/testapi-ui/components/profile/profile.html
index 563adbf..cfcc79a 100644
--- a/3rd_party/static/testapi-ui/components/profile/profile.html
+++ b/3rd_party/static/testapi-ui/components/profile/profile.html
@@ -23,6 +23,67 @@
</tbody>
</table>
</div>
+ <br>
+ <br>
+ <h3>Organization Details</h3>
+ <table class="table table-striped table-hover">
+ <tbody>
+ <tr>
+ <td>Company Name</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'companyName', $data)"
+ editable-text="ctrl.profile.companyName">{{ ctrl.profile.companyName || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Company website</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'companyWebsite', $data)"
+ editable-url="ctrl.profile.companyWebsite">{{ ctrl.profile.companyWebsite || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Name</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryContactName', $data)"
+ editable-text="ctrl.profile.primaryContactName">{{ ctrl.profile.primaryContactName || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Business email</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryBusinessEmail', $data)"
+ editable-email="ctrl.profile.primaryBusinessEmail">{{ ctrl.profile.primaryBusinessEmail || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Postal Address</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryPostalAddress', $data)"
+ editable-text="ctrl.profile.primaryPostalAddress">{{ ctrl.profile.primaryPostalAddress || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ <tr>
+ <td>Primary Contact Phone Number</td>
+ <td>
+ <div class="popover-wrapper">
+ <a editable-theme="bs3" onbeforesave="ctrl.changeProfileDetails(ctrl.profile, 'primaryPhoneNumber', $data)"
+ editable-tel="ctrl.profile.primaryPhoneNumber">{{ ctrl.profile.primaryPhoneNumber || "None" }}</a>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
<div ng-show="ctrl.pubkeys">
<div class="container-fluid">
<div class="row">
diff --git a/3rd_party/static/testapi-ui/components/profile/profileController.js b/3rd_party/static/testapi-ui/components/profile/profileController.js
index 0660e19..506771d 100644
--- a/3rd_party/static/testapi-ui/components/profile/profileController.js
+++ b/3rd_party/static/testapi-ui/components/profile/profileController.js
@@ -51,12 +51,38 @@
ctrl.updatePubKeys = updatePubKeys;
ctrl.openImportPubKeyModal = openImportPubKeyModal;
ctrl.openShowPubKeyModal = openShowPubKeyModal;
+ ctrl.changeProfileDetails = changeProfileDetails;
// Must be authenticated to view this page.
if (!$scope.auth.isAuthenticated) {
$state.go('home');
}
+ ctrl.authRequest = $scope.auth.doSignCheck();
+ ctrl.profile = $scope.auth.currentUser;
+
+ function changeProfileDetails(profile, key, newValue){
+ if (profile[key] === newValue) {
+ return;
+ }
+ var updateUrl = testapiApiUrl + "/profile";
+
+ var data = {};
+ data[key] = newValue;
+
+ $http.put(updateUrl, JSON.stringify(data), {
+ transformRequest: angular.identity,
+ headers: {'Content-Type': 'application/json'}}).then(function(ret) {
+ if (ret.data.code && ret.data.code != 0) {
+ alert(ret.data.msg);
+ } else {
+ profile[key] = newValue;
+ }
+ }, function(error) {
+ alert("Error when update data");
+ });
+ }
+
/**
* This function will fetch all the user's public keys from the
* server and store them in an array.
diff --git a/3rd_party/static/testapi-ui/components/results/modal/applicationModal.html b/3rd_party/static/testapi-ui/components/results/modal/applicationModal.html
new file mode 100644
index 0000000..e7c4609
--- /dev/null
+++ b/3rd_party/static/testapi-ui/components/results/modal/applicationModal.html
@@ -0,0 +1,191 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Complete this application then start your CVP journey</p>
+ </div>
+ </div>
+
+ <div class="row" style="margin-top: 20px;">
+ <div class="col-lg-12 container">
+ <p class="message" style="display: none;"></p>
+ <fieldset>
+ <div class="field text col-md-4">
+ <label class="left" >Organization name</label>
+ <i uib-tooltip="Organization name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.organization_name"
+ ng-init="ctrl.organization_name=auth.currentUser.companyName" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Company Logo</label>
+ <i uib-tooltip="Required dimensions (Max Values): {width: 165pixels, height: 40pixels}" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input class="form-control btn btn-success-cust cvp-btn medium accent-color regular-button"
+ modal-file-model="logoFile" type="file" style="padding: 0;" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Organization website</label>
+ <i uib-tooltip="Organization website if it is public"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="url" class="text form-control" ng-model="ctrl.organization_web"
+ ng-init="ctrl.organization_web=auth.currentUser.companyWebsite" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product name and/or identifier</label>
+ <i uib-tooltip="Product name and/or identifier" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="email text form-control" ng-model="ctrl.product_name" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product specifications</label>
+ <i uib-tooltip="A link of product specifications"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.product_spec" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product public documentation</label>
+ <i uib-tooltip="A link of product public documentation"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.product_documentation" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product categories</label>
+ <i uib-tooltip="Product categories" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <select class="form-control" ng-model="ctrl.product_categories" ng-init="ctrl.product_categories='soft&hard'">
+ <option value="soft&hard">software and hardware</option>
+ <option value="soft&3rd">software and third party hardware</option>
+ </select>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary contact name</label>
+ <i uib-tooltip="Primary contact name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.prim_name"
+ ng-init="ctrl.prim_name=auth.currentUser.primaryContactName" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary business email</label>
+ <i uib-tooltip="Only the Business email address should be used for official communication with OPNFV CVP"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="email" class="text form-control" ng-model="ctrl.prim_email"
+ ng-init="ctrl.prim_email=auth.currentUser.primaryBusinessEmail" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary postal address</label>
+ <i uib-tooltip="Primary postal address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.prim_address"
+ ng-init="ctrl.prim_address=auth.currentUser.primaryPostalAddress" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary phone number</label>
+ <i uib-tooltip="Primary phone number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.prim_phone"
+ ng-init="ctrl.prim_phone=auth.currentUser.primaryPhoneNumber" required
+ aria-required="true">
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Description</label>
+ <i uib-tooltip="Product Description" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.description" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Version</label>
+ <i uib-tooltip="SUT Version" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.sut_version" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Label</label>
+ <i uib-tooltip="SUT Label" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.sut_label" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT HW Version</label>
+ <i uib-tooltip="SUT HW Version - leave blank if not applicable"
+ class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.sut_hw_version" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">OVP Category</label>
+ <i uib-tooltip="OVP Category" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <input type="text" class="text form-control" ng-model="ctrl.ovp_category" required>
+ </div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Location</label>
+ <i uib-tooltip="Location" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <div class="middleColumn">
+ <select class="form-control" ng-model="ctrl.lab_location" ng-init="ctrl.lab_location='internal'">
+ <option value="internal">internal vendor lab</option>
+ <option value="third">third-party lab</option>
+ </select>
+ </div>
+ </div>
+ <div ng-if="ctrl.lab_location=='third'" class="field text">
+ <div class="field text col-md-4">
+ <label class="left">Lab Name</label>
+ <i uib-tooltip="Lab Name" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="text" class="text form-control" ng-model="ctrl.lab_name" required>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Email</label>
+ <i uib-tooltip="Lab Email" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="text" class="text form-control" ng-model="ctrl.lab_email" required>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Address</label>
+ <i uib-tooltip="Lab Address" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="text" class="text form-control" ng-model="ctrl.lab_address" required>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Phone Number</label>
+ <i uib-tooltip="Lab Phone Number" class="glyphicon glyphicon-question-sign opnfv-blue"></i>
+ <input type="text" class="text form-control" ng-model="ctrl.lab_phone" required>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+ <button class="btn btn-default"
+ ng-click="ctrl.openConfirmModal(ctrl.tempResult)">Submit</button>
+</div>
+
+<style type="text/css">
+ .ngdialog.custom-background .ngdialog-content {
+ background: #ffffff;
+ }
+</style>
diff --git a/3rd_party/static/testapi-ui/components/results/modal/applicationView.html b/3rd_party/static/testapi-ui/components/results/modal/applicationView.html
new file mode 100644
index 0000000..3cbbcb5
--- /dev/null
+++ b/3rd_party/static/testapi-ui/components/results/modal/applicationView.html
@@ -0,0 +1,107 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Application Details</p>
+ </div>
+ </div>
+
+ <div class="row" style="margin-top: 20px;">
+ <div class="col-lg-12 container">
+ <p class="message" style="display: none;"></p>
+ <fieldset>
+ <div class="field text col-md-4">
+ <label class="left">Organization name</label>
+ <div class="middleColumn">{{ ctrl.application.organization_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Company Logo</label>
+ <div class="middleColumn">{{ ctrl.application.company_logo }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Organization website</label>
+ <div class="middleColumn">{{ ctrl.application.organization_web }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product name and/or identifier</label>
+ <div class="middleColumn">{{ ctrl.application.product_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product specifications</label>
+ <div class="middleColumn">{{ ctrl.application.product_spec }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product public documentation</label>
+ <div class="middleColumn">{{ ctrl.application.product_documentation }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Product categories</label>
+ <div class="middleColumn">{{ ctrl.application.product_categories }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary contact name</label>
+ <div class="middleColumn">{{ ctrl.application.prim_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary business email</label>
+ <div class="middleColumn">{{ ctrl.application.prim_email }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary postal address</label>
+ <div class="middleColumn">{{ ctrl.application.prim_address }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Primary phone number</label>
+ <div class="middleColumn">{{ ctrl.application.prim_phone }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Description</label>
+ <div class="middleColumn">{{ ctrl.application.description }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Version</label>
+ <div class="middleColumn">{{ ctrl.application.sut_version }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT Label</label>
+ <div class="middleColumn">{{ ctrl.application.sut_label }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">SUT HW Version</label>
+ <div class="middleColumn">{{ ctrl.application.sut_hw_version }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">OVP Category</label>
+ <div class="middleColumn">{{ ctrl.application.ovp_category }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Location</label>
+ <div class="middleColumn">{{ ctrl.application.lab_location }}</div>
+ </div>
+ <div ng-if="ctrl.lab_location=='third'" class="field text">
+ <div class="field text col-md-4">
+ <label class="left">Lab Name</label>
+ <div>{{ ctrl.application.lab_name }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Email</label>
+ <div>{{ ctrl.application.lab_email }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Address</label>
+ <div>{{ ctrl.application.lab_address }}</div>
+ </div>
+ <div class="field text col-md-4">
+ <label class="left">Lab Phone Number</label>
+ <div>{{ ctrl.application.lab_phone }}</div>
+ </div>
+ </div>
+ </fieldset>
+ </div>
+ </div>
+</div>
+
+<style type="text/css">
+ .ngdialog.custom-background .ngdialog-content {
+ background: #ffffff;
+ }
+</style>
diff --git a/3rd_party/static/testapi-ui/components/results/modal/reviewsModal.html b/3rd_party/static/testapi-ui/components/results/modal/reviewsModal.html
new file mode 100644
index 0000000..c93d1ef
--- /dev/null
+++ b/3rd_party/static/testapi-ui/components/results/modal/reviewsModal.html
@@ -0,0 +1,41 @@
+<div class="container-fluid common-main-container">
+ <div class="top-site-banner">
+ <div class="container">
+ <p class="p1">Community Reviews</p>
+ </div>
+ </div>
+
+ <div class="row" style="margin-top: 20px;">
+ <div class="col-lg-12 container">
+ <div cg-busy="{promise:ctrl.reviewsRequest,message:'Loading'}"></div>
+ <div ng-show="ctrl.reviews" class="results-table" style="width: 100%; overflow-x: scroll;">
+ <table ng-data="ctrl.reviews" ng-show="ctrl.reviews" class="table table-striped table-hover">
+ <thead>
+ <tr>
+ <th>Reviewer</th>
+ <th>Linux Foundation OpenId</th>
+ <th>Email</th>
+ <th>Review Date</th>
+ <th>Outcome</th>
+ </tr>
+ </thead>
+ <tbody style="white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">
+ <tr ng-repeat="(index, review) in ctrl.reviews">
+ <td>{{ review.reviewer_name }}</td>
+ <td>{{ review.reviewer_openid }}</td>
+ <td>{{ review.reviewer_email }}</td>
+ <td>{{ review.creation_date | limitTo:19}}</td>
+ <td>{{ review.outcome }}</td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </div>
+</div>
+
+<style type="text/css">
+ .ngdialog.custom-background .ngdialog-content {
+ background: #ffffff;
+ }
+</style>
diff --git a/3rd_party/static/testapi-ui/components/results/results.html b/3rd_party/static/testapi-ui/components/results/results.html
index bc15169..30bcd94 100644
--- a/3rd_party/static/testapi-ui/components/results/results.html
+++ b/3rd_party/static/testapi-ui/components/results/results.html
@@ -1,17 +1,18 @@
<div class="container-fluid common-main-container">
<h3>{{ctrl.pageHeader}}</h3>
<p>{{ctrl.pageParagraph}}</p>
- <form class="form-inline" ng-show="ctrl.isUserResults">
+ <form class="form-inline" ng-show="ctrl.isUserResults"
+ ng-if="auth.isAuthenticated && auth.currentUser.role.indexOf('user') != -1">
<h4>Upload Results
<i class="glyphicon glyphicon-question-sign opnfv-blue"
uib-tooltip="results file is logs.xxx.tar.gz under your dovetail installation path"></i>
</h4>
<div class="form-group col-m-3">
- <input class="form-contrl btn btn-success cvp-btn medium accent-color regular-button" type="file"
+ <input class="form-contrl btn btn-success-cust cvp-btn medium accent-color regular-button" type="file"
file-model="resultFile">
</div>
<div class="form-group col-m-3">
- <a class="btn btn-success cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadFile()">
+ <a class="btn btn-success-cust cvp-btn medium accent-color regular-button" ng-click="ctrl.uploadFile()">
<span>upload result</span>
</a>
</div>
@@ -36,7 +37,8 @@
<th>Status</th>
<th>Log</th>
<th>SUT</th>
- <th>SUT Version</th>
+ <th>Application</th>
+ <th>Review Status</th>
<th class="col-md-2">Operation</th>
<th class="col-md-2">Share List</th>
</tr>
@@ -62,43 +64,52 @@
<td><a ng-click="ctrl.downloadLogs(result.id)">logs</a></td>
<td><a ng-click="ctrl.gotoSUT(result.id)">info</a></td>
<td>
- <div class="popover-wrapper">
- <a editable-theme="bs3" onbeforesave="ctrl.changeLabel(result, 'sut_label', $data)"
- editable-text="result.sut_label">{{ result.sut_label || "None" }}</a>
- </div>
+ <a ng-if="result.status !='private'" ng-click="ctrl.openApplicationView(result)">View Application</a>
+ <div ng-if="result.status == 'private'">Not created</div>
+ </td>
+ <td><a ng-if="result.status !='private'" ng-click="ctrl.openReviewsModal(result.id)">View Reviews</a>
+ <div ng-if="result.status == 'private'"></div>
</td>
<td>
<div class="btn-group" uib-dropdown>
- <a id="single-button" type="button" class="btn btn-success cvp-btn medium accent-color regular-button"
+ <a id="single-button" type="button" class="btn btn-success-cust cvp-btn medium accent-color regular-button"
uib-dropdown-toggle>
Operation<span class="caret"></span>
</a>
<ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="single-button">
- <li role="menuitem" ng-if="auth.currentUser.openid == result.owner"
+ <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults"
class="menu-item menu-item-type-post_type menu-item-object-page">
- <a ng-class="{'hide': result.status == 'private'}"
- ng-click="ctrl.toPrivate(result, 'private')">withdraw submit</a>
+ <a ng-class="{'hide': result.status != 'review'}"
+ ng-click="ctrl.deleteApplication(result)">withdraw submit</a>
</li>
- <li role="menuitem" ng-if="auth.currentUser.openid == result.owner"
+ <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults"
class="menu-item menu-item-type-post_type menu-item-object-page">
<a ng-class="{'hide': result.status != 'private'}"
- ng-click="ctrl.toReview(result, 'review')">submit to review</a>
+ ng-click="ctrl.openApplicationModal(result)">submit to review</a>
+ </li>
+ <li role="menuitem"
+ ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults"
+ class="menu-item menu-item-type-post_type menu-item-object-page">
+ <a ng-class="{'hide': (result.voted == 'true') || (result.status != 'review')}"
+ ng-click="ctrl.toApprove(result)">approve</a>
</li>
- <li role="menuitem" ng-if="auth.currentUser.role.indexOf('administrator') != -1"
+ <li role="menuitem"
+ ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults"
class="menu-item menu-item-type-post_type menu-item-object-page">
- <a ng-class="{'hide': result.status == 'approved' || result.status == 'private'}"
- ng-click="ctrl.toggleCheck(result, 'status', 'approved')">approve</a>
+ <a ng-class="{'hide': (result.voted == 'true') || (result.status != 'review')}"
+ ng-click="ctrl.toDisapprove(result)">not approve</a>
</li>
- <li role="menuitem" ng-if="auth.currentUser.role.indexOf('administrator') != -1"
+ <li role="menuitem"
+ ng-if="auth.currentUser.role.indexOf('reviewer') != -1 && !ctrl.isUserResults"
class="menu-item menu-item-type-post_type menu-item-object-page">
- <a ng-class="{'hide': result.status == 'not approved' || result.status == 'private'}"
- ng-click="ctrl.toggleCheck(result, 'status', 'not approved')">not approve</a>
+ <a ng-class="{'hide': (result.voted == 'false') || (result.status != 'review')}"
+ ng-click="ctrl.toUndo(result)">undo</a>
</li>
- <li role="menuitem" ng-if="auth.currentUser.openid == result.owner"
+ <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults"
class="menu-item menu-item-type-post_type menu-item-object-page">
<a ng-click="ctrl.openSharedModal(result)">share with</a>
</li>
- <li role="menuitem" ng-if="auth.currentUser.openid == result.owner"
+ <li role="menuitem" ng-if="auth.currentUser.openid == result.owner && ctrl.isUserResults"
class="menu-item menu-item-type-post_type menu-item-object-page">
<a ng-click="ctrl.deleteTest(result._id)">delete</a>
</li>
@@ -108,7 +119,7 @@
<td>
<div class="btn-group" uib-dropdown>
<a id="single-button-two" type="button"
- class="btn btn-success cvp-btn medium accent-color regular-button" style="width: 130px;"
+ class="btn btn-success-cust cvp-btn medium accent-color regular-button" style="width: 130px;"
uib-dropdown-toggle>
Share List<span class="caret"></span>
</a>
diff --git a/3rd_party/static/testapi-ui/components/results/resultsController.js b/3rd_party/static/testapi-ui/components/results/resultsController.js
index 6e4e0ac..1fb4f0d 100644
--- a/3rd_party/static/testapi-ui/components/results/resultsController.js
+++ b/3rd_party/static/testapi-ui/components/results/resultsController.js
@@ -37,6 +37,24 @@
};
}]);
+ angular
+ .module('testapiApp')
+ .directive('modalFileModel', ['$parse', function ($parse) {
+ return {
+ restrict: 'A',
+ link: function(scope, element, attrs) {
+ var model = $parse(attrs.modalFileModel);
+ var modelSetter = model.assign;
+
+ element.bind('change', function(){
+ scope.$apply(function(){
+ modelSetter(scope.$parent, element[0].files[0]);
+ });
+ });
+ }
+ };
+ }]);
+
ResultsController.$inject = [
'$scope', '$http', '$filter', '$state', 'testapiApiUrl','raiseAlert', 'ngDialog', '$resource'
];
@@ -62,7 +80,6 @@
ctrl.gotoSUT = gotoSUT;
ctrl.gotoResultDetail = gotoResultDetail;
ctrl.toggleCheck = toggleCheck;
- ctrl.changeLabel = changeLabel;
ctrl.toReview = toReview;
ctrl.toPrivate = toPrivate;
ctrl.removeSharedUser = removeSharedUser;
@@ -70,6 +87,16 @@
ctrl.openSharedModal = openSharedModal;
ctrl.downloadLogs = downloadLogs;
ctrl.deleteTest = deleteTest;
+ ctrl.deleteApplication = deleteApplication;
+ ctrl.openApplicationModal = openApplicationModal;
+ ctrl.toApprove = toApprove;
+ ctrl.toDisapprove = toDisapprove;
+ ctrl.toUndo = toUndo;
+ ctrl.openConfirmModal = openConfirmModal;
+ ctrl.openApplicationView = openApplicationView;
+ ctrl.submitApplication = submitApplication;
+ ctrl.openReviewsModal = openReviewsModal;
+ ctrl.doReview = doReview;
/** Mappings of Interop WG components to marketing program names. */
ctrl.targetMappings = {
@@ -110,10 +137,17 @@
// ctrl.isUserResults = $state.current.name === 'userResults';
// need auth to browse
ctrl.isUserResults = $state.current.name === 'userResults';
+ ctrl.isReviewer = $scope.auth.currentUser.role.indexOf('reviewer') != -1;
+ ctrl.isAdministrator = $scope.auth.currentUser.role.indexOf('administrator') != -1;
ctrl.currentUser = $scope.auth.currentUser ? $scope.auth.currentUser.openid : null;
// Should only be on user-results-page if authenticated.
+ if (!$scope.auth.isAuthenticated) {
+ $state.go('home');
+ }
+
+ // Should only be on user-results-page if authenticated.
if (ctrl.isUserResults && !$scope.auth.isAuthenticated) {
$state.go('home');
}
@@ -167,6 +201,216 @@
});
}
+ function deleteApplication (result) {
+ var resp = confirm('Are you sure you want to delete this application?');
+ if (!resp)
+ return;
+
+ $http.get(testapiApiUrl + "/cvp/applications?test_id=" + result.id).then(function(response) {
+ ctrl.application = response.data.applications[0];
+ var app_id = ctrl.application._id;
+ var delUrl = testapiApiUrl + "/cvp/applications/" + app_id;
+ $http.delete(delUrl)
+ .then(function(ret) {
+ if (ret.data.code && ret.data.code != 0) {
+ alert(ret.data.msg);
+ return;
+ }
+ result['status'] = 'private';
+ });
+
+ }, function(error) {
+ /* do nothing */
+ });
+
+ }
+
+ function submitApplication(result) {
+ var file = $scope.logoFile;
+ var logo_name = null;
+ if (typeof file !== 'undefined') {
+ var fd = new FormData();
+ fd.append('file', file);
+ fd.append('company_name', ctrl.organization_name)
+
+ $http.post(testapiApiUrl + "/cvp/applications/uploadlogo", fd, {
+ transformRequest: angular.identity,
+ headers: {'Content-Type': undefined}
+ }).then(function(resp) {
+ if (resp.data.code && resp.data.code != 0) {
+ alert(resp.data.msg);
+ return;
+ } else {
+ logo_name = resp.data.filename;
+ var data = {
+ "organization_name": ctrl.organization_name,
+ "organization_web": ctrl.organization_web,
+ "product_name": ctrl.product_name,
+ "product_spec": ctrl.product_spec,
+ "product_documentation": ctrl.product_documentation,
+ "product_categories": ctrl.product_categories,
+ "prim_name": ctrl.prim_name,
+ "prim_email": ctrl.prim_email,
+ "prim_address": ctrl.prim_address,
+ "prim_phone": ctrl.prim_phone,
+ "description": ctrl.description,
+ "sut_version": ctrl.sut_version,
+ "sut_label": ctrl.sut_label,
+ "sut_hw_version": ctrl.sut_hw_version,
+ "ovp_version": result.version,
+ "ovp_category": ctrl.ovp_category,
+ "company_logo": logo_name,
+ "approve_date": "",
+ "approved": "false",
+ "test_id": result.id,
+ "lab_location": ctrl.lab_location,
+ "lab_email": ctrl.lab_email,
+ "lab_address": ctrl.lab_address,
+ "lab_phone": ctrl.lab_phone
+ };
+
+ $http.post(testapiApiUrl + "/cvp/applications", data).then(function(resp) {
+ if (resp.data.code && resp.data.code != 0) {
+ alert(resp.data.msg);
+ return;
+ }
+ toggleCheck(result, 'status', 'review');
+ }, function(error) {
+ /* do nothing */
+ });
+ }
+ }, function(error) {
+ /* do nothing */
+ });
+ logo_name = file.name;
+ }
+ ngDialog.close();
+ }
+
+ function openConfirmModal(result) {
+ var resp = confirm("Are you sure to submit?");
+ if (resp) {
+ ctrl.submitApplication(result);
+ }
+ }
+
+ function openApplicationModal(result) {
+ ctrl.tempResult = result;
+ ngDialog.open({
+ preCloseCallback: function(value) {
+ },
+ template: 'testapi-ui/components/results/modal/applicationModal.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function openApplicationView(result) {
+ $http.get(testapiApiUrl + "/cvp/applications?test_id=" + result.id).then(function(response) {
+ ctrl.application = response.data.applications[0];
+ }, function(error) {
+ /* do nothing */
+ });
+
+ ctrl.tempResult = result;
+ ngDialog.open({
+ preCloseCallback: function(value) {
+ },
+ template: 'testapi-ui/components/results/modal/applicationView.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function getReviews(test) {
+ var reviews_url = testapiApiUrl + '/reviews?test_id=' + test;
+ ctrl.reviewsRequest =
+ $http.get(reviews_url).success(function (data) {
+ ctrl.reviews = data.reviews;
+ }).error(function (error) {
+ ctrl.reviews = null;
+ });
+ }
+
+ function openReviewsModal(test) {
+ getReviews(test);
+ ngDialog.open({
+ preCloseCallback: function(value) {
+ },
+ template: 'testapi-ui/components/results/modal/reviewsModal.html',
+ scope: $scope,
+ className: 'ngdialog-theme-default custom-background',
+ width: 950,
+ showClose: true,
+ closeByDocument: true
+ });
+ }
+
+ function doReview(test, outcome) {
+ var createUrl = testapiApiUrl + "/reviews";
+ var data = {
+ 'test_id': test.id,
+ 'outcome': outcome
+ };
+
+ $http.post(createUrl, JSON.stringify(data), {
+ transformRequest: angular.identity,
+ headers: {'Content-Type': 'application/json'}}).then(function(ret) {
+ if (ret.data.code && ret.data.code != 0) {
+ alert(ret.data.msg);
+ } else {
+ if (outcome === null) {
+ test.voted = 'false';
+ } else {
+ test.voted = 'true';
+ }
+ }
+ }, function(error) {
+ alert('Error when creating review');
+ });
+ }
+
+ function toApprove(test) {
+ var resp = confirm('Once you approve a test result, your action will become visible. Do you want to proceed?');
+ if (resp) {
+ doReview(test, 'positive');
+ }
+ }
+
+ function toDisapprove(test) {
+ var resp = confirm('Once you disapprove a test result, your action will become visible. Do you want to proceed?');
+ if (resp) {
+ doReview(test, 'negative');
+ }
+ }
+
+ function toUndo(test) {
+ var resp = confirm('Once you undo your previous vote, your action will become visible. Do you want to proceed?');
+ if (resp) {
+ doReview(test, null);
+ }
+ }
+
+ function toReview(result, value){
+ var resp = confirm('Once you submit a test result for review, it will become readable to all OVP reviewers. Do you want to proceed?');
+ if(resp){
+ toggleCheck(result, 'status', value);
+ }
+ }
+
+ function toPrivate(result, value){
+ var resp = confirm('Do you want to proceed?');
+ if(resp){
+ toggleCheck(result, 'status', value);
+ }
+ }
+
function toggleCheck(result, item, newValue) {
var id = result._id;
var updateUrl = testapiApiUrl + "/tests/"+ id;
@@ -189,10 +433,6 @@
});
}
- function changeLabel(result, key, data){
- toggleCheck(result, key, data);
- }
-
function toReview(result, value){
var resp = confirm('Once you submit a test result for review, it will become readable to all OVP reviewers. Do you want to proceed?');
if(resp){
@@ -291,20 +531,24 @@
function update() {
ctrl.showError = false;
// Construct the API URL based on user-specified filters.
- var content_url = testapiApiUrl + '/tests' +
- '?page=' + ctrl.currentPage;
+ var content_url = testapiApiUrl + '/tests';
var start = $filter('date')(ctrl.startDate, 'yyyy-MM-dd');
+ var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd');
+ content_url += '?page=' + ctrl.currentPage;
+ content_url += '&per_page=' + ctrl.itemsPerPage;
if (start) {
content_url =
content_url + '&from=' + start + ' 00:00:00';
}
- var end = $filter('date')(ctrl.endDate, 'yyyy-MM-dd');
if (end) {
content_url = content_url + '&to=' + end + ' 23:59:59';
}
if (ctrl.isUserResults) {
- content_url = content_url + '&signed'+'&per_page='+ ctrl.itemsPerPage;
+ content_url += '&signed';
+ } else {
+ content_url += '&status={"$ne":"private"}&review';
}
+
ctrl.resultsRequest =
$http.get(content_url).success(function (data) {
ctrl.data = data;
diff --git a/3rd_party/static/testapi-ui/index.html b/3rd_party/static/testapi-ui/index.html
index 94aff67..961e4cf 100644
--- a/3rd_party/static/testapi-ui/index.html
+++ b/3rd_party/static/testapi-ui/index.html
@@ -30,6 +30,7 @@
<link rel="stylesheet" href="testapi-ui/node_modules/ng-dialog/css/ngDialog.min.css">
<link rel="stylesheet" href="testapi-ui/node_modules/ng-dialog/css/ngDialog-theme-default.min.css">
<link rel="stylesheet" href="testapi-ui/node_modules/angular-xeditable/dist/css/xeditable.min.css">
+ <link rel="stylesheet" href="testapi-ui/assets/css/combine.css">
<!-- CSS Internal Code -->
<link rel="stylesheet" href="testapi-ui/assets/css/cvp-style.css">
@@ -75,7 +76,8 @@
</head>
<body class="container-fluid home page-template-default page page-id-6 do-etfw tribe-no-js ascend wpb-js-composer
- js-comp-ver-5.2.1 vc_responsive index-header">
+ js-comp-ver-5.2.1 vc_responsive index-header"
+ ng-controller="HeaderController as header">
<header ng-include src="'testapi-ui/shared/header/header.html'"></header>
<div ui-view></div>
<footer ng-include src="'testapi-ui/shared/footer/footer.html'"></footer>
diff --git a/3rd_party/static/testapi-ui/shared/header/header.html b/3rd_party/static/testapi-ui/shared/header/header.html
index 54470e7..fad240c 100644
--- a/3rd_party/static/testapi-ui/shared/header/header.html
+++ b/3rd_party/static/testapi-ui/shared/header/header.html
@@ -19,7 +19,12 @@
ng-if="auth.isAuthenticated && auth.currentUser.role.indexOf('administrator') != -1">
<a ui-sref="application">Applications</a>
</li>
- <li ng-class="{ active: header.isActive('/user_results')}" ng-if="auth.isAuthenticated">
+ <li ng-class="{ active: header.isActive('/community_results')}"
+ ng-if="auth.isAuthenticated && auth.canReview(auth.currentUser)">
+ <a ui-sref="communityResults">Incoming Reviews</a>
+ </li>
+ <li ng-class="{ active: header.isActive('/user_results')}"
+ ng-if="auth.isAuthenticated && auth.currentUser.role.indexOf('user') != -1">
<a ui-sref="userResults">My Results</a>
</li>
<li ng-class="{ active: header.isActive('/profile')}" ng-if="auth.isAuthenticated">
diff --git a/opnfv_testapi/resources/test_handlers.py b/opnfv_testapi/resources/test_handlers.py
index 7ab20dc..7c5078a 100644
--- a/opnfv_testapi/resources/test_handlers.py
+++ b/opnfv_testapi/resources/test_handlers.py
@@ -294,11 +294,6 @@ class TestsGURHandler(GenericTestHandler):
self.finish_request({'code': 403, 'msg': msg})
return
- 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
-
query['owner'] = curr_user
db_keys.append('owner')
diff --git a/opnfv_testapi/router/url_mappings.py b/opnfv_testapi/router/url_mappings.py
index 65c8480..4dc4893 100644
--- a/opnfv_testapi/router/url_mappings.py
+++ b/opnfv_testapi/router/url_mappings.py
@@ -56,6 +56,7 @@ mappings = [
(r'/api/v1/auth/signin_return_cas', sign.SigninReturnCasHandler),
(r'/api/v1/auth/signout', sign.SignoutHandler),
(r'/api/v1/profile', user.ProfileHandler),
+ (r'/api/v1/reviews', review_handlers.ReviewsCLHandler)
]