Add improvements to OVP directory and logo upload 29/58129/3
authorEddie Arrage <eddie.arrage@huawei.com>
Thu, 31 May 2018 23:59:31 +0000 (23:59 +0000)
committerGeorg Kunz <georg.kunz@ericsson.com>
Thu, 7 Jun 2018 09:25:12 +0000 (09:25 +0000)
- Formatting changes to directory on home page based
on OPNFV marketing
- Updated branding guide link
- Added test_id field to mongo applications collection
to associate to approved results for directory
- Set Test ID from user accounts with administrator
role in Applications view
- Provide file upload function for administrator to
post company logos for OVP directory
- Company logos are stored and served through tornado
from cvp-cvpapi container rather than cvp-web

JIRA: DOVETAIL-663
JIRA: DOVETAIL-664

Change-Id: I1226b42883afa2ea2eb5551e3836211abbb94b20
Signed-off-by: Eddie Arrage <eddie.arrage@huawei.com>
cvp/3rd_party/static/testapi-ui/assets/css/home/home.css
cvp/3rd_party/static/testapi-ui/components/application/application.html
cvp/3rd_party/static/testapi-ui/components/application/applicationController.js
cvp/3rd_party/static/testapi-ui/components/directory/directory.html
cvp/3rd_party/static/testapi-ui/components/home/home.html
cvp/opnfv_testapi/resources/application_handlers.py
cvp/opnfv_testapi/router/url_mappings.py

index ce8c88e..f6f9a2e 100644 (file)
 
 #directory_inner > thead > tr > th {
     border-bottom: 2px solid #ddd;
-    padding: 8px;
+    padding-bottom: 8px;
 }
 
 #directory_inner > tbody > tr > td {
     border-bottom: 1px solid #ddd;
 }
+
+.company_logo {
+    padding-right: 30px;
+    padding-left: 20px;
+    padding-top: 20px;
+    padding-bottom: 20px;
+}
+
+.company_row:hover {
+    cursor: pointer;
+    text-decoration: underline;
+}
index dc27585..17b17c6 100644 (file)
@@ -179,6 +179,13 @@ urpose. Once we understand more about your product or service, we can determine
                                         <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>
@@ -243,6 +250,7 @@ urpose. Once we understand more about your product or service, we can determine
                 <th>Company logo</th>
                 <th>Approve date</th>
                 <th>Approved</th>
+                <th>Test ID</th>
                 <th>Location</th>
                 <th>Operation</th>
             </tr>
@@ -302,6 +310,7 @@ urpose. Once we understand more about your product or service, we can determine
                 <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" popover-title="Lab Info" popover-placement="top" popover-trigger="mouseenter">{{ app.lab_location | labLocation}}</span><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"><i class="glyphicon glyphicon-remove" ></i></a></td>
             </tr>
@@ -322,4 +331,18 @@ urpose. Once we understand more about your product or service, we can determine
         </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>
index 32f1053..5666ff2 100644 (file)
@@ -30,6 +30,7 @@
         $uibModal, testapiApiUrl, raiseAlert, ngDialog, $scope) {
 
         var ctrl = this;
+        ctrl.uploadLogo=uploadLogo;
 
        function init(){
                ctrl.organization_name = null;
@@ -52,6 +53,7 @@
                 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;
@@ -94,6 +96,7 @@
                     "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,
           });
         }
 
