summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorthuva4 <tharma.thuva@gmail.com>2017-11-16 14:51:29 +0530
committerthuva4 <tharma.thuva@gmail.com>2017-11-16 16:31:55 +0530
commit141e16fcbdcacc02ff30d861bf76082b51d4c287 (patch)
treeaf8f398f254d9e1ba27b392b9e36957a75af77b9
parent265e10a036b545d9d4e15bebef17e38e4b013af3 (diff)
Update and Delete functionalities for projects
Implemented the update and delete functions for the projects and wrote the e2e tests for the both functions. Change-Id: I917dd9503f145b0dde61dd9970bd855f9711335e Signed-off-by: thuva4 <tharma.thuva@gmail.com>
-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();
}
})();