summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerena Feng <feng.xiaowei@zte.com.cn>2017-11-21 02:13:12 +0000
committerGerrit Code Review <gerrit@opnfv.org>2017-11-21 02:13:12 +0000
commitb8c925baa4f00185d5465e6f85ebce832c0c41f6 (patch)
tree8d96b1e2d47cd6b55433e97fe3c4760f9d2e4398
parent4dced360ffbde66755ec49715db8fd876fa11d09 (diff)
parent141e16fcbdcacc02ff30d861bf76082b51d4c287 (diff)
Merge "Update and Delete functionalities for projects"
-rw-r--r--testapi/3rd_party/static/testapi-ui/Gruntfile.js5
-rw-r--r--testapi/3rd_party/static/testapi-ui/app.js5
-rw-r--r--testapi/3rd_party/static/testapi-ui/index.html1
-rw-r--r--testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html10
-rw-r--r--testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js2
-rw-r--r--testapi/opnfv_testapi/common/check.py11
-rw-r--r--testapi/opnfv_testapi/handlers/base_handlers.py4
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js8
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js434
-rw-r--r--testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js271
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_base.py3
-rw-r--r--testapi/opnfv_testapi/tests/unit/handlers/test_project.py7
-rw-r--r--testapi/opnfv_testapi/ui/projects/project/project.html25
-rw-r--r--testapi/opnfv_testapi/ui/projects/project/projectController.js183
-rw-r--r--testapi/opnfv_testapi/ui/projects/project/updateModal.html26
-rw-r--r--testapi/opnfv_testapi/ui/projects/projects.html40
-rw-r--r--testapi/opnfv_testapi/ui/projects/projectsController.js20
17 files changed, 883 insertions, 172 deletions
diff --git a/testapi/3rd_party/static/testapi-ui/Gruntfile.js b/testapi/3rd_party/static/testapi-ui/Gruntfile.js
index f82269e..13f484f 100644
--- a/testapi/3rd_party/static/testapi-ui/Gruntfile.js
+++ b/testapi/3rd_party/static/testapi-ui/Gruntfile.js
@@ -14,7 +14,9 @@ module.exports = function (grunt) {
base: './',
middleware: function(connect, options, middlewares) {
middlewares.unshift(function(req, res, next) {
- if (req.method.toUpperCase() == 'POST') req.method='GET';
+ if (req.method.toUpperCase() == 'POST' || req.method.toUpperCase() == "PUT"){
+ req.method='GET';
+ }
return next();
});
return middlewares;
@@ -118,6 +120,7 @@ module.exports = function (grunt) {
coverageDir: '../../../opnfv_testapi/tests/UI/coverage',
args: {
specs: ['../../../opnfv_testapi/tests/UI/e2e/podsControllerSpec.js',
+ '../../../opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js',
'../../../opnfv_testapi/tests/UI/e2e/projectControllerSpec.js']
}
},
diff --git a/testapi/3rd_party/static/testapi-ui/app.js b/testapi/3rd_party/static/testapi-ui/app.js
index 0b35162..dbb56a6 100644
--- a/testapi/3rd_party/static/testapi-ui/app.js
+++ b/testapi/3rd_party/static/testapi-ui/app.js
@@ -69,6 +69,11 @@
templateUrl: 'testapi-ui/components/projects/projects.html',
controller: 'ProjectsController as ctrl'
}).
+ state('project', {
+ url: '/projects/:name',
+ templateUrl: 'testapi-ui/components/projects/project/project.html',
+ controller: 'ProjectController as ctrl'
+ }).
state('communityResults', {
url: '/community_results',
templateUrl: 'testapi-ui/components/results/results.html',
diff --git a/testapi/3rd_party/static/testapi-ui/index.html b/testapi/3rd_party/static/testapi-ui/index.html
index 45162dc..ac29aca 100644
--- a/testapi/3rd_party/static/testapi-ui/index.html
+++ b/testapi/3rd_party/static/testapi-ui/index.html
@@ -47,6 +47,7 @@
<script src="testapi-ui/components/auth-failure/authFailureController.js"></script>
<script src="testapi-ui/components/logout/logoutController.js"></script>
<script src="testapi-ui/components/projects/projectsController.js"></script>
+ <script src="testapi-ui/components/projects/project/projectController.js"></script>
<!-- Filters -->
<script src="testapi-ui/shared/filters.js"></script>
diff --git a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html b/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html
index 82478a5..e5397e0 100644
--- a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html
+++ b/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModal.html
@@ -1,11 +1,21 @@
<div class="modal-header"><h3 class="modal-title">Confirm</h3></div>
<div class="modal-body">
+ <div class="confirm" ng-class="{ 'hidden': confirmModal.data.text=='Delete' }">
<div class="form-group">
<label for="confirmText">{{confirmModal.data.text}}:</label>
<textarea type="text" class="form-control"
rows="5" ng-model="confirmModal.inputText" id="confirmText">
</textarea>
</div>
+ </div>
+ <div class="Delete" ng-class="{ 'hidden': confirmModal.data.text!='Delete' }">
+ <div class="form-group">
+ <label for="confirmText"> You are about to delete.</label>
+ <br>
+ Do you want to proceed?
+ </div>
+ </div>
+
</div>
<div class="modal-footer">
<button class="btn btn-primary" ng-click="confirmModal.confirm()">Ok</button>
diff --git a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js b/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js
index 76c74df..aba205e 100644
--- a/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js
+++ b/testapi/3rd_party/static/testapi-ui/shared/alerts/confirmModalFactory.js
@@ -13,7 +13,7 @@
function confirmModal($uibModal) {
return function(text, successHandler) {
$uibModal.open({
- templateUrl: '/shared/alerts/confirmModal.html',
+ templateUrl: '/testapi-ui/shared/alerts/confirmModal.html',
controller: 'CustomConfirmModalController as confirmModal',
size: 'md',
resolve: {
diff --git a/testapi/opnfv_testapi/common/check.py b/testapi/opnfv_testapi/common/check.py
index 432a6c1..1155d24 100644
--- a/testapi/opnfv_testapi/common/check.py
+++ b/testapi/opnfv_testapi/common/check.py
@@ -28,10 +28,17 @@ def is_authorized(method):
user_info = yield dbapi.db_find_one('users', {'user': testapi_id})
if not user_info:
raises.Unauthorized(message.not_lfid())
- kwargs['owner'] = testapi_id
+ if "owner" in kwargs:
+ kwargs['owner'] = testapi_id
if self.table in ['projects']:
query = kwargs.get('query')
- query_data = query()
+ if type(query) is not dict:
+ query_data = query()
+ else:
+ if self.json_args is None:
+ query_data = query
+ else:
+ query_data = self.json_args
group = "opnfv-gerrit-" + query_data['name'] + "-submitters"
if group not in user_info['groups']:
raises.Unauthorized(message.no_permission())
diff --git a/testapi/opnfv_testapi/handlers/base_handlers.py b/testapi/opnfv_testapi/handlers/base_handlers.py
index df7f520..a2fdb19 100644
--- a/testapi/opnfv_testapi/handlers/base_handlers.py
+++ b/testapi/opnfv_testapi/handlers/base_handlers.py
@@ -78,10 +78,10 @@ class GenericApiHandler(web.RequestHandler):
@check.valid_token
@check.no_body
@check.miss_fields
+ @check.new_not_exists
@check.is_authorized
@check.values_check
@check.carriers_exist
- @check.new_not_exists
def _create(self, **kwargs):
"""
:param miss_checks: [miss1, miss2]
@@ -179,6 +179,7 @@ class GenericApiHandler(web.RequestHandler):
@web.asynchronous
@gen.coroutine
@check.not_exist
+ @check.is_authorized
def _delete(self, data, query=None):
yield dbapi.db_delete(self.table, query)
self.finish_request()
@@ -188,6 +189,7 @@ class GenericApiHandler(web.RequestHandler):
@check.no_body
@check.not_exist
@check.updated_one_not_exist
+ @check.is_authorized
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/tests/UI/e2e/podsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js
index 8cf7467..cb1d95d 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/podsControllerSpec.js
@@ -20,6 +20,10 @@ describe('testing the Pods page for anonymous user', function () {
}]);
});
+ afterEach(function(){
+ mock.teardown();
+ });
+
it( 'should navigate to pods link ', function() {
browser.get(baseURL);
var podslink = element(by.linkText('Pods')).click();
@@ -128,6 +132,10 @@ describe('testing the Pods page for authorized user', function () {
]);
});
+ afterEach(function(){
+ mock.teardown();
+ });
+
it('create button is visible for authorized user', function () {
browser.get(baseURL + '/#/pods');
var buttonCreate = element(by.buttonText('Create'));
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js
index 921625d..475e037 100644
--- a/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js
+++ b/testapi/opnfv_testapi/tests/UI/e2e/projectControllerSpec.js
@@ -1,224 +1,354 @@
'use strict';
var mock = require('protractor-http-mock');
-var baseURL = "http://localhost:8000"
+var baseURL = "http://localhost:8000/#/"
describe('testing the Project Link for anonymous user', function () {
-
- it( 'should not show the Project Link for anonymous user', function() {
- mock.teardown();
- browser.get(baseURL);
- var projectslink = element(by.linkText('Projects'));
- expect(projectslink.isPresent()).toBe(true);
+ beforeEach(function(){
+ mock([
+ {
+ request: {
+ path: '/api/v1/projects/testproject',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject"
+ }
+ }
+ }
+ ]);
});
- it( 'navigate anonymous user to project page', function() {
- browser.get(baseURL+'#/projects');
+ afterEach(function(){
+ mock.teardown();
+ });
+
+ it( 'navigate to the project page', function() {
+ browser.get(baseURL+"projects/testproject");
var EC = browser.ExpectedConditions;
- browser.wait(EC.urlContains(baseURL+ '/#/projects'), 10000);
+ browser.wait(EC.urlContains(baseURL+ 'projects/testproject'), 10000);
+ });
+
+ it('show the project details for anonymous user ', function(){
+ var table = $$('.projects-table.ng-scope tr');
+ var projectDetailsLable = ['Name','Description','Creation date']
+ var projectDetails = ['testproject', 'dsfsd','2017-11-15 14:30:31.200259']
+ table.each(function(row,index) {
+ var rowElems = row.$$('td');
+ expect(rowElems.count()).toBe(2);
+ expect(rowElems.get(0).getText()).toMatch(projectDetailsLable[index]);
+ expect(rowElems.get(1).getText()).toMatch(projectDetails[index]);
+ });
});
- it('create button is not visible for anonymous user ', function () {
- browser.get(baseURL+'#/projects');
- var buttonCreate = element(by.buttonText('Create'));
- expect(buttonCreate.isDisplayed()).toBeFalsy();
+ it('should not show the update & delete button', function(){
+ var buttonUpdate = element(by.buttonText('Update Project'));
+ var buttonDelete = element(by.buttonText('Delete Project'));
+ expect(buttonUpdate.isDisplayed()).toBeFalsy();
+ expect(buttonDelete.isDisplayed()).toBeFalsy();
});
});
-describe('testing the Project Link for user who is not in submitter group', function () {
- beforeEach(function(){
- mock([
- {
- request: {
- path: '/api/v1/profile',
+
+describe('testing the Project Link for authorized user(not a submitter)', function () {
+ beforeEach(function(){
+ mock([
+ {
+ request: {
+ path: '/api/v1/projects/testproject',
method: 'GET'
- },
- response: {
- data: {
- "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
- "user": "testUser", "groups": ["opnfv-testapi-users"],
- "email": "testuser@test.com"
- }
+ },
+ response: {
+ data: {
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject"
}
}
- ]);
- });
-
- it( 'should show the Project Link for user', function() {
- browser.get(baseURL);
- var projectslink = element(by.linkText('Projects'));
- expect(projectslink.isPresent()).toBe(true);
- });
-
- it( 'should navigate the user to the Project page', function() {
- browser.get(baseURL);
- var projectslink = element(by.linkText('Projects')).click();
- var EC = browser.ExpectedConditions;
- browser.wait(EC.urlContains(baseURL+ '/#/projects'), 10000);
- });
-
- it('create button is not visible for user', function () {
- browser.get(baseURL+'#/projects');
- var buttonCreate = element(by.buttonText('Create'));
- expect(buttonCreate.isDisplayed()).toBeFalsy();
- });
-})
-
-describe('testing the Project Link for user who is in submitter group', function () {
+ },
+ {
+ request: {
+ path: '/api/v1/profile',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
+ "user": "testUser", "groups": ["opnfv-testapi-users"],
+ "email": "testuser@test.com"
+ }
+ }
+ }
+ ]);
+ });
+
+ afterEach(function(){
+ mock.teardown();
+ });
+
+ it( 'navigate to the project page', function() {
+ browser.get(baseURL+"projects/testproject");
+ var EC = browser.ExpectedConditions;
+ browser.wait(EC.urlContains(baseURL+ 'projects/testproject'), 10000);
+ });
+
+ it('show the project details for user ', function(){
+ var table = $$('.projects-table.ng-scope tr');
+ var projectDetailsLable = ['Name','Description','Creation date']
+ var projectDetails = ['testproject', 'dsfsd','2017-11-15 14:30:31.200259']
+ table.each(function(row,index) {
+ var rowElems = row.$$('td');
+ expect(rowElems.count()).toBe(2);
+ expect(rowElems.get(0).getText()).toMatch(projectDetailsLable[index]);
+ expect(rowElems.get(1).getText()).toMatch(projectDetails[index]);
+ });
+ });
+
+ it('should not show the update & delete button', function(){
+ var buttonUpdate = element(by.buttonText('Update Project'));
+ var buttonDelete = element(by.buttonText('Delete Project'));
+ expect(buttonUpdate.isDisplayed()).toBeFalsy();
+ expect(buttonDelete.isDisplayed()).toBeFalsy();
+ });
+
+});
+
+describe('testing the Project Link for authorized user(a submitter)', function () {
beforeEach(function(){
mock([
{
request: {
- path: '/api/v1/profile',
+ path: '/api/v1/projects/testproject',
method: 'GET'
},
response: {
data: {
- "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
- "user": "testUser", "groups": ["opnfv-testapi-users",
- "opnfv-gerrit-testProject1-submitters",
- "opnfv-gerrit-testProject2-submitters" ],
- "email": "testuser@test.com"
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject"
}
}
},
{
request: {
- path: '/api/v1/projects',
- method: 'POST'
+ path: '/api/v1/projects/testproject1',
+ method: 'GET'
},
response: {
data: {
- href: baseURL+"/api/v1/projects/testProject1"
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject1"
}
}
},
{
request: {
path: '/api/v1/projects',
- method: 'POST',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "projects": [
+ {
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject"
+ }
+ ]
+ }
+ }
+ },
+ {
+ request: {
+ path: '/api/v1/projects/testproject',
+ method: 'DELETE'
+ },
+ response: {
+ status : 200
+ }
+ },
+ {
+ request: {
+ path: '/api/v1/projects/testproject1',
+ method: 'DELETE'
+ },
+ response: {
+ status : 403
+ }
+ },
+ {
+ request: {
+ path: '/api/v1/projects/testproject',
+ method: 'PUT',
data: {
name: 'testProject2',
description : 'demoDescription',
}
},
response: {
- status : 403
+ status : 200,
+ data : {
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject2"
+ }
}
},
{
request: {
- path: '/api/v1/projects',
- method: 'POST',
+ path: '/api/v1/projects/testproject',
+ method: 'PUT',
data: {
- name: 'testProject3',
+ name: 'testProject1',
description : 'demoDescription',
}
},
response: {
- status : 403,
- data : 'You do not have permission to perform this action'
+ status : 403
}
- }
+ },
+ {
+ request: {
+ path: '/api/v1/profile',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
+ "user": "testUser", "groups": ["opnfv-testapi-users",
+ "opnfv-gerrit-testProject-submitters",
+ "opnfv-gerrit-testProject2-submitters" ],
+ "email": "testuser@test.com"
+ }
+ }
+ },
]);
});
- it( 'should show the Project Link for user', function() {
- browser.get(baseURL);
- var projectslink = element(by.linkText('Projects'));
- expect(projectslink.isPresent()).toBe(true);
- });
+ afterEach(function(){
+ mock.teardown();
+ });
- it( 'should navigate the user to the Project page', function() {
- browser.get(baseURL);
- var projectslink = element(by.linkText('Projects')).click();
+ it( 'navigate to the project page', function() {
+ browser.get(baseURL+"projects/testproject");
var EC = browser.ExpectedConditions;
- browser.wait(EC.urlContains(baseURL+ '/#/projects'), 10000);
+ browser.wait(EC.urlContains(baseURL+ 'projects/testproject'), 10000);
});
- it('create button is visible for user', function () {
- browser.get(baseURL+'#/projects');
- var buttonCreate = element(by.buttonText('Create'));
- expect(buttonCreate.isDisplayed()).toBe(true);
+ it('show the project details for user ', function(){
+ var table = $$('.projects-table.ng-scope tr');
+ var projectDetailsLable = ['Name','Description','Creation date']
+ var projectDetails = ['testproject', 'dsfsd','2017-11-15 14:30:31.200259']
+ table.each(function(row,index) {
+ var rowElems = row.$$('td');
+ expect(rowElems.count()).toBe(2);
+ expect(rowElems.get(0).getText()).toMatch(projectDetailsLable[index]);
+ expect(rowElems.get(1).getText()).toMatch(projectDetails[index]);
+ });
});
- it('Show error when user click the create button with a empty name', function () {
- browser.get(baseURL+ '/#/projects');
- var description = element(by.model('ctrl.description'));
- description.sendKeys('DemoDescription');
- var buttonCreate = element(by.buttonText('Create'));
- buttonCreate.click();
- expect(element(by.cssContainingText(".alert","Name is missing."))
- .isDisplayed()).toBe(true);
- });
+ it('should show the update & delete button', function(){
+ var buttonUpdate = element(by.buttonText('Update Project'));
+ var buttonDelete = element(by.buttonText('Delete Project'));
+ expect(buttonUpdate.isDisplayed()).toBe(true);
+ expect(buttonDelete.isDisplayed()).toBe(true);
+ });
- it('Show error when user click the create button with an already existing name', function () {
- browser.get(baseURL+ '/#/projects');
- var name = element(by.model('ctrl.name'));
- var details = element(by.model('ctrl.description'));
- name.sendKeys('testProject2');
- details.sendKeys('demoDescription');
- var buttonCreate = element(by.buttonText('Create'));
- buttonCreate.click();
- expect(element(by.cssContainingText(".alert",
- "Error creating the new Project from server:undefined"))
- .isDisplayed()).toBe(true);
+ it('show the update modal when user clicks the update button', function(){
+ browser.get(baseURL+"projects/testproject");
+ var buttonDelete = element(by.buttonText('Update Project')).click();
+ var EC = protractor.ExpectedConditions;
+ var elm = element(by.css(".modal-body"));
+ browser.wait(EC.textToBePresentInElement(elm, "Update"), 5000);
+ expect(elm.isDisplayed()).toBe(true);
+ var buttonCancel = element(by.buttonText('Cancel')).click();
+ expect(elm.isPresent()).toEqual(false);
});
- it('Show error when user try to create a project which he is not belonged to ', function () {
- browser.get(baseURL+ '/#/projects');
- var name = element(by.model('ctrl.name'));
- var details = element(by.model('ctrl.description'));
- name.sendKeys('testProject3');
- details.sendKeys('demoDescription');
- var buttonCreate = element(by.buttonText('Create'));
- buttonCreate.click();
+ it('send a update request to server and show success when we click ok', function(){
+ browser.get(baseURL+"projects/testproject");
+ var buttonUpdate = element(by.buttonText('Update Project')).click();
+ var EC = protractor.ExpectedConditions;
+ var elm = element(by.css(".modal-body"));
+ browser.wait(EC.textToBePresentInElement(elm, "Update"), 5000);
+ expect(elm.isDisplayed()).toBe(true);
+ var name = element(by.model('updateModal.name'));
+ var description = element(by.model('updateModal.description'));
+ name.click().clear().sendKeys('testProject2');
+ description.click().clear().sendKeys('demoDescription');
+ var buttonOk = element(by.buttonText('Ok')).click();
+ expect(element(by.cssContainingText(".alert.alert-success",
+ "Update Success"))
+ .isDisplayed()).toBe(true);
+ });
+
+ it('show error when server send a error response when we click ok', function(){
+ browser.get(baseURL+"projects/testproject");
+ var buttonUpdate = element(by.buttonText('Update Project')).click();
+ var EC = protractor.ExpectedConditions;
+ var elm = element(by.css(".modal-body"));
+ browser.wait(EC.textToBePresentInElement(elm, "Update"), 5000);
+ expect(elm.isDisplayed()).toBe(true);
+ var name = element(by.model('updateModal.name'));
+ var description = element(by.model('updateModal.description'));
+ name.click().clear().sendKeys('testProject1');
+ description.click().clear().sendKeys('demoDescription');
+ var buttonOk = element(by.buttonText('Ok')).click();
expect(element(by.cssContainingText(".alert",
- 'Error creating the new Project from server:"You do not have permission to perform this action"')).isDisplayed())
- .toBe(true);
+ "Error updating the existing Project from server: undefined"))
+ .isDisplayed()).toBe(true);
});
- it('Do not show error if input is acceptable', function () {
- var name = element(by.model('ctrl.name'));
- var details = element(by.model('ctrl.description'));
- name.sendKeys('testProject1');
- details.sendKeys('demoDescription');
- var buttonCreate = element(by.buttonText('Create'));
- buttonCreate.click().then(function(){
- expect(element(by.cssContainingText(".alert",
- "Create Success"))
- .isDisplayed()).toBe(true);
- });
+ it('show the confirm modal when user clicks the delete button', function(){
+ var buttonDelete = element(by.buttonText('Delete Project')).click();
+ var EC = protractor.ExpectedConditions;
+ var elm = element(by.css(".modal-body"));
+ browser.wait(EC.textToBePresentInElement(elm, "You are about to delete."), 5000);
+ expect(elm.isDisplayed()).toBe(true);
+ var buttonCancel = element(by.buttonText('Cancel')).click();
+ expect(elm.isPresent()).toEqual(false);
});
- it('If backend is not responding then show error when user click the create button',function(){
- mock.teardown();
- mock([
- {
- request: {
- path: '/api/v1/profile',
- method: 'GET'
- },
- response: {
- data: {
- "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
- "user": "testUser", "groups": ["opnfv-testapi-users",
- "opnfv-gerrit-testProject1-submitters",
- "opnfv-gerrit-testProject2-submitters" ],
- "email": "testuser@test.com"
- }
- }
- }
- ]);
- browser.get(baseURL+ '/#/projects');
- var name = element(by.model('ctrl.name'));
- var details = element(by.model('ctrl.description'));
- name.sendKeys('testProject1');
- details.sendKeys('demoDescription');
- var buttonCreate = element(by.buttonText('Create'));
- buttonCreate.click().then(function(){
- expect(element(by.css(".alert.alert-danger.ng-binding.ng-scope")).isDisplayed()).toBe(true);
- });
- });
-})
+ it('send a delete request to server when we click ok', function(){
+ var buttonDelete = element(by.buttonText('Delete Project')).click();
+ var EC = protractor.ExpectedConditions;
+ var elm = element(by.css(".modal-body"));
+ browser.wait(EC.textToBePresentInElement(elm, "You are about to delete."), 5000);
+ expect(elm.isDisplayed()).toBe(true);
+ var buttonCancel = element(by.buttonText('Ok')).click();
+ browser.wait(EC.urlContains(baseURL+ 'projects'), 10000);
+ });
+
+ it('show the error message when we click ok', function(){
+ browser.get(baseURL+"projects/testproject1");
+ var buttonDelete = element(by.buttonText('Delete Project')).click();
+ var EC = protractor.ExpectedConditions;
+ var elm = element(by.css(".modal-body"));
+ browser.wait(EC.textToBePresentInElement(elm, "You are about to delete."), 5000);
+ expect(elm.isDisplayed()).toBe(true);
+ var buttonCancel = element(by.buttonText('Ok')).click();
+ // browser.wait(EC.urlContains(baseURL+ 'projects'), 10000);
+ expect(element(by.cssContainingText(".alert",
+ "Error deleting project from server: undefined"))
+ .isDisplayed()).toBe(true);
+ // browser.pause();
+ });
+
+}); \ No newline at end of file
diff --git a/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js
new file mode 100644
index 0000000..64a5aeb
--- /dev/null
+++ b/testapi/opnfv_testapi/tests/UI/e2e/projectsControllerSpec.js
@@ -0,0 +1,271 @@
+'use strict';
+
+var mock = require('protractor-http-mock');
+var baseURL = "http://localhost:8000"
+
+describe('testing the Projects Link for anonymous user', function () {
+ beforeEach(function(){
+ mock([
+ {
+ request: {
+ path: '/api/v1/projects',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "projects": [
+ {
+ "owner": "thuva4",
+ "_id": "5a0c022f9a07c846d3c2cc94",
+ "creation_date": "2017-11-15 14:30:31.200259",
+ "description": "dsfsd",
+ "name": "testproject"
+ }
+ ]
+ }
+ }
+ }
+ ]);
+ });
+
+ afterEach(function(){
+ mock.teardown();
+ });
+
+ it( 'should show the Projects Link for anonymous user', function() {
+ mock.teardown();
+ browser.get(baseURL);
+ var projectslink = element(by.linkText('Projects'));
+ expect(projectslink.isPresent()).toBe(true);
+ });
+
+ it( 'navigate anonymous user to project page', function() {
+ browser.get(baseURL+'#/projects');
+ var EC = browser.ExpectedConditions;
+ browser.wait(EC.urlContains(baseURL+ '/#/projects'), 10000);
+ });
+
+ it('create button is not visible for anonymous user ', function () {
+ browser.get(baseURL+'#/projects');
+ var buttonCreate = element(by.buttonText('Create'));
+ expect(buttonCreate.isDisplayed()).toBeFalsy();
+ });
+
+ it('Show projects list when user comes to the projects page', function () {
+ var firstBookName = element(by.repeater('(index, project) in ctrl.data.projects').
+ row(0).column('{{project.name}}'));
+ expect(firstBookName).toBeDefined();
+ });
+
+ it('redirect to project page when user clicks a project',function(){
+ var projectlink = element(by.linkText('testproject')).click();
+ var EC = browser.ExpectedConditions;
+ browser.wait(EC.urlContains(baseURL+ '/#/projects/testproject'), 10000);
+ });
+
+});
+
+describe('testing the Project Link for user who is not in submitter group', function () {
+ beforeEach(function(){
+ mock([
+ {
+ request: {
+ path: '/api/v1/profile',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
+ "user": "testUser", "groups": ["opnfv-testapi-users"],
+ "email": "testuser@test.com"
+ }
+ }
+ }
+ ]);
+ });
+
+ afterEach(function(){
+ mock.teardown();
+ });
+
+ it( 'should show the Project Link for user', function() {
+ browser.get(baseURL);
+ var projectslink = element(by.linkText('Projects'));
+ expect(projectslink.isPresent()).toBe(true);
+ });
+
+ it( 'should navigate the user to the Project page', function() {
+ browser.get(baseURL);
+ var projectslink = element(by.linkText('Projects')).click();
+ var EC = browser.ExpectedConditions;
+ browser.wait(EC.urlContains(baseURL+ '/#/projects'), 10000);
+ });
+
+ it('create button is not visible for user', function () {
+ browser.get(baseURL+'#/projects');
+ var buttonCreate = element(by.buttonText('Create'));
+ expect(buttonCreate.isDisplayed()).toBeFalsy();
+ });
+})
+
+describe('testing the Project Link for user who is in submitter group', function () {
+ beforeEach(function(){
+ mock([
+ {
+ request: {
+ path: '/api/v1/profile',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
+ "user": "testUser", "groups": ["opnfv-testapi-users",
+ "opnfv-gerrit-testProject1-submitters",
+ "opnfv-gerrit-testProject2-submitters" ],
+ "email": "testuser@test.com"
+ }
+ }
+ },
+ {
+ request: {
+ path: '/api/v1/projects',
+ method: 'POST'
+ },
+ response: {
+ data: {
+ href: baseURL+"/api/v1/projects/testProject1"
+ }
+ }
+ },
+ {
+ request: {
+ path: '/api/v1/projects',
+ method: 'POST',
+ data: {
+ name: 'testProject2',
+ description : 'demoDescription',
+ }
+ },
+ response: {
+ status : 403
+ }
+ },
+ {
+ request: {
+ path: '/api/v1/projects',
+ method: 'POST',
+ data: {
+ name: 'testProject3',
+ description : 'demoDescription',
+ }
+ },
+ response: {
+ status : 403,
+ data : 'You do not have permission to perform this action'
+ }
+ }
+ ]);
+ });
+
+ afterEach(function(){
+ mock.teardown();
+ });
+
+ it( 'should show the Project Link for user', function() {
+ browser.get(baseURL);
+ var projectslink = element(by.linkText('Projects'));
+ expect(projectslink.isPresent()).toBe(true);
+ });
+
+ it( 'should navigate the user to the Project page', function() {
+ browser.get(baseURL);
+ var projectslink = element(by.linkText('Projects')).click();
+ var EC = browser.ExpectedConditions;
+ browser.wait(EC.urlContains(baseURL+ '/#/projects'), 10000);
+ });
+
+ it('create button is visible for user', function () {
+ browser.get(baseURL+'#/projects');
+ var buttonCreate = element(by.buttonText('Create'));
+ expect(buttonCreate.isDisplayed()).toBe(true);
+ });
+
+ it('Show error when user click the create button with a empty name', function () {
+ browser.get(baseURL+ '/#/projects');
+ var description = element(by.model('ctrl.description'));
+ description.sendKeys('DemoDescription');
+ var buttonCreate = element(by.buttonText('Create'));
+ buttonCreate.click();
+ expect(element(by.cssContainingText(".alert","Name is missing."))
+ .isDisplayed()).toBe(true);
+ });
+
+ it('Show error when user click the create button with an already existing name', function () {
+ browser.get(baseURL+ '/#/projects');
+ var name = element(by.model('ctrl.name'));
+ var details = element(by.model('ctrl.description'));
+ name.sendKeys('testProject2');
+ details.sendKeys('demoDescription');
+ var buttonCreate = element(by.buttonText('Create'));
+ buttonCreate.click();
+ expect(element(by.cssContainingText(".alert",
+ "Error creating the new Project from server:undefined"))
+ .isDisplayed()).toBe(true);
+ });
+
+ it('Show error when user try to create a project which he is not belonged to ', function () {
+ browser.get(baseURL+ '/#/projects');
+ var name = element(by.model('ctrl.name'));
+ var details = element(by.model('ctrl.description'));
+ name.sendKeys('testProject3');
+ details.sendKeys('demoDescription');
+ var buttonCreate = element(by.buttonText('Create'));
+ buttonCreate.click();
+ expect(element(by.cssContainingText(".alert",
+ 'Error creating the new Project from server:"You do not have permission to perform this action"')).isDisplayed())
+ .toBe(true);
+ });
+
+ it('Do not show error if input is acceptable', function () {
+ var name = element(by.model('ctrl.name'));
+ var details = element(by.model('ctrl.description'));
+ name.sendKeys('testProject1');
+ details.sendKeys('demoDescription');
+ var buttonCreate = element(by.buttonText('Create'));
+ buttonCreate.click().then(function(){
+ expect(element(by.cssContainingText(".alert",
+ "Create Success"))
+ .isDisplayed()).toBe(true);
+ });
+ });
+
+ it('If backend is not responding then show error when user click the create button',function(){
+ mock.teardown();
+ mock([
+ {
+ request: {
+ path: '/api/v1/profile',
+ method: 'GET'
+ },
+ response: {
+ data: {
+ "fullname": "Test User", "_id": "79f82eey9a00c84bfhc7aed",
+ "user": "testUser", "groups": ["opnfv-testapi-users",
+ "opnfv-gerrit-testProject1-submitters",
+ "opnfv-gerrit-testProject2-submitters" ],
+ "email": "testuser@test.com"
+ }
+ }
+ }
+ ]);
+ browser.get(baseURL+ '/#/projects');
+ var name = element(by.model('ctrl.name'));
+ var details = element(by.model('ctrl.description'));
+ name.sendKeys('testProject1');
+ details.sendKeys('demoDescription');
+ var buttonCreate = element(by.buttonText('Create'));
+ buttonCreate.click().then(function(){
+ expect(element(by.css(".alert.alert-danger")).isDisplayed()).toBe(true);
+ });
+ });
+})
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_base.py b/testapi/opnfv_testapi/tests/unit/handlers/test_base.py
index eb147cc..4e5c0d9 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_base.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_base.py
@@ -61,7 +61,8 @@ class TestBase(testing.AsyncHTTPTestCase):
'opnfv-testapi-users',
'opnfv-gerrit-functest-submitters',
'opnfv-gerrit-qtip-submitters',
- 'opnfv-gerrit-qtip-contributors']
+ 'opnfv-gerrit-qtip-contributors',
+ 'opnfv-gerrit-apex-submitters']
})
def tearDown(self):
diff --git a/testapi/opnfv_testapi/tests/unit/handlers/test_project.py b/testapi/opnfv_testapi/tests/unit/handlers/test_project.py
index 2873ab0..9bc0e86 100644
--- a/testapi/opnfv_testapi/tests/unit/handlers/test_project.py
+++ b/testapi/opnfv_testapi/tests/unit/handlers/test_project.py
@@ -110,21 +110,25 @@ class TestProjectUpdate(TestProjectBase):
def test_withoutBody(self):
return None, 'noBody'
+ @executor.mock_valid_lfid()
@executor.update(httplib.NOT_FOUND, message.not_found_base)
def test_notFound(self):
return self.req_e, 'notFound'
+ @executor.mock_valid_lfid()
@executor.update(httplib.FORBIDDEN, message.exist_base)
def test_newNameExist(self):
return self.req_e, self.req_d.name
+ @executor.mock_valid_lfid()
@executor.update(httplib.FORBIDDEN, message.no_update())
def test_noUpdate(self):
return self.req_d, self.req_d.name
+ @executor.mock_valid_lfid()
@executor.update(httplib.OK, '_assert_update')
def test_success(self):
- req = project_models.ProjectUpdateRequest('newName', 'new description')
+ req = project_models.ProjectUpdateRequest('apex', 'apex test')
return req, self.req_d.name
def _assert_update(self, req, body):
@@ -145,6 +149,7 @@ class TestProjectDelete(TestProjectBase):
def test_notFound(self):
return 'notFound'
+ @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/ui/projects/project/project.html b/testapi/opnfv_testapi/ui/projects/project/project.html
new file mode 100644
index 0000000..9d46364
--- /dev/null
+++ b/testapi/opnfv_testapi/ui/projects/project/project.html
@@ -0,0 +1,25 @@
+<div ng-show="ctrl.data" class="projects-table" style="margin-top:24px; margin-left:8px;">
+ <table class="table">
+ <tbody>
+ <tr> <td class="col-md-3">Name</td> <td class="col-md-9">{{ctrl.data.name}}</td> </tr>
+ <tr> <td>Description</td> <td>{{ctrl.data.description}}</td> </tr>
+ <tr> <td>Creation date</td> <td>{{ctrl.data.creation_date}}</td> </tr>
+ </tbody>
+ </table>
+</div>
+
+<div class="row" style="margin-bottom:24px;"></div>
+<div class="project-create col-md-3" style="margin-top:10px" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) &&
+ auth.isAuthenticated) }">
+ <button type="submit" class="btn btn-primary" ng-click="ctrl.openDeleteModal()">Delete Project</button>
+ <button type="submit" class="btn btn-primary" ng-click="ctrl.openUpdateModal()">Update Project</button>
+</div>
+<div ng-show="ctrl.showError" class="alert alert-danger col-md-9" role="alert">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
+ <span class="sr-only">Error:</span>
+ {{ctrl.error}}
+</div>
+<div ng-show="ctrl.showSuccess" class="alert alert-success col-md-9" role="alert">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ Update Success
+</div> \ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/projects/project/projectController.js b/testapi/opnfv_testapi/ui/projects/project/projectController.js
new file mode 100644
index 0000000..8f4bd20
--- /dev/null
+++ b/testapi/opnfv_testapi/ui/projects/project/projectController.js
@@ -0,0 +1,183 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+(function () {
+ 'use strict';
+
+ angular
+ .module('testapiApp')
+ .controller('ProjectController', ProjectController);
+
+ ProjectController.$inject = [
+ '$scope', '$http', '$filter', '$state', '$window', '$uibModal', 'testapiApiUrl','raiseAlert',
+ 'confirmModal'
+ ];
+
+ /**
+ * TestAPI Project Controller
+ * This controller is for the '/projects' page where a user can browse
+ * through projects declared in TestAPI.
+ */
+ function ProjectController($scope, $http, $filter, $state, $window, $uibModal, testapiApiUrl,
+ raiseAlert, confirmModal) {
+ var ctrl = this;
+ ctrl.name = $state.params['name'];
+ ctrl.url = testapiApiUrl + '/projects/' + ctrl.name;
+
+ ctrl.loadDetails = loadDetails;
+ ctrl.deleteProject = deleteProject;
+ ctrl.openDeleteModal = openDeleteModal;
+ ctrl.openUpdateModal = openUpdateModal;
+ ctrl.updateProject = updateProject;
+
+
+ /**
+ * This will contact the TestAPI to update an existing project.
+ */
+ function updateProject(name,description) {
+ ctrl.showError = false;
+ ctrl.showSuccess = false;
+ if(ctrl.name != ""){
+ var projects_url = ctrl.url;
+ var body = {
+ name: name,
+ description: description
+ };
+ ctrl.projectsRequest =
+ $http.put(projects_url, body).success(function (data){
+ ctrl.showSuccess = true ;
+ })
+ .error(function (data) {
+ ctrl.showError = true;
+ ctrl.error = 'Error updating the existing Project from server: ' + angular.toJson(data);
+ });
+ ctrl.name = "";
+ ctrl.description="";
+ }
+ else{
+ ctrl.showError = true;
+ ctrl.error = 'Name is missing.'
+ }
+ }
+
+ /**
+ * This will contact the TestAPI to delete an existing project.
+ */
+ function deleteProject() {
+ ctrl.showError = false;
+ ctrl.showSuccess = false;
+ ctrl.projectsRequest =
+ $http.delete(ctrl.url).success(function (data) {
+ $state.go('projects', {}, {reload: true});
+ ctrl.showSuccess = true ;
+
+ }).error(function (error) {
+ ctrl.showError = true;
+ ctrl.error =
+ 'Error deleting project from server: ' +
+ angular.toJson(error);
+ });
+ }
+
+ /**
+ * This will open the modal that will show the delete confirm
+ * message
+ */
+ function openDeleteModal() {
+ confirmModal("Delete",ctrl.deleteProject);
+ }
+
+ /**
+ * This will open the modal that will show the update
+ * view
+ */
+ function openUpdateModal(){
+ $uibModal.open({
+ templateUrl: 'testapi-ui/components/projects/project/updateModal.html',
+ controller: 'ModalInstanceCtrl as updateModal',
+ size: 'md',
+ resolve: {
+ data: function () {
+ return {
+ text: "Update",
+ successHandler: ctrl.updateProject,
+ project: ctrl.data
+ };
+ }
+ }
+ });
+ }
+
+ /**
+ * This will contact the TestAPI to get a listing of declared projects.
+ */
+ function loadDetails() {
+ ctrl.showError = false;
+ ctrl.projectsRequest =
+ $http.get(ctrl.url).success(function (data) {
+ ctrl.data = data;
+ }).error(function (error) {
+ ctrl.data = null;
+ ctrl.showError = true;
+ ctrl.error =
+ 'Error retrieving projects from server: ' +
+ angular.toJson(error);
+ });
+ }
+ ctrl.loadDetails();
+ }
+
+
+ /**
+ * TestAPI Modal instance Controller
+ * This controller is for the update modal where a user can update
+ * the project information.
+ */
+ angular.module('testapiApp').controller('ModalInstanceCtrl', ModalInstanceCtrl);
+ ModalInstanceCtrl.$inject = ['$scope', '$uibModalInstance', 'data'];
+ function ModalInstanceCtrl($scope, $uibModalInstance, data) {
+ var ctrl = this;
+ ctrl.confirm = confirm;
+ ctrl.cancel = cancel;
+ ctrl.data = angular.copy(data);
+
+ ctrl.createRequirements = [
+ {label: 'name', type: 'text', required: true},
+ {label: 'description', type: 'textarea', required: false}
+ ];
+
+ ctrl.name = ctrl.data.project.name;
+ ctrl.description = ctrl.data.project.description;
+
+ /**
+ * Initiate confirmation and call the success handler with the
+ * inputs.
+ */
+ function confirm() {
+ $uibModalInstance.close();
+ if (angular.isDefined(ctrl.data.successHandler)) {
+ ctrl.data.successHandler(ctrl.name,ctrl.description);
+ }
+ }
+
+ /**
+ * Close the confirm modal without initiating changes.
+ */
+ function cancel() {
+ $uibModalInstance.dismiss('cancel');
+ }
+ }
+
+
+})();
diff --git a/testapi/opnfv_testapi/ui/projects/project/updateModal.html b/testapi/opnfv_testapi/ui/projects/project/updateModal.html
new file mode 100644
index 0000000..ab8d64e
--- /dev/null
+++ b/testapi/opnfv_testapi/ui/projects/project/updateModal.html
@@ -0,0 +1,26 @@
+<div class="modal-header"><h3 class="modal-title">Confirm</h3></div>
+<div class="modal-body">
+ <div class="form-group">
+ <h4>Update</h4>
+ <div class="row">
+ <div ng-repeat="require in updateModal.createRequirements">
+ <div class="update-project" style="margin-left:24px;">
+ <p class="input-group">
+ <label for="cpid">{{require.label|capitalize}}: </label>
+ <a ng-if="require.type == 'text'">
+ <input type="text" dynamic-model="'updateModal.' + require.label"/>
+ </a>
+ <a ng-if="require.type == 'textarea'">
+ <textarea rows="2" cols="50" value={{require.vaule}} dynamic-model="'updateModal.' + require.label">
+ </textarea>
+ </a>
+ </p>
+ </div>
+ </div>
+ </div>
+ </div>
+</div>
+<div class="modal-footer">
+ <button class="btn btn-primary" ng-click="updateModal.confirm()">Ok</button>
+ <button class="btn btn-default" ng-click="updateModal.cancel()">Cancel</button>
+</div>
diff --git a/testapi/opnfv_testapi/ui/projects/projects.html b/testapi/opnfv_testapi/ui/projects/projects.html
index 62a968b..55f8683 100644
--- a/testapi/opnfv_testapi/ui/projects/projects.html
+++ b/testapi/opnfv_testapi/ui/projects/projects.html
@@ -1,8 +1,8 @@
<h3>Projects</h3>
-<p> </p>
<div class="row" style="margin-bottom:24px;"></div>
-<div class="project-create" ng-class="{ 'hidden': ! (auth.projectNames.length>0) }">
+<div class="project-create" ng-class="{ 'hidden': ! ((auth.projectNames.length>0) &&
+ auth.isAuthenticated) }">
<h4>Create</h4>
<div class="row">
<div ng-repeat="require in ctrl.createRequirements">
@@ -19,20 +19,34 @@
</p>
</div>
</div>
-
- <div class="col-md-3" style="margin-top:12px; margin-left:8px;">
- <button type="submit" class="btn btn-primary" ng-click="ctrl.create()">Create</button>
+ <div class="col-md-1 col-sm-1 col-xs-1 " style="margin-top:15px;">
+ <button type="submit" class="btn btn-primary" ng-click="ctrl.create()">Create</button>
+ </div>
+ <div class="col-md-11 col-sm-11 col-xs-11">
+ <div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
+ <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
+ <span class="sr-only">Error:</span>
+ {{ctrl.error}}
+ </div>
+ <div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert">
+ <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
+ Create Success
+ </div>
</div>
</div>
</div>
-<div ng-show="ctrl.showError" class="alert alert-danger" role="alert">
- <span class="glyphicon glyphicon-exclamation-sign" aria-hidden="true"></span>
- <span class="sr-only">Error:</span>
- {{ctrl.error}}
-</div>
-<div ng-show="ctrl.showSuccess" class="alert alert-success" role="alert">
- <span class="glyphicon glyphicon-ok" aria-hidden="true"></span>
- Create Success
+<div ng-show="ctrl.data" class="projects-table" style="margin-top:24px; margin-left:8px;">
+ <table ng-data="ctrl.data.projects" ng-show="ctrl.data" class="table table-striped table-hover">
+ <tbody>
+ <tr ng-repeat-start="(index, project) in ctrl.data.projects">
+ <td>
+ <a ui-sref='project({name: project.name})'>{{project.name}}</a>
+ </td>
+ </tr>
+ <tr ng-repeat-end=>
+ </tr>
+ </tbody>
+ </table>
</div> \ No newline at end of file
diff --git a/testapi/opnfv_testapi/ui/projects/projectsController.js b/testapi/opnfv_testapi/ui/projects/projectsController.js
index d2640b6..16002f6 100644
--- a/testapi/opnfv_testapi/ui/projects/projectsController.js
+++ b/testapi/opnfv_testapi/ui/projects/projectsController.js
@@ -33,6 +33,7 @@
var ctrl = this;
ctrl.url = testapiApiUrl + '/projects';
ctrl.create = create;
+ ctrl.update = update;
ctrl.createRequirements = [
{label: 'name', type: 'text', required: true},
@@ -57,6 +58,7 @@
ctrl.projectsRequest =
$http.post(projects_url, body).success(function (data){
ctrl.showSuccess = true ;
+ ctrl.update();
})
.error(function (data) {
ctrl.showError = true;
@@ -70,5 +72,23 @@
ctrl.error = 'Name is missing.'
}
}
+
+ /**
+ * This will contact the TestAPI to get a listing of declared projects.
+ */
+ function update() {
+ ctrl.showError = false;
+ ctrl.projectsRequest =
+ $http.get(ctrl.url).success(function (data) {
+ ctrl.data = data;
+ }).error(function (error) {
+ ctrl.data = null;
+ ctrl.showError = true;
+ ctrl.error =
+ 'Error retrieving projects from server: ' +
+ angular.toJson(error);
+ });
+ }
+ ctrl.update();
}
})();