+    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){
                        ctrl.applications = response.data.applications;
index d138313..1174752 100644 (file)
@@ -3,7 +3,7 @@
 
     <div>
         <h4>Compliance Marks Granted to {{ctrl.companyID}}</h4>
-        <img class="" src="testapi-ui/assets/img/{{ctrl.company_logo}}" />
+        <img class="" src="api/v1/cvp/applications/getlogo/{{ctrl.company_logo}}" />
         <table class="table table-striped table-hover">
             <thead>
                 <tr class="">
index f7d61cd..184980b 100644 (file)
@@ -61,7 +61,7 @@
                             " target="_blank">2018.01 Reviewer Guide&nbsp<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a></div>
                             <div><a href="http://docs.opnfv.org/en/stable-danube/submodules/dovetail/docs/testing/user/ovpaddendum/index.html
                             " target="_blank">2018.01 Guidelines Addendum&nbsp<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a></div>
-                            <div><a href="https://www.opnfv.org/wp-content/uploads/sites/12/2018/02/OPNFV_Verified_BrandGuide_021618.pdf
+                            <div><a href="https://www.opnfv.org/wp-content/uploads/sites/12/2018/05/OPNFV_Verified_BrandGuide_021618.pdf
                             " target="_blank">OPNFV Verified Brand Guidelines&nbsp<span class="glyphicon glyphicon-new-window" aria-hidden="true"></span></a></div>
                             <!--
                             <div><a target="_blank">FAQ</a></div>
                 </div>
                 <div class="home-content-title">
                     <h1>OPNFV Verified Products Directory</h1>
+                    Click on rows for more product verification details per company.
                 </div>
                 <div class="directory_main">
-                        <table id="directory_inner" class="table-striped table-hover">
+                        <table id="directory_inner" class="">
                             <thead>
                                 <tr>
                                     <th>Company</th>
                                 </tr>
                             </thead>
                             <tbody style="overflow: hidden; text-overflow: ellipsis;">
-                                <tr ng-click="ctrl.getCompany(app)" ng-repeat="app in ctrl.applications | filter:{approved:true} | orderBy : 'approve_date'">
-                                    <td width="450"><img src="testapi-ui/assets/img/{{app.company_logo}}" />&ensp;{{ app.organization_name}}</td>
+                                <tr class="company_row" ng-click="ctrl.getCompany(app)" ng-repeat="app in ctrl.applications | filter:{approved:true} | orderBy : 'approve_date'">
+                                    <td width="400"><img class="company_logo" src="api/v1/cvp/applications/getlogo/{{app.company_logo}}" />{{ app.organization_name}}</td>
                                     <td width="300">{{ app.product_name}}</td>
                                     <td width="150">{{ app.ovp_category}}</td>
                                     <td width="150">{{ app.ovp_version}}</td>
index 144b224..258c1aa 100644 (file)
@@ -30,6 +30,49 @@ class GenericApplicationHandler(handlers.GenericApiHandler):
         self.table_cls = application_models.Application
 
 
+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']
+        location = '3rd_party/static/testapi-ui/assets/img/'
+        fh = open(location + fname, 'w')
+        fh.write(fileinfo['body'])
+        msg = 'Successfully uploaded logo: ' + fname
+        resp = {'code': '1', 'msg': msg}
+        self.finish_request(resp)
+
+
+class ApplicationsGetLogoHandler(GenericApplicationHandler):
+    def get(self, filename):
+        location = '3rd_party/static/testapi-ui/assets/img/' + filename
+        self.set_header('Content-Type', 'application/force-download')
+        self.set_header('Content-Disposition',
+                        'attachment; filename=%s' % filename)
+        try:
+            with open(location, "rb") as f:
+                try:
+                    while True:
+                        _buffer = f.read(4096)
+                        if _buffer:
+                            self.write(_buffer)
+                        else:
+                            f.close()
+                            self.finish()
+                            return
+                except Exception:
+                    raise web.HTTPError(404)
+        except Exception:
+            raise web.HTTPError(500)
+
+
 class ApplicationsCLHandler(GenericApplicationHandler):
     @swagger.operation(nickname="queryApplications")
     @web.asynchronous
index 83190ee..e1d4c18 100644 (file)
@@ -24,6 +24,10 @@ mappings = [
     (r"/api/v1/tests", test_handlers.TestsCLHandler),
     (r"/api/v1/tests/([^/]+)", test_handlers.TestsGURHandler),
 
+    (r"/api/v1/cvp/applications/getlogo/([^/]+)",
+     application_handlers.ApplicationsGetLogoHandler),
+    (r"/api/v1/cvp/applications/uploadlogo",
+     application_handlers.ApplicationsLogoHandler),
     (r"/api/v1/cvp/applications", application_handlers.ApplicationsCLHandler),
     (r"/api/v1/cvp/applications/([^/]+)",
      application_handlers.ApplicationsGURHandler),