From 1e5a1f8df1b46d9db6cc13e469cca6c8247b1980 Mon Sep 17 00:00:00 2001 From: Gustavo Alves Date: Fri, 14 Apr 2017 18:13:05 -0300 Subject: [PATCH 01/25] Test environment variables --- circle.yml | 1 - e2e/dashboard.spec.js | 16 ++++++++++++---- e2e/login.spec.js | 22 +++++++++++++++------- 3 files changed, 27 insertions(+), 12 deletions(-) diff --git a/circle.yml b/circle.yml index 93fc2e9..131afaf 100644 --- a/circle.yml +++ b/circle.yml @@ -5,7 +5,6 @@ machine: # Add some environment variables environment: - CIRCLE_ENV: dev ## Customize dependencies dependencies: diff --git a/e2e/dashboard.spec.js b/e2e/dashboard.spec.js index 112452a..b6af000 100644 --- a/e2e/dashboard.spec.js +++ b/e2e/dashboard.spec.js @@ -3,17 +3,25 @@ describe('The dashboard view', function () { var page; var mainPage; + var testUser = process.env.TEST_USER; + var testPassword = process.env.TEST_PASSWORD; + var testPort = process.env.TEST_PORT || 3000; beforeEach(function () { - browser.get('http://localhost:3000/'); + browser.get('http://localhost:' + testPort + '/'); page = require('./login.po'); mainPage = require('./main.po'); - page.usernameInput.sendKeys('amy_admin'); - page.passwordInput.sendKeys('topcoder1'); - page.loginButton.click(); + }); + + it('should have environment variables defined', function(){ + expect(testUser).toBeDefined(); + expect(testPassword).toBeDefined(); }); it('should find members', function() { + page.usernameInput.sendKeys(testUser); + page.passwordInput.sendKeys(testPassword); + page.loginButton.click(); mainPage.searchHandleInput.sendKeys('sah2ed'); mainPage.searchButton.click(); expect(mainPage.users.count()).toBe(1); diff --git a/e2e/login.spec.js b/e2e/login.spec.js index 2e46633..ec57407 100644 --- a/e2e/login.spec.js +++ b/e2e/login.spec.js @@ -3,13 +3,21 @@ describe('The login view', function () { var page; var mainPage; + var testUser = process.env.TEST_USER; + var testPassword = process.env.TEST_PASSWORD; + var testPort = process.env.TEST_PORT || 3000; beforeEach(function () { - browser.get('http://localhost:3000/'); + browser.get('http://localhost:' + testPort + '/'); page = require('./login.po'); mainPage = require('./main.po'); }); + it('should have environment variables defined', function(){ + expect(testUser).toBeDefined(); + expect(testPassword).toBeDefined(); + }); + it('should display the correct form heading', function() { expect(page.loginHeader.getText()).toBe('ADMIN APP LOGIN'); //expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); @@ -27,20 +35,20 @@ describe('The login view', function () { it('login should succeed for correct credentials', function () { //expect(page.thumbnailEls.count()).toBeGreaterThan(5); - page.usernameInput.sendKeys('amy_admin'); - page.passwordInput.sendKeys('topcoder1'); + page.usernameInput.sendKeys(testUser); + page.passwordInput.sendKeys(testPassword); page.loginButton.click(); expect(mainPage.isUserLoggedIn.isDisplayed()).toBeTruthy(); - expect(mainPage.loggedInUser.getText()).toBe('amy_admin'); + expect(mainPage.loggedInUser.getText()).toBe(testUser); }); it('logout should work after login', function () { //expect(page.thumbnailEls.count()).toBeGreaterThan(5); - page.usernameInput.sendKeys('amy_admin'); - page.passwordInput.sendKeys('topcoder1'); + page.usernameInput.sendKeys(testUser); + page.passwordInput.sendKeys(testPassword); page.loginButton.click(); expect(mainPage.isUserLoggedIn.isDisplayed()).toBeTruthy(); - expect(mainPage.loggedInUser.getText()).toBe('amy_admin'); + expect(mainPage.loggedInUser.getText()).toBe(testUser); mainPage.logout.click(); expect(page.loginHeader.getText()).toBe('ADMIN APP LOGIN'); }); From 62207d4c37f8baa549f7218da55387b417f44994 Mon Sep 17 00:00:00 2001 From: Gustavo Alves Date: Fri, 14 Apr 2017 20:11:00 -0300 Subject: [PATCH 02/25] Updated README --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index cea1c58..6dd8a2f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![CircleCI](https://circleci.com/gh/GSTVAC/admin-app.svg?style=svg)](https://circleci.com/gh/GSTVAC/admin-app) + # support-admin-app Support application @@ -37,6 +39,15 @@ The following configuration parameters are available: | AUTH0_TOKEN_NAME | Auth0 token name | | AUTH0_REFRESH_TOKEN_NAME | Auth0 refresh token name | +Environment variables: + +| Name | Description | +| --- | --- | +| BUILD_ENV | Build environment. Default is `dev` | +| TEST_USER | App user to use on tests | +| TEST_PASSWORD | App password to use on tests | +| TEST_PORT | Local port used to run the tests. Default is 3000 | + ## Start the Application Simply execute the following command to start the app in development mode (with browsersync) From 9eb2d1e72233b34b27e55be2de8ee0bc4c58d14f Mon Sep 17 00:00:00 2001 From: Gustavo Alves Date: Sun, 16 Apr 2017 12:49:45 -0300 Subject: [PATCH 03/25] README updates --- README.md | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 6dd8a2f..ab65426 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -[![CircleCI](https://circleci.com/gh/GSTVAC/admin-app.svg?style=svg)](https://circleci.com/gh/GSTVAC/admin-app) - +[![CircleCI](https://circleci.com/gh/topcoder-platform/admin-app.svg?style=svg)](https://circleci.com/gh/topcoder-platform/admin-app) # support-admin-app Support application @@ -39,15 +38,6 @@ The following configuration parameters are available: | AUTH0_TOKEN_NAME | Auth0 token name | | AUTH0_REFRESH_TOKEN_NAME | Auth0 refresh token name | -Environment variables: - -| Name | Description | -| --- | --- | -| BUILD_ENV | Build environment. Default is `dev` | -| TEST_USER | App user to use on tests | -| TEST_PASSWORD | App password to use on tests | -| TEST_PORT | Local port used to run the tests. Default is 3000 | - ## Start the Application Simply execute the following command to start the app in development mode (with browsersync) @@ -64,6 +54,15 @@ npm run build ## Execute E2E Tests +Before executing the end-to-end (e2e) protractor tests, these environment variables should be set: + +| Name | Description | Default Value | +| --- | --- | --- | +| BUILD_ENV | Deployment configuration to be tested by e2e tests. | See [Configuration](#configuration) for possible values. Defaults to `dev`. | +| TEST_USER | Account username to use for e2e tests. | No default. Must be set. | +| TEST_PASSWORD | Account password to use for e2e tests. | No default. Must be set. | +| TEST_PORT | Port from which to serve the app for e2e tests. | Defaults to `3000`. | + ```npm test``` ## Fallback instruction in case the npm scripts fail From e2a029dd57885cd7d1ef47eeeaa3f8affa0659f4 Mon Sep 17 00:00:00 2001 From: Gustavo Alves Date: Sun, 16 Apr 2017 15:52:41 -0300 Subject: [PATCH 04/25] throwing a warning if environment variables are not set when running e2e tests --- protractor.conf.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/protractor.conf.js b/protractor.conf.js index b2c93a1..0396ecf 100755 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -11,6 +11,13 @@ exports.config = { 'browserName': 'chrome' }, + onPrepare: function() { + // check if env variables for testing are set + if (typeof process.env.TEST_USER === "undefined" || typeof process.env.TEST_PASSWORD === "undefined") { + console.warn("The environment variables TEST_USER and TEST_PASSWORD should be set in order for the tests to work"); + } + }, + // Spec patterns are relative to the current working directly when // protractor is called. specs: [paths.e2e + '/**/*.js'], From bd496bccdeccf67bd111a87f2fc091dd3b61e9e2 Mon Sep 17 00:00:00 2001 From: Gustavo Alves Date: Sun, 16 Apr 2017 16:14:59 -0300 Subject: [PATCH 05/25] throwing an exception if environment variables are not set when running e2e tests --- protractor.conf.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/protractor.conf.js b/protractor.conf.js index 0396ecf..3af9dbd 100755 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -14,7 +14,7 @@ exports.config = { onPrepare: function() { // check if env variables for testing are set if (typeof process.env.TEST_USER === "undefined" || typeof process.env.TEST_PASSWORD === "undefined") { - console.warn("The environment variables TEST_USER and TEST_PASSWORD should be set in order for the tests to work"); + throw "The environment variables TEST_USER and TEST_PASSWORD should be set in order for the tests to work"; } }, From dee96e48ce6467871e1e2ef7e8d3dbb568e87474 Mon Sep 17 00:00:00 2001 From: Qun Huang Date: Mon, 15 May 2017 23:06:19 +0800 Subject: [PATCH 06/25] roles management --- bower.json | 4 +- src/app/app.js | 7 + src/app/less/custom.less | 9 +- src/app/less/navigation.less | 12 ++ .../permission_management.controller.js | 178 ++++++++++++++++ .../permission_management.html | 191 ++++++++++++++++++ .../permission_management.service.js | 66 ++++++ src/components/common/navigation.html | 10 + 8 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 src/app/permission_management/permission_management.controller.js create mode 100644 src/app/permission_management/permission_management.html create mode 100644 src/app/permission_management/permission_management.service.js diff --git a/bower.json b/bower.json index 5b9a7a6..9f2351f 100755 --- a/bower.json +++ b/bower.json @@ -10,7 +10,6 @@ "angular-resource": "~1.4.4", "angular-ui-router": "~0.2.13", "bootstrap": "~3.3.5", - "angular-bootstrap": "0.12.x", "angular": "~1.4.4", "PACE": "https://github.com/HubSpot/pace.git#~1.0.2", "metisMenu": "~2.0.2", @@ -33,7 +32,8 @@ "moment-timezone": "~0.5.0", "ng-file-model": "https://github.com/mistralworks/ng-file-model.git#fd1889b28e279944012919574bbcaaf45c1540d6", "angular-bootstrap-multiselect": "*", - "bootstrap-ui-datetime-picker": "^2.4.0" + "bootstrap-ui-datetime-picker": "^2.4.0", + "angular-bootstrap": "^2.5.0" }, "overrides": { "bootstrap": { diff --git a/src/app/app.js b/src/app/app.js index 831dd10..d0b8817 100755 --- a/src/app/app.js +++ b/src/app/app.js @@ -75,6 +75,13 @@ angular.module('supportAdminApp', [ templateUrl: 'app/addmembers/add.html', data: { pageTitle: 'User Management' } }) + .state('index.permission_management', { + url: '/permission_management', + templateUrl: 'app/permission_management/permission_management.html', + data: { pageTitle: 'Permission Management' }, + controller: 'PermissionManagementCtrl', + controllerAs: 'ctrl', + }) .state('index.submissions', { abstract: true, url: '/submissions', diff --git a/src/app/less/custom.less b/src/app/less/custom.less index 89f8f14..ffddbda 100755 --- a/src/app/less/custom.less +++ b/src/app/less/custom.less @@ -3,4 +3,11 @@ .welcome-message { display: none; } -} \ No newline at end of file +} + +/* Permission Management - Roles */ + +.user-in-role { + display: inline-block; + margin-right: 12px; +} diff --git a/src/app/less/navigation.less b/src/app/less/navigation.less index 3e4e56f..95ce0ee 100755 --- a/src/app/less/navigation.less +++ b/src/app/less/navigation.less @@ -476,6 +476,18 @@ body.canvas-menu.mini-navbar .navbar-default .nav li a span { display: inline; } +#side-menu { + li { + span { + vertical-align: top; + } + } + .nav-label { + display: inline-block; + width: 120px; + } +} + body.canvas-menu.mini-navbar .navbar-default .nav li .profile-element a span { display: block; } diff --git a/src/app/permission_management/permission_management.controller.js b/src/app/permission_management/permission_management.controller.js new file mode 100644 index 0000000..92dcb5b --- /dev/null +++ b/src/app/permission_management/permission_management.controller.js @@ -0,0 +1,178 @@ +angular.module('supportAdminApp') +.controller('PermissionManagementCtrl', [ + '$scope', '$timeout', 'PermissionManagementService', 'UserService', + function ($scope, $timeout, PMService, UserService) { + + var vm = this; + + /* Table initialization. */ + + angular.element(document).ready(function() { + $('.footable').footable({ + addRowToggle: true + }); + }); + + $scope.$on('permissionManagement.DataUpdated', function(event) { + $timeout(function () { + $('.footable').trigger('footable_redraw'); + }, 100); + }); + + /* Role search by name. */ + + vm.searchCreateRoleText = ''; + + vm.clearRoleSearch = function() { + vm.searchCreateRoleText = ''; + vm.searchRole(); + } + + vm.searchRole = function() { + $('.footable').trigger('footable_filter', { + filter: vm.searchCreateRoleText, + }); + } + + /* Role creation. */ + + vm.creatingNewRole = false; + vm.createNewRoleError = ''; + + vm.createNewRole = function() { + vm.creatingNewRole = true; + vm.createNewRoleError = ''; + PMService.createRole(vm.searchCreateRoleText) + .then(function(res) { + vm.roles.push(res); + loadUser(res.createdBy); + loadUser(res.modifiedBy); + vm.assignment[res.id] = {}; + vm.roles = vm.roles.sort(function(a, b) { + return a.roleName.localeCompare(b.roleName); + }); + }, function(error) { + vm.createNewRoleError = + 'Error: ' + (error.message || 'Failed to create role!'); + }).then(function() { + vm.creatingNewRole = false; + $scope.$broadcast('permissionManagement.DataUpdated'); + }); + } + + /* Role assignments. */ + + vm.assignment = {}; + + /** + * Assigns role to the user. + * @param {String} roleId + * @param {String} userHandle + */ + vm.assignRole = function(roleId, userHandle) { + vm.assignment[roleId].inProgress = true; + vm.assignment[roleId].error = ''; + vm.assignment[roleId].info = ''; + var userId; + UserService.find({ + filter: 'handle=' + userHandle, + }).then(function(res) { + if (!res.length) throw new Error('No user found!'); + userId = res[0].id; + vm.users[userId] = userHandle; + return PMService.assignRole(roleId, userId); + }).then(function() { + var role = vm.roles.find(function (r) { return r.id === roleId; }); + vm.assignment[roleId].info = + 'Success: Role ' + role.roleName + + ' assigned to the user ' + userHandle; + }, function(error) { + vm.assignment[roleId].error = + 'Error: ' + (error.message || 'Failed to assign role!'); + }).then(function() { + vm.assignment[roleId].inProgress = false; + }); + } + + /** + * Unassign role from the user. + * @param {String} roleId + * @param {String} userId + */ + vm.unassignRole = function(roleId, userHandle) { + vm.assignment[roleId].error = ''; + var role = vm.roles.find(function(r) { + return r.id === roleId; + }); + vm.assignment[roleId].error = ''; + vm.assignment[roleId].info = ''; + var userId; + UserService.find({ + filter: 'handle=' + userHandle, + }).then(function (res) { + if (!res.length) throw new Error('No user found!'); + userId = res[0].id; + vm.users[userId] = userHandle; + if (confirm('Unassign role ' + role.roleName + ' from user ' + vm.users[userId] + '?')) { + return PMService.unassignRole(roleId, userId).then(function() { + var role = vm.roles.find(function (r) { return r.id === roleId; }); + vm.assignment[roleId].info = + 'Success: Role ' + role.roleName + + ' unassigned from the user ' + userHandle; + }); + } + }).catch(function(error) { + vm.assignment[roleId].error = + 'Error: ' + (error.message || 'Failed to unassign role!'); + }); + }; + + /* Loading roles. */ + + vm.loadingRoles = true; + vm.loadingRolesError = null; + PMService.getRoles().then(function(roles) { + vm.roles = roles; + roles.forEach(function(role) { + vm.assignment[role.id] = {}; + loadUser(role.createdBy); + loadUser(role.modifiedBy); + }); + }, function(error) { + vm.loadingRolesError = + 'Error: ' + (error.message || 'Failed to load roles!'); + }).then(function() { + vm.loadingRoles = false; + $scope.$broadcast('permissionManagement.DataUpdated'); + }); + + /* Maps user ids, present in the page, into user handles. */ + vm.users = {}; + + /** + * Loads handle of the user specified by id into $scope.users. Does nothing, + * if the handle is already in there. To avoid overflooding API with + * requests, this function handles the calls sequentially. + * @param {String} id User ID. + */ + var loadingUser = false; + var userLoadQueue = []; + function loadUser(id) { + if (id && !vm.users[id]) { + if (loadingUser) userLoadQueue.push(id); + else { + loadingUser = true; + UserService.findById(id).then(function(res) { + vm.users[id] = res.handle; + loadingUser = false; + while (userLoadQueue.length) { + var next = userLoadQueue[0]; + userLoadQueue = userLoadQueue.slice(1); + if (!vm.users[next]) return loadUser(next); + } + }); + } + } + } + } +]); \ No newline at end of file diff --git a/src/app/permission_management/permission_management.html b/src/app/permission_management/permission_management.html new file mode 100644 index 0000000..9bb00bf --- /dev/null +++ b/src/app/permission_management/permission_management.html @@ -0,0 +1,191 @@ +
+
+

Roles

+
+
+
+
+ +
+
+
+
+
+
+
{{ctrl.loadingRolesError}}
+
+
+
+ +
+
+
+
+ +
+
+ + +
+
+
+
{{ctrl.createNewRoleError}}
+
+
+
+
+

Press on a role row to assign/unassign users.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Role IDRole NameCreated byCreated atModified byModified atUser handle
{{role.id}}{{role.roleName}} + + {{ctrl.users[role.createdBy]}} + + loading... + {{role.createdAt | date : 'MM dd yyyy HH:mm' : 'EDT'}} EDT + + {{ctrl.users[role.modifiedBy]}} + + loading... + {{role.modifiedAt | date : 'MM dd yyyy HH:mm' : 'EDT'}} EDT +
+
+ +
+
+ +
+
+ +
+
+
+
{{ctrl.assignment[role.id].error}}
+
+
+
{{ctrl.assignment[role.id].info}}
+
+
+
    +
    +
    +
    +
    +
    \ No newline at end of file diff --git a/src/app/permission_management/permission_management.service.js b/src/app/permission_management/permission_management.service.js new file mode 100644 index 0000000..bfd35af --- /dev/null +++ b/src/app/permission_management/permission_management.service.js @@ -0,0 +1,66 @@ +angular.module('supportAdminApp') +.factory('PermissionManagementService', [ + '$http', 'API_URL', + function($http, API_URL) { + var Service = {}; + + /** + * Assigns role to the user. + * @param {String} roleId + * @param {String} userId + * @return {Promise} Resolves to the roleId, if success. + */ + Service.assignRole = function(roleId, userId) { + return $http.post(API_URL + '/v3/roles/' + roleId + + '/assign?action=true&filter=subjectID%3D' + userId) + .then(function(res) { + return res.data.result.content; + }); + }; + + /** + * Creates a new role. + * @param {String} roleName + * @return {Promise} Resolves to the created role object. + */ + Service.createRole = function(roleName) { + return $http.post(API_URL + '/v3/roles', { + param: { + roleName: roleName + } + }).then(function(res) { + return res.data.result.content; + }); + }; + + /** + * Gets roles. + * @return {Promise} Resolves to the array of role objects, sorted + * by names. + */ + Service.getRoles = function() { + return $http.get(API_URL + '/v3/roles') + .then(function(res) { + return res.data.result.content.sort(function(a, b) { + return a.roleName.localeCompare(b.roleName); + }); + }); + }; + + /** + * Unassigns the role from the user. + * @param {String} roleId + * @param {String} userId + * @return {Promise} Resolves to the roleId, if success. + */ + Service.unassignRole = function(roleId, userId) { + return $http.delete(API_URL + '/v3/roles/' + roleId + + '/deassign?action=true&filter=subjectID%3D' + userId) + .then(function(res) { + return res.data.result.content; + }); + }; + + return Service; + } +]); diff --git a/src/components/common/navigation.html b/src/components/common/navigation.html index 949ac59..7d429d1 100755 --- a/src/components/common/navigation.html +++ b/src/components/common/navigation.html @@ -17,6 +17,16 @@
  • Import SSO Users
  • +
  • + + + Permission Management + + + +
  • Billing Account From 935b66477fa4347872cac8c0c7a9530bfc688ad0 Mon Sep 17 00:00:00 2001 From: ajefts Date: Mon, 15 May 2017 13:47:31 -0400 Subject: [PATCH 07/25] adding deployment commands --- circle.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/circle.yml b/circle.yml index 131afaf..053d313 100644 --- a/circle.yml +++ b/circle.yml @@ -21,3 +21,14 @@ compile: test: override: - npm run test + +deployment: + dev: + branch: dev + commands: + - aws s3 sync / s3://admin.topcoder-dev.com --delete + + prod: + branch: master + commands: + - aws s3 sync / s3://admin.topcoder-prod.com --delete From 3da5f75c466729a1f6273e1adfda866ba935bf07 Mon Sep 17 00:00:00 2001 From: ajefts Date: Mon, 15 May 2017 13:55:54 -0400 Subject: [PATCH 08/25] Update circle.yml --- circle.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/circle.yml b/circle.yml index 053d313..733d3f2 100644 --- a/circle.yml +++ b/circle.yml @@ -26,9 +26,9 @@ deployment: dev: branch: dev commands: - - aws s3 sync / s3://admin.topcoder-dev.com --delete + - aws s3 sync . s3://admin.topcoder-dev.com --delete prod: branch: master commands: - - aws s3 sync / s3://admin.topcoder-prod.com --delete + - aws s3 sync . s3://admin.topcoder-prod.com --delete From 77c2a25d56f313b80e7e678f0be7b1705a1d5cea Mon Sep 17 00:00:00 2001 From: Parth Shah Date: Mon, 15 May 2017 12:45:43 -0700 Subject: [PATCH 09/25] updating circle ci and addign new deploy script --- circle.yml | 18 +++++++++++++++--- deploy.sh | 10 ++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100755 deploy.sh diff --git a/circle.yml b/circle.yml index 131afaf..7f1e4d0 100644 --- a/circle.yml +++ b/circle.yml @@ -2,10 +2,10 @@ machine: node: version: 6.8.1 - + # Add some environment variables environment: - + ## Customize dependencies dependencies: pre: @@ -17,7 +17,19 @@ dependencies: compile: override: - npm run build - + test: override: - npm run test + +deployment: + prod: + branch: master + commands: + - ./deploy.sh PROD admin.topcoder.com + dev: + # branch: dev + # temporarily testing on feature branch + branch: feature/ci-deploy + commands: + - ./deploy.sh DEV admin.topcoder-dev.com diff --git a/deploy.sh b/deploy.sh new file mode 100755 index 0000000..90aecec --- /dev/null +++ b/deploy.sh @@ -0,0 +1,10 @@ +#!/bin/bash + + +echo "Deploying to S3" +ENV=$1 +BUCKET_URL=$2 +export AWS_ACCESS_KEY_ID=$(eval "echo \$${ENV}_AWS_ACCESS_KEY_ID") +export AWS_SECRET_ACCESS_KEY=$(eval "echo \$${ENV}_AWS_SECRET_ACCESS_KEY") + +aws s3 sync dist/** s3://${BUCKET_URL} --delete From 8816f10554af1690030f13a92ff3a44b57d843e5 Mon Sep 17 00:00:00 2001 From: Parth Shah Date: Mon, 15 May 2017 20:21:33 -0700 Subject: [PATCH 10/25] minor fixes --- deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy.sh b/deploy.sh index 90aecec..9e8d4db 100755 --- a/deploy.sh +++ b/deploy.sh @@ -7,4 +7,4 @@ BUCKET_URL=$2 export AWS_ACCESS_KEY_ID=$(eval "echo \$${ENV}_AWS_ACCESS_KEY_ID") export AWS_SECRET_ACCESS_KEY=$(eval "echo \$${ENV}_AWS_SECRET_ACCESS_KEY") -aws s3 sync dist/** s3://${BUCKET_URL} --delete +aws s3 sync dist s3://${BUCKET_URL} --delete From c2cf2c0bb11ca5c12a4db2b81d582e4fc0dc7f0c Mon Sep 17 00:00:00 2001 From: Parth Shah Date: Mon, 15 May 2017 20:28:02 -0700 Subject: [PATCH 11/25] switching to dev branch --- circle.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/circle.yml b/circle.yml index 7f1e4d0..c7c29cc 100644 --- a/circle.yml +++ b/circle.yml @@ -28,8 +28,6 @@ deployment: commands: - ./deploy.sh PROD admin.topcoder.com dev: - # branch: dev - # temporarily testing on feature branch - branch: feature/ci-deploy + branch: dev commands: - ./deploy.sh DEV admin.topcoder-dev.com From a97f362a653c7d986f7e8d04cf0320c00ba102b1 Mon Sep 17 00:00:00 2001 From: Parth Shah Date: Tue, 16 May 2017 09:03:58 -0700 Subject: [PATCH 12/25] updating deploy script to include public read option --- deploy.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy.sh b/deploy.sh index 9e8d4db..6730849 100755 --- a/deploy.sh +++ b/deploy.sh @@ -7,4 +7,4 @@ BUCKET_URL=$2 export AWS_ACCESS_KEY_ID=$(eval "echo \$${ENV}_AWS_ACCESS_KEY_ID") export AWS_SECRET_ACCESS_KEY=$(eval "echo \$${ENV}_AWS_SECRET_ACCESS_KEY") -aws s3 sync dist s3://${BUCKET_URL} --delete +aws s3 sync dist s3://${BUCKET_URL} --acl public-read --delete From 59161726be13a75b77f16df2b349c756b07e9858 Mon Sep 17 00:00:00 2001 From: Parth Shah Date: Tue, 16 May 2017 09:34:23 -0700 Subject: [PATCH 13/25] updating deploy scripts --- deploy.sh | 7 ++++--- package.json | 1 + 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/deploy.sh b/deploy.sh index 6730849..f45c2cb 100755 --- a/deploy.sh +++ b/deploy.sh @@ -4,7 +4,8 @@ echo "Deploying to S3" ENV=$1 BUCKET_URL=$2 -export AWS_ACCESS_KEY_ID=$(eval "echo \$${ENV}_AWS_ACCESS_KEY_ID") -export AWS_SECRET_ACCESS_KEY=$(eval "echo \$${ENV}_AWS_SECRET_ACCESS_KEY") +AWS_ACCESS_KEY_ID=$(eval "echo \$${ENV}_AWS_ACCESS_KEY_ID") +AWS_SECRET_ACCESS_KEY=$(eval "echo \$${ENV}_AWS_SECRET_ACCESS_KEY") -aws s3 sync dist s3://${BUCKET_URL} --acl public-read --delete +# aws s3 sync dist s3://${BUCKET_URL} --acl public-read --delete +AWS_BUCKET=$BUCKET_URL AWS_KEY=$AWS_ACCESS_KEY_ID AWS_SECRET=$AWS_SECRET_ACCESS_KEY ./node_modules/.bin/gulp publish diff --git a/package.json b/package.json index 5822935..b967e66 100755 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ }, "scripts": { "postinstall": "bower install --config.interactive=false", + "clean": "gulp clean", "build": "gulp build", "start": "gulp serve", "test": "gulp protractor" From b1c8f9fa00324b042b21a0e7cc79fe83ad5e429a Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 14:18:12 -0400 Subject: [PATCH 14/25] Update circle.yml --- circle.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/circle.yml b/circle.yml index c7c29cc..f8f319f 100644 --- a/circle.yml +++ b/circle.yml @@ -13,6 +13,13 @@ dependencies: override: - npm install + + post: + - rm -rf bower_components + - ./node_modules/bower/bin/bower install + - ./node_modules/gulp/bin/gulp.js clean + - ./node_modules/gulp/bin/gulp.js build + - ./node_modules/gulp/bin/gulp.js publish compile: override: From e80cdb66593f372587b005787a4e3d9a17fa1ebd Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 14:30:55 -0400 Subject: [PATCH 15/25] Update circle.yml --- circle.yml | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/circle.yml b/circle.yml index f8f319f..6805fd3 100644 --- a/circle.yml +++ b/circle.yml @@ -12,18 +12,16 @@ dependencies: - curl -s https://raw.githubusercontent.com/chronogolf/circleci-google-chrome/master/use_chrome_stable_version.sh | bash override: - - npm install - - post: +## - npm install + + +compile: + override: - rm -rf bower_components - ./node_modules/bower/bin/bower install - ./node_modules/gulp/bin/gulp.js clean - ./node_modules/gulp/bin/gulp.js build - - ./node_modules/gulp/bin/gulp.js publish - -compile: - override: - - npm run build + - ./node_modules/gulp/bin/gulp.js publish test: override: From 17a534c079f5087c9640b1959971057adc6c6135 Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 14:36:57 -0400 Subject: [PATCH 16/25] Update circle.yml --- circle.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 6805fd3..1971f75 100644 --- a/circle.yml +++ b/circle.yml @@ -13,7 +13,8 @@ dependencies: override: ## - npm install - + - npm install -g gulp@3.8.10 bower + - npm install compile: override: From 242a065321e2422729adf249524eb84cbd26ef10 Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 14:49:18 -0400 Subject: [PATCH 17/25] Update circle.yml --- circle.yml | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/circle.yml b/circle.yml index 1971f75..c7c29cc 100644 --- a/circle.yml +++ b/circle.yml @@ -12,17 +12,11 @@ dependencies: - curl -s https://raw.githubusercontent.com/chronogolf/circleci-google-chrome/master/use_chrome_stable_version.sh | bash override: -## - npm install - - npm install -g gulp@3.8.10 bower - npm install compile: override: - - rm -rf bower_components - - ./node_modules/bower/bin/bower install - - ./node_modules/gulp/bin/gulp.js clean - - ./node_modules/gulp/bin/gulp.js build - - ./node_modules/gulp/bin/gulp.js publish + - npm run build test: override: From e1b2d630a0d7bcd2edfef085c6383a412dbb36ce Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 14:49:59 -0400 Subject: [PATCH 18/25] updating for circleci build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index b967e66..6a7e257 100755 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "postinstall": "bower install --config.interactive=false", "clean": "gulp clean", "build": "gulp build", - "start": "gulp serve", + "start": "gulp publish", "test": "gulp protractor" } } From b1b788d14e2efedcc4ae6185579410d72b5dbcf7 Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 15:10:38 -0400 Subject: [PATCH 19/25] Update circle.yml --- circle.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/circle.yml b/circle.yml index c7c29cc..65b02fc 100644 --- a/circle.yml +++ b/circle.yml @@ -13,6 +13,11 @@ dependencies: override: - npm install + + post: + - ./node_modules/gulp/bin/gulp.js clean + - ./node_modules/gulp/bin/gulp.js build + - ./node_modules/gulp/bin/gulp.js publish compile: override: From 13440ead028147c0146fbd1d46f5b9c89c58ea40 Mon Sep 17 00:00:00 2001 From: ajefts Date: Wed, 17 May 2017 15:15:37 -0400 Subject: [PATCH 20/25] Update circle.yml --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 65b02fc..8b1c160 100644 --- a/circle.yml +++ b/circle.yml @@ -21,7 +21,7 @@ dependencies: compile: override: - - npm run build +## - npm run build test: override: From 63542a84b4767adc2063a44617303ddb4de10b88 Mon Sep 17 00:00:00 2001 From: Qun Huang Date: Thu, 18 May 2017 10:02:55 +0800 Subject: [PATCH 21/25] trial fix for build failure --- circle.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 8b1c160..1fafa25 100644 --- a/circle.yml +++ b/circle.yml @@ -13,7 +13,8 @@ dependencies: override: - npm install - + - bower --force update + post: - ./node_modules/gulp/bin/gulp.js clean - ./node_modules/gulp/bin/gulp.js build From 73592ed1c81afef88affa287c65bcf8bf1400846 Mon Sep 17 00:00:00 2001 From: Qun Huang Date: Thu, 18 May 2017 10:06:49 +0800 Subject: [PATCH 22/25] trial fix for build failure --- circle.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/circle.yml b/circle.yml index 1fafa25..08d040e 100644 --- a/circle.yml +++ b/circle.yml @@ -12,8 +12,8 @@ dependencies: - curl -s https://raw.githubusercontent.com/chronogolf/circleci-google-chrome/master/use_chrome_stable_version.sh | bash override: + - rm -rf bower_components - npm install - - bower --force update post: - ./node_modules/gulp/bin/gulp.js clean From acba7913807f638a36e77eaccd03c5ca891f8111 Mon Sep 17 00:00:00 2001 From: ajefts Date: Thu, 18 May 2017 15:31:39 -0400 Subject: [PATCH 23/25] trying to fix angular issue --- bower.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bower.json b/bower.json index 9f2351f..7f67031 100755 --- a/bower.json +++ b/bower.json @@ -9,7 +9,6 @@ "angular-sanitize": "~1.4.4", "angular-resource": "~1.4.4", "angular-ui-router": "~0.2.13", - "bootstrap": "~3.3.5", "angular": "~1.4.4", "PACE": "https://github.com/HubSpot/pace.git#~1.0.2", "metisMenu": "~2.0.2", @@ -31,6 +30,7 @@ "moment": "~2.11.2", "moment-timezone": "~0.5.0", "ng-file-model": "https://github.com/mistralworks/ng-file-model.git#fd1889b28e279944012919574bbcaaf45c1540d6", + "bootstrap": "~3.3.5", "angular-bootstrap-multiselect": "*", "bootstrap-ui-datetime-picker": "^2.4.0", "angular-bootstrap": "^2.5.0" From 1c69145fd64fe4f02ce1ef8df9398cb0ec40036c Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 7 Jun 2017 14:24:51 +0800 Subject: [PATCH 24/25] challenge #30057836 - 72H ADMIN APP - REPLACE LOGIN IMPLEMENTATION --- README.md | 25 +- bower.json | 3 - config.json | 44 +- e2e/dashboard.spec.js | 19 - e2e/login.po.js | 22 - e2e/login.spec.js | 56 -- gulp/server.js | 4 +- package.json | 2 +- protractor.conf.js | 7 - src/app/addmembers/add.controller.js | 2 +- src/app/admintool/admintool.controller.js | 60 +- src/app/admintool/admintool.html | 10 +- src/app/admintool/admintool.service.js | 85 +-- src/app/app.js | 583 ++++++++++-------- src/app/auth/auth.config.js | 65 ++ src/app/auth/auth.controller.js | 42 ++ src/app/auth/auth.html | 23 + src/app/auth/auth.service.js | 275 +++++++++ .../billingaccountresources.service.js | 8 +- .../billingaccounts.service.js | 8 +- src/app/login/login.controller.js | 69 --- src/app/login/login.html | 33 - src/app/main/main.controller.js | 6 +- .../permission_management.service.js | 13 +- src/app/tags/tags.edit.controller.js | 6 +- src/app/users/users.service.js | 18 +- 26 files changed, 826 insertions(+), 662 deletions(-) delete mode 100644 e2e/login.po.js delete mode 100644 e2e/login.spec.js create mode 100644 src/app/auth/auth.config.js create mode 100644 src/app/auth/auth.controller.js create mode 100644 src/app/auth/auth.html create mode 100644 src/app/auth/auth.service.js delete mode 100644 src/app/login/login.controller.js delete mode 100755 src/app/login/login.html diff --git a/README.md b/README.md index ab65426..f737156 100644 --- a/README.md +++ b/README.md @@ -28,29 +28,26 @@ The following configuration parameters are available: | Name | Description | |--------------------------|---------------------------------| -| ES_PROJECT_API_URL | URL of the ES project API | | API_URL | URL of the topcoder API | -| WORK_API_URL | URL of the topcoder work API | | ADMIN_TOOL_URL | URL of the admin tool API | | API_VERSION_PATH | Version of the API | -| AUTH0_CLIENT_ID | Client ID for Auth0 | -| AUTH0_DOMAIN | Domain for Auth0 authentication | -| AUTH0_TOKEN_NAME | Auth0 token name | -| AUTH0_REFRESH_TOKEN_NAME | Auth0 refresh token name | +| COOKIES_SECURE | If true the cookies set by this App will only be transmitted over secure protocols like https. | +| AUTH_URL | Url of Topcoder auth form | +| ACCOUNTS_CONNECTOR_URL | Url to TC account connector | +| JWT_V3_NAME | jwt V3 cookie name | +| JWT_V2_NAME | jwt V2 cookie name | ## Start the Application +As application uses Topcoder authorization we have to run it on the one of allowed domains. For development purposes we can use `local.topcoder-dev.com:3000`. So before run we have to add into `hosts` file the line `127.0.0.1 local.topcoder-dev.com`. Be aware, that we also have to run on the port `3000` to be able to authorize when run locally. + Simply execute the following command to start the app in development mode (with browsersync) ``` npm install -npm start -``` -Application will be hosted and running at http://locahost:3000 - -To build the application to be hosted on a real webserver run: -``` -npm run build +gulp build +gulp serve ``` +Application will be hosted and running at http://local.topcoder-dev.com:3000. ## Execute E2E Tests @@ -59,8 +56,6 @@ Before executing the end-to-end (e2e) protractor tests, these environment variab | Name | Description | Default Value | | --- | --- | --- | | BUILD_ENV | Deployment configuration to be tested by e2e tests. | See [Configuration](#configuration) for possible values. Defaults to `dev`. | -| TEST_USER | Account username to use for e2e tests. | No default. Must be set. | -| TEST_PASSWORD | Account password to use for e2e tests. | No default. Must be set. | | TEST_PORT | Port from which to serve the app for e2e tests. | Defaults to `3000`. | ```npm test``` diff --git a/bower.json b/bower.json index 7f67031..c69699e 100755 --- a/bower.json +++ b/bower.json @@ -21,9 +21,6 @@ "a0-angular-storage": "~0.0.11", "angular-jwt": "~0.0.9", "angular-footable": "~1.0.3", - "appirio-tech-ng-auth": "git://github.com/appirio-tech/ng-auth.git#3.2.10", - "appirio-tech-ng-login-reg": "0.x.x", - "appirio-tech-ng-api-services": "0.x.x", "angular-clipboard": "~1.2.1", "lodash": "~4.2.0", "angular-moment": "~1.0.0-beta.3", diff --git a/config.json b/config.json index 3c099af..dcf688a 100644 --- a/config.json +++ b/config.json @@ -1,46 +1,42 @@ { "local": { - "ES_PROJECT_API_URL": "http://127.0.0.1:8553", "API_URL" : "https://127.0.0.1:8443", - "WORK_API_URL" : "https://127.0.0.1:8443", "ADMIN_TOOL_URL" : "http://localhost:8080/api/v2", "API_VERSION_PATH" : "v3", - "AUTH0_CLIENT_ID" : "JFDo7HMkf0q2CkVFHojy3zHWafziprhT", - "AUTH0_DOMAIN" : "127.0.0.1:8443", - "AUTH0_TOKEN_NAME" : "userJWTToken", - "AUTH0_REFRESH_TOKEN_NAME" : "userRefreshJWTToken" + "COOKIES_SECURE": false, + "AUTH_URL": "https://accounts.topcoder-dev.com/member", + "ACCOUNTS_CONNECTOR_URL": "https://accounts.topcoder-dev.com/connector.html", + "JWT_V3_NAME": "v3jwt", + "JWT_V2_NAME": "tcjwt" }, "dev": { - "ES_PROJECT_API_URL": "https://internal-api.topcoder-dev.com", "API_URL" : "https://api.topcoder-dev.com", - "WORK_API_URL" : "https://api-work.topcoder-dev.com", "ADMIN_TOOL_URL" : "https://api.topcoder-dev.com/v2", "API_VERSION_PATH" : "v3", - "AUTH0_CLIENT_ID" : "JFDo7HMkf0q2CkVFHojy3zHWafziprhT", - "AUTH0_DOMAIN" : "topcoder-dev.auth0.com", - "AUTH0_TOKEN_NAME" : "userJWTToken", - "AUTH0_REFRESH_TOKEN_NAME" : "userRefreshJWTToken" + "COOKIES_SECURE": false, + "AUTH_URL": "https://accounts.topcoder-dev.com/member", + "ACCOUNTS_CONNECTOR_URL": "https://accounts.topcoder-dev.com/connector.html", + "JWT_V3_NAME": "v3jwt", + "JWT_V2_NAME": "tcjwt" }, "qa": { - "ES_PROJECT_API_URL": "https://internal-api.topcoder-qa.com", "API_URL" : "https://api.topcoder-qa.com", - "WORK_API_URL" : "https://api-work.topcoder-qa.com", "ADMIN_TOOL_URL" : "https://api.topcoder-qa.com/v2", "API_VERSION_PATH" : "v3", - "AUTH0_CLIENT_ID" : "EVOgWZlCtIFlbehkq02treuRRoJk12UR", - "AUTH0_DOMAIN" : "topcoder-qa.auth0.com", - "AUTH0_TOKEN_NAME" : "userJWTToken", - "AUTH0_REFRESH_TOKEN_NAME" : "userRefreshJWTToken" + "COOKIES_SECURE": false, + "AUTH_URL": "https://accounts.topcoder-qa.com/member", + "ACCOUNTS_CONNECTOR_URL": "https://accounts.topcoder-qa.com/connector.html", + "JWT_V3_NAME": "v3jwt", + "JWT_V2_NAME": "tcjwt" }, "prod": { "API_URL" : "https://api.topcoder.com", - "WORK_API_URL" : "https://api-work.topcoder.com", - "ES_PROJECT_API_URL": "https://internal-api.topcoder.com", "ADMIN_TOOL_URL" : "https://api.topcoder.com/v2", "API_VERSION_PATH" : "v3", - "AUTH0_CLIENT_ID" : "6ZwZEUo2ZK4c50aLPpgupeg5v2Ffxp9P", - "AUTH0_DOMAIN" : "topcoder.auth0.com", - "AUTH0_TOKEN_NAME" : "userJWTToken", - "AUTH0_REFRESH_TOKEN_NAME" : "userRefreshJWTToken" + "COOKIES_SECURE": false, + "AUTH_URL": "https://accounts.topcoder.com/member", + "ACCOUNTS_CONNECTOR_URL": "https://accounts.topcoder.com/connector.html", + "JWT_V3_NAME": "v3jwt", + "JWT_V2_NAME": "tcjwt" } } diff --git a/e2e/dashboard.spec.js b/e2e/dashboard.spec.js index b6af000..529a358 100644 --- a/e2e/dashboard.spec.js +++ b/e2e/dashboard.spec.js @@ -1,30 +1,11 @@ 'use strict'; describe('The dashboard view', function () { - var page; var mainPage; - var testUser = process.env.TEST_USER; - var testPassword = process.env.TEST_PASSWORD; var testPort = process.env.TEST_PORT || 3000; beforeEach(function () { browser.get('http://localhost:' + testPort + '/'); - page = require('./login.po'); mainPage = require('./main.po'); }); - - it('should have environment variables defined', function(){ - expect(testUser).toBeDefined(); - expect(testPassword).toBeDefined(); - }); - - it('should find members', function() { - page.usernameInput.sendKeys(testUser); - page.passwordInput.sendKeys(testPassword); - page.loginButton.click(); - mainPage.searchHandleInput.sendKeys('sah2ed'); - mainPage.searchButton.click(); - expect(mainPage.users.count()).toBe(1); - expect(mainPage.users.get(0).element(by.cssContainingText('td', 'sah2ed')).getText()).toBe('sah2ed'); - }); }); diff --git a/e2e/login.po.js b/e2e/login.po.js deleted file mode 100644 index 14077e3..0000000 --- a/e2e/login.po.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * This file uses the Page Object pattern to define the main page for tests - * https://docs.google.com/presentation/d/1B6manhG0zEXkC-H-tPo2vwU06JhL8w9-XCF9oehXzAQ - */ - -'use strict'; - -var LoginPage = function() { - /*this.jumbEl = element(by.css('.jumbotron')); - this.h1El = this.jumbEl.element(by.css('h1')); - this.imgEl = this.jumbEl.element(by.css('img')); - this.thumbnailEls = element(by.css('body')).all(by.repeater('awesomeThing in awesomeThings'));*/ - this.loginForm = element(by.css('form')); - this.loginHeader = this.loginForm.element(by.css('h3')); - const inputs = this.loginForm.all(by.css('input')); - this.usernameInput = inputs.get(0); - this.passwordInput = inputs.get(1); - this.loginButton = this.loginForm.element(by.css('button')); - this.alerts = element(by.css('body')).all(by.repeater('alert in alerts')); -}; - -module.exports = new LoginPage(); diff --git a/e2e/login.spec.js b/e2e/login.spec.js deleted file mode 100644 index ec57407..0000000 --- a/e2e/login.spec.js +++ /dev/null @@ -1,56 +0,0 @@ -'use strict'; - -describe('The login view', function () { - var page; - var mainPage; - var testUser = process.env.TEST_USER; - var testPassword = process.env.TEST_PASSWORD; - var testPort = process.env.TEST_PORT || 3000; - - beforeEach(function () { - browser.get('http://localhost:' + testPort + '/'); - page = require('./login.po'); - mainPage = require('./main.po'); - }); - - it('should have environment variables defined', function(){ - expect(testUser).toBeDefined(); - expect(testPassword).toBeDefined(); - }); - - it('should display the correct form heading', function() { - expect(page.loginHeader.getText()).toBe('ADMIN APP LOGIN'); - //expect(page.imgEl.getAttribute('src')).toMatch(/assets\/images\/yeoman.png$/); - //expect(page.imgEl.getAttribute('alt')).toBe('I\'m Yeoman'); - }); - - it('login should fail for wrong credentials', function () { - //expect(page.thumbnailEls.count()).toBeGreaterThan(5); - page.usernameInput.sendKeys('wrong'); - page.passwordInput.sendKeys('wrong'); - page.loginButton.click(); - expect(page.alerts.count()).toBe(1); - expect(page.alerts.get(0).getText()).toBe('Wrong username or password.'); - }); - - it('login should succeed for correct credentials', function () { - //expect(page.thumbnailEls.count()).toBeGreaterThan(5); - page.usernameInput.sendKeys(testUser); - page.passwordInput.sendKeys(testPassword); - page.loginButton.click(); - expect(mainPage.isUserLoggedIn.isDisplayed()).toBeTruthy(); - expect(mainPage.loggedInUser.getText()).toBe(testUser); - }); - - it('logout should work after login', function () { - //expect(page.thumbnailEls.count()).toBeGreaterThan(5); - page.usernameInput.sendKeys(testUser); - page.passwordInput.sendKeys(testPassword); - page.loginButton.click(); - expect(mainPage.isUserLoggedIn.isDisplayed()).toBeTruthy(); - expect(mainPage.loggedInUser.getText()).toBe(testUser); - mainPage.logout.click(); - expect(page.loginHeader.getText()).toBe('ADMIN APP LOGIN'); - }); - -}); diff --git a/gulp/server.js b/gulp/server.js index f5f4f92..c0845e9 100755 --- a/gulp/server.js +++ b/gulp/server.js @@ -27,7 +27,9 @@ function browserSyncInit(baseDir, files, browser) { middleware: middleware, routes: routes }, - browser: browser + browser: browser, + host: 'local.topcoder-dev.com', + open: 'external' }); } diff --git a/package.json b/package.json index 6a7e257..cc3f0c6 100755 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "gulp-useref": "~1.0.2", "http-proxy": "~1.7.0", "jasmine-core": "^2.5.2", - "jshint":"~2.9.4", + "jshint": "~2.9.4", "jshint-stylish": "~1.0.0", "main-bower-files": "~2.13.1", "protractor": "~5.1.1", diff --git a/protractor.conf.js b/protractor.conf.js index 3af9dbd..b2c93a1 100755 --- a/protractor.conf.js +++ b/protractor.conf.js @@ -11,13 +11,6 @@ exports.config = { 'browserName': 'chrome' }, - onPrepare: function() { - // check if env variables for testing are set - if (typeof process.env.TEST_USER === "undefined" || typeof process.env.TEST_PASSWORD === "undefined") { - throw "The environment variables TEST_USER and TEST_PASSWORD should be set in order for the tests to work"; - } - }, - // Spec patterns are relative to the current working directly when // protractor is called. specs: [paths.e2e + '/**/*.js'], diff --git a/src/app/addmembers/add.controller.js b/src/app/addmembers/add.controller.js index 463f371..84c90cc 100644 --- a/src/app/addmembers/add.controller.js +++ b/src/app/addmembers/add.controller.js @@ -2,7 +2,7 @@ var module = angular.module('supportAdminApp'); -module.controller('addmembers.AddMemberController', ['$log', '$scope', '$parse', 'AuthService', 'MemberService', function ($log, $scope, $parse, $authService, $memberService) { +module.controller('addmembers.AddMemberController', ['$log', '$scope', '$parse', 'MemberService', function ($log, $scope, $parse, $memberService) { $scope.errors = []; $scope.response = []; diff --git a/src/app/admintool/admintool.controller.js b/src/app/admintool/admintool.controller.js index b2126db..7c995a5 100644 --- a/src/app/admintool/admintool.controller.js +++ b/src/app/admintool/admintool.controller.js @@ -7,7 +7,6 @@ module.controller('admintool.AdminToolController', [ function ($scope, $timeout, $modal, $authService, $adminToolService, $alert, $const) { $scope.users = []; $scope.reviewBoardProjectCategories = []; - $scope.v2Token = null; $scope.constRoles = $const.Roles; // search $scope.formSearch = { @@ -60,8 +59,8 @@ module.controller('admintool.AdminToolController', [ $scope.formSearch.setLoading(true); var searchMethod = $scope.formSearch.isReviewer() ? - $adminToolService.findReviewers($scope.v2Token, $scope.formSearch.categoryId) - : $adminToolService['find' + role + 's']($scope.v2Token); + $adminToolService.findReviewers($scope.formSearch.categoryId) + : $adminToolService['find' + role + 's'](); searchMethod.then( function (users) { if (handle) { @@ -82,24 +81,16 @@ module.controller('admintool.AdminToolController', [ ); }; - // exchange v3 token with v2 token $scope.formSearch.setLoading(true); - $adminToolService.getV2Token().then(function (token) { - $scope.v2Token = token; - $adminToolService.findReviewBoardProjectCategories($scope.v2Token).then(function (projectCategories) { - projectCategories = projectCategories.filter(function (projectCategory) { - return $const.ExcludeCategories.indexOf(angular.lowercase(projectCategory.name)) === -1; - }); - projectCategories = projectCategories.sort(function (p1, p2) { - return p1.name.localeCompare(p2.name); - }); - $scope.reviewBoardProjectCategories = projectCategories; - $scope.formSearch.setLoading(false); - }, - function (error) { - $alert.error(error.error, $scope); - $scope.formSearch.setLoading(false); - }) + $adminToolService.findReviewBoardProjectCategories().then(function (projectCategories) { + projectCategories = projectCategories.filter(function (projectCategory) { + return $const.ExcludeCategories.indexOf(angular.lowercase(projectCategory.name)) === -1; + }); + projectCategories = projectCategories.sort(function (p1, p2) { + return p1.name.localeCompare(p2.name); + }); + $scope.reviewBoardProjectCategories = projectCategories; + $scope.formSearch.setLoading(false); }, function (error) { $alert.error(error.error, $scope); @@ -113,9 +104,6 @@ module.controller('admintool.AdminToolController', [ templateUrl: 'app/admintool/remove-user-role-dialog.html', controller: 'admintool.RemoveUserRoleDialogController', resolve: { - v2Token: function () { - return $scope.v2Token; - }, user: function () { return $scope.users[index]; }, @@ -136,9 +124,6 @@ module.controller('admintool.AdminToolController', [ templateUrl: 'app/admintool/user-role-dialog.html', controller: 'admintool.NewUserRoleDialogController', resolve: { - v2Token: function () { - return $scope.v2Token; - }, role: function () { return $scope.formSearch.role; }, @@ -166,9 +151,6 @@ module.controller('admintool.AdminToolController', [ templateUrl: 'app/admintool/user-role-dialog.html', controller: 'admintool.EditUserRoleDialogController', resolve: { - v2Token: function () { - return $scope.v2Token; - }, user: function () { return $scope.users[index]; }, @@ -194,8 +176,8 @@ module.controller('admintool.AdminToolController', [ } ]); module.controller('admintool.RemoveUserRoleDialogController', [ - '$scope', '$uibModalInstance', 'AdminToolService', 'Alert', 'v2Token', 'user', 'role', 'admintool.Constants', - function ($scope, $modalInstance, $adminToolService, $alert, v2Token, user, role, $const) { + '$scope', '$uibModalInstance', 'AdminToolService', 'Alert', 'user', 'role', 'admintool.Constants', + function ($scope, $modalInstance, $adminToolService, $alert, user, role, $const) { $scope.form = { user: user, role: role, @@ -218,7 +200,7 @@ module.controller('admintool.RemoveUserRoleDialogController', [ if (role === $const.Roles.Reviewer) { data.categoryId = user.projectCategoryId; } - $adminToolService['delete' + role](v2Token, data).then( + $adminToolService['delete' + role](data).then( function (result) { $scope.form.setLoading(false); $modalInstance.close(result); @@ -233,9 +215,9 @@ module.controller('admintool.RemoveUserRoleDialogController', [ ]); module.controller('admintool.NewUserRoleDialogController', [ - '$scope', '$uibModalInstance', 'AdminToolService', 'Alert', 'v2Token', 'role', 'categoryId', 'reviewBoardProjectCategories', + '$scope', '$uibModalInstance', 'AdminToolService', 'Alert', 'role', 'categoryId', 'reviewBoardProjectCategories', 'admintool.Constants', - function ($scope, $modalInstance, $adminToolService, $alert, v2Token, role, categoryId, reviewBoardProjectCategories, $const) { + function ($scope, $modalInstance, $adminToolService, $alert, role, categoryId, reviewBoardProjectCategories, $const) { $scope.reviewBoardProjectCategories = reviewBoardProjectCategories; $scope.constRoles = $const.Roles; $scope.form = { @@ -284,7 +266,7 @@ module.controller('admintool.NewUserRoleDialogController', [ } } - $adminToolService['create' + $scope.form.role](v2Token, newUser).then( + $adminToolService['create' + $scope.form.role](newUser).then( function (result) { $scope.form.setLoading(false); result.role = $scope.form.role; @@ -303,8 +285,8 @@ module.controller('admintool.NewUserRoleDialogController', [ ]); module.controller('admintool.EditUserRoleDialogController', [ - '$scope', '$uibModalInstance', 'AdminToolService', 'Alert', 'v2Token', 'user', 'role', 'categoryId', 'reviewBoardProjectCategories', 'admintool.Constants', - function ($scope, $modalInstance, $adminToolService, $alert, v2Token, user, role, categoryId, reviewBoardProjectCategories, $const) { + '$scope', '$uibModalInstance', 'AdminToolService', 'Alert', 'user', 'role', 'categoryId', 'reviewBoardProjectCategories', 'admintool.Constants', + function ($scope, $modalInstance, $adminToolService, $alert, user, role, categoryId, reviewBoardProjectCategories, $const) { $scope.reviewBoardProjectCategories = reviewBoardProjectCategories; $scope.constRoles = $const.Roles; $scope.form = { @@ -353,7 +335,7 @@ module.controller('admintool.EditUserRoleDialogController', [ $modalInstance.close(user); return; } - updateMethod = $adminToolService.updateCopilot(v2Token, updatedUser); + updateMethod = $adminToolService.updateCopilot(updatedUser); } if ($scope.form.isReviewer()) { if ($scope.form.editImmune) { @@ -369,7 +351,7 @@ module.controller('admintool.EditUserRoleDialogController', [ $modalInstance.close(user); return; } - updateMethod = $adminToolService.updateReviewer(v2Token, { + updateMethod = $adminToolService.updateReviewer({ username: user.name, categoryId: categoryId }, updatedUser); diff --git a/src/app/admintool/admintool.html b/src/app/admintool/admintool.html index f2107ac..8d1c6c0 100644 --- a/src/app/admintool/admintool.html +++ b/src/app/admintool/admintool.html @@ -32,20 +32,20 @@

    Admins / Copilots / Reviewers

    + ng-model="formSearch.handle" ng-disabled="formSearch.isLoading" ng-trim="true">
    @@ -53,7 +53,7 @@

    Admins / Copilots / Reviewers

    diff --git a/src/app/admintool/admintool.service.js b/src/app/admintool/admintool.service.js index 2cc400b..05f9091 100644 --- a/src/app/admintool/admintool.service.js +++ b/src/app/admintool/admintool.service.js @@ -4,7 +4,6 @@ angular.module('supportAdminApp') .factory('AdminToolService', ['$log', '$q', '$http', 'ADMIN_TOOL_URL', 'API_URL', 'API_VERSION_PATH', function ($log, $q, $http, ADMIN_TOOL_URL, API_URL, API_VERSION_PATH) { var service = { - getV2Token: getV2Token, findAdmins: findAdmins, createAdmin: createAdmin, deleteAdmin: deleteAdmin, @@ -19,45 +18,6 @@ angular.module('supportAdminApp') findReviewBoardProjectCategories: findReviewBoardProjectCategories }; - /** - * Get v2 token with v3 token - */ - function getV2Token() { - return $http({ - method: 'GET', - url: API_URL + '/' + API_VERSION_PATH + '/authorizations/1' - }).then( - function (response) { - $log.debug(response); - if (response.data && response.data.result && response.data.result.content - && response.data.result.content.externalToken) { - return response.data.result.content.externalToken; - } else { - return $q.reject({ - error: 'Cannot find v2 token in response.' - }); - } - }, - function (error) { - $log.error(error); - var err; - if (error && error.data && error.data.result) { - err = { - status: error.status, - error: error.data.result.content - }; - } - if (!err) { - err = { - status: error.status, - error: error.statusText - }; - } - return $q.reject(err); - } - ); - } - /** * helper function to process http request */ @@ -105,13 +65,12 @@ angular.module('supportAdminApp') /** * Find admins */ - function findAdmins(token) { + function findAdmins() { var request = $http({ method: 'GET', url: ADMIN_TOOL_URL + '/admin/admins', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token } }); return _processRequest(request, 'allAdmins'); @@ -120,13 +79,12 @@ angular.module('supportAdminApp') /** * creates admin user */ - function createAdmin(token, data) { + function createAdmin(data) { var request = $http({ method: 'POST', url: ADMIN_TOOL_URL + '/admin/admins', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token }, data: angular.toJson(data) }); @@ -136,13 +94,12 @@ angular.module('supportAdminApp') /** * Delete an existing admin user */ - function deleteAdmin(token, data) { + function deleteAdmin(data) { var request = $http({ method: "DELETE", url: ADMIN_TOOL_URL + "/admin/admins", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token }, data: angular.toJson(data) }); @@ -153,13 +110,12 @@ angular.module('supportAdminApp') /** * Find copilots */ - function findCopilots(token) { + function findCopilots() { var request = $http({ method: 'GET', url: ADMIN_TOOL_URL + '/admin/copilots', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token } }); return _processRequest(request, 'allCopilots'); @@ -168,13 +124,12 @@ angular.module('supportAdminApp') /** * creates copilot */ - function createCopilot(token, data) { + function createCopilot(data) { var request = $http({ method: 'POST', url: ADMIN_TOOL_URL + '/admin/copilots', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token }, data: angular.toJson(data) }); @@ -184,13 +139,12 @@ angular.module('supportAdminApp') /** * Delete copilot */ - function deleteCopilot(token, data) { + function deleteCopilot(data) { var request = $http({ method: "DELETE", url: ADMIN_TOOL_URL + "/admin/copilots", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token }, data: angular.toJson(data) }); @@ -200,9 +154,9 @@ angular.module('supportAdminApp') /** * Update copilot */ - function updateCopilot(token, data) { - return deleteCopilot(token, data).then(function () { - return createCopilot(token, data); + function updateCopilot(data) { + return deleteCopilot(data).then(function () { + return createCopilot(data); }); } @@ -210,7 +164,7 @@ angular.module('supportAdminApp') /** * Find Reviewers */ - function findReviewers(token, categoryId) { + function findReviewers(categoryId) { var request = $http({ method: 'GET', url: ADMIN_TOOL_URL + '/admin/reviewers', @@ -219,7 +173,6 @@ angular.module('supportAdminApp') }, headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token } }); return _processRequest(request, 'reviewers'); @@ -229,13 +182,12 @@ angular.module('supportAdminApp') /** * creates Reviewer */ - function createReviewer(token, data) { + function createReviewer(data) { var request = $http({ method: 'POST', url: ADMIN_TOOL_URL + '/admin/reviewers', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token }, data: angular.toJson(data) }); @@ -245,13 +197,12 @@ angular.module('supportAdminApp') /** * Delete Reviewer */ - function deleteReviewer(token, data) { + function deleteReviewer(data) { var request = $http({ method: "DELETE", url: ADMIN_TOOL_URL + "/admin/reviewers", headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token }, data: angular.toJson(data) }); @@ -262,10 +213,10 @@ angular.module('supportAdminApp') /** * Update Reviewer */ - function updateReviewer(token, oldReviewer, newReviewer) { - var requests = [deleteReviewer(token, oldReviewer)]; + function updateReviewer(oldReviewer, newReviewer) { + var requests = [deleteReviewer(oldReviewer)]; if (oldReviewer.categoryId !== newReviewer.categoryId) { - requests.push(deleteReviewer(token, { + requests.push(deleteReviewer({ username: newReviewer.username, categoryId: newReviewer.categoryId }).catch(function (error) { @@ -277,27 +228,25 @@ angular.module('supportAdminApp') } return $q.all(requests).then(function () { delete newReviewer.id; - return createReviewer(token, newReviewer) + return createReviewer(newReviewer) }); } /** * Find review board project categories */ - function findReviewBoardProjectCategories(token) { + function findReviewBoardProjectCategories() { var request = $q.all([$http({ method: 'GET', url: ADMIN_TOOL_URL + '/develop/challengetypes', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token } }), $http({ method: 'GET', url: ADMIN_TOOL_URL + '/design/challengetypes', headers: { "Content-Type": "application/json", - "Authorization": "Bearer " + token } })]); return _processRequest(request); diff --git a/src/app/app.js b/src/app/app.js index d0b8817..ab61105 100755 --- a/src/app/app.js +++ b/src/app/app.js @@ -4,292 +4,327 @@ * support-admin-app */ angular.module('supportAdminApp', [ - 'ngAnimate', - 'ngCookies', - 'ngTouch', - 'ngSanitize', - 'ngResource', - 'csvReader', - 'ui.router', - 'ui.bootstrap', - 'app.constants', - 'appirio-tech-ng-api-services', - 'appirio-tech-ng-auth', - 'angular-clipboard', - 'ng-file-model', - 'ui.multiselect', - 'ui.bootstrap.datetimepicker', - 'angularMoment']) + 'ngAnimate', + 'ngCookies', + 'ngTouch', + 'ngSanitize', + 'ngResource', + 'csvReader', + 'ui.router', + 'ui.bootstrap', + 'app.constants', + 'angular-clipboard', + 'ng-file-model', + 'ui.multiselect', + 'ui.bootstrap.datetimepicker', + 'angularMoment', + 'angular-jwt']) // In the run phase of your Angular application - .run(function ($rootScope, $location, AuthService, $state, UserV3Service) { - // Listen to '$locationChangeSuccess', not '$stateChangeStart' - $rootScope.$on('$stateChangeStart', function (event, toState, toParams, fromState, fromParams) { - if (toState.name === 'login') { - return; - } - console.log('state changed. loggedIn: ' + AuthService.isLoggedIn()); // debug - if (!AuthService.isLoggedIn()) { - $state.go('login'); - } else { - UserV3Service.loadUser().then(function (currentUser) { - $rootScope.currentUser = currentUser; - $state.go(toState, toParams); - }); - } - }); + .run(function (AuthService) { + // init AuthService, it has to be done once, when app starts + AuthService.init(); }) .config(function ($stateProvider, $urlRouterProvider, $locationProvider) { - $stateProvider - .state('login', { - url: '/login', - templateUrl: 'app/login/login.html', - data: { pageTitle: 'Login' } - }) - .state('index', { - abstract: true, - url: '/index', - templateUrl: 'components/common/content.html' - }) - .state('index.main', { - url: '/main', - templateUrl: 'app/main/main.html', - data: { pageTitle: 'Dashboard' } - }) - .state('index.users', { - url: '/users', - templateUrl: 'app/users/users.html', - data: { pageTitle: 'User Management' } - }) - .state('index.admintool', { - url: '/admintool', - templateUrl: 'app/admintool/admintool.html', - data: { pageTitle: 'Admins / Copilots / Reviewers Management' } - }) - .state('index.sso', { - url: '/sso', - templateUrl: 'app/sso/sso.html', - data: { pageTitle: 'SSO User Management' } - }) - .state('index.addmembers', { - url: '/add', - templateUrl: 'app/addmembers/add.html', - data: { pageTitle: 'User Management' } - }) - .state('index.permission_management', { - url: '/permission_management', - templateUrl: 'app/permission_management/permission_management.html', - data: { pageTitle: 'Permission Management' }, - controller: 'PermissionManagementCtrl', - controllerAs: 'ctrl', - }) - .state('index.submissions', { - abstract: true, - url: '/submissions', - templateUrl: 'app/submissions/submissions.html', - data: { pageTitle: 'Submissions' } - }) - .state('index.submissions.list', { - url: '/list', - templateUrl: 'app/submissions/submissions.list.html', - data: { pageTitle: 'Submissions List' }, - controller: 'SubmissionListCtrl' - }) - .state('index.submissions.new', { - url: '/new', - templateUrl: 'app/submissions/submissions.new.html', - controller: 'NewSubmissionCtrl', - data: { pageTitle: 'New Submission' } - }) - .state('index.tags', { - abstract: true, - url: '/tags', - templateUrl: 'app/tags/tags.html', - data: { pageTitle: 'Tags' }, - controller: function ($scope, $state, TagService) { - $scope.$state = $state; - $scope.tagDomains = [{ - value: 'skills', - name: 'Skills' - }, { - value: 'events', - name: 'Events' - }, { - value: 'technology', - name: 'Technology' - }, { - value: 'platform', - name: 'Platform' - }]; + var authenticate = ['AuthService', '$q', '$state', function(AuthService, $q, $state) { + return AuthService.authenticate().catch(function(err) { + // if we get error that use doesn't have permissions + // then go to auth page, which will show permissions denied error + if (err === AuthService.ERROR.NO_PERMISSIONS) { + $state.go('auth'); + } + return $q.reject(); + }); + }]; - $scope.tagCategories = [{ - value: 'data_science', - name: 'Data Science' - }, { - value: 'develop', - name: 'Develop' - }, - { - value: 'design', - name: 'Design' - }]; + $stateProvider + .state('auth', { + url: '/auth', + templateUrl: 'app/auth/auth.html', + data: { pageTitle: 'Authentication' }, + resolve: { + auth: ['AuthService', '$q', function(AuthService, $q) { + // for auth state we use another resolver then all other states + return AuthService.authenticate().catch(function(err) { + // if we get error that use doesn't have permissions + // we still resolve the promise and proceed to auth page + // which will show permissions denied error + // also we keep going if we are in loging out process + if (err === AuthService.ERROR.NO_PERMISSIONS || AuthService.logginOut) { + return $q.resolve(); + } + return $q.reject(); + }); + }] + } + }) + .state('index', { + abstract: true, + url: '/index', + templateUrl: 'components/common/content.html' + }) + .state('index.main', { + url: '/main', + templateUrl: 'app/main/main.html', + data: { pageTitle: 'Dashboard' }, + resolve: { auth: authenticate } + }) + .state('index.users', { + url: '/users', + templateUrl: 'app/users/users.html', + data: { pageTitle: 'User Management' }, + resolve: { auth: authenticate } + }) + .state('index.admintool', { + url: '/admintool', + templateUrl: 'app/admintool/admintool.html', + data: { pageTitle: 'Admins / Copilots / Reviewers Management' }, + resolve: { auth: authenticate } + }) + .state('index.sso', { + url: '/sso', + templateUrl: 'app/sso/sso.html', + data: { pageTitle: 'SSO User Management' }, + resolve: { auth: authenticate } + }) + .state('index.addmembers', { + url: '/add', + templateUrl: 'app/addmembers/add.html', + data: { pageTitle: 'User Management' }, + resolve: { auth: authenticate } + }) + .state('index.permission_management', { + url: '/permission_management', + templateUrl: 'app/permission_management/permission_management.html', + data: { pageTitle: 'Permission Management' }, + controller: 'PermissionManagementCtrl', + controllerAs: 'ctrl', + resolve: { auth: authenticate } + }) + .state('index.submissions', { + abstract: true, + url: '/submissions', + templateUrl: 'app/submissions/submissions.html', + data: { pageTitle: 'Submissions' } + }) + .state('index.submissions.list', { + url: '/list', + templateUrl: 'app/submissions/submissions.list.html', + data: { pageTitle: 'Submissions List' }, + controller: 'SubmissionListCtrl', + resolve: { auth: authenticate } + }) + .state('index.submissions.new', { + url: '/new', + templateUrl: 'app/submissions/submissions.new.html', + controller: 'NewSubmissionCtrl', + data: { pageTitle: 'New Submission' }, + resolve: { auth: authenticate } + }) + .state('index.tags', { + abstract: true, + url: '/tags', + templateUrl: 'app/tags/tags.html', + data: { pageTitle: 'Tags' }, + controller: function ($scope, $state, TagService) { + $scope.$state = $state; + $scope.tagDomains = [{ + value: 'skills', + name: 'Skills' + }, { + value: 'events', + name: 'Events' + }, { + value: 'technology', + name: 'Technology' + }, { + value: 'platform', + name: 'Platform' + }]; - $scope.tagStatuses = [{ - value: 'approved', - name: 'Approved' - }, { - value: 'pending', - name: 'Pending' + $scope.tagCategories = [{ + value: 'data_science', + name: 'Data Science' + }, { + value: 'develop', + name: 'Develop' + }, + { + value: 'design', + name: 'Design' }]; - TagService.getTechnologyStatuses().then(function(techStatuses) { - _.forEach(techStatuses, function(status) { - status.value = _.lowerCase(status.description); - status.name = status.description; - }); - $scope.techStatuses = techStatuses; + $scope.tagStatuses = [{ + value: 'approved', + name: 'Approved' + }, { + value: 'pending', + name: 'Pending' + }]; + + TagService.getTechnologyStatuses().then(function(techStatuses) { + _.forEach(techStatuses, function(status) { + status.value = _.lowerCase(status.description); + status.name = status.description; }); - $scope.getTagStatuses = function(domainType) { - if (domainType === 'technology') { - return $scope.techStatuses; - } else { - return $scope.tagStatuses; - } + $scope.techStatuses = techStatuses; + }); + $scope.getTagStatuses = function(domainType) { + if (domainType === 'technology') { + return $scope.techStatuses; + } else { + return $scope.tagStatuses; } } - }) - .state('index.tags.list', { - url: '/list', - templateUrl: 'app/tags/tags.list.html', - controller: 'TagListCtrl' - }) - .state('index.tags.new', { - url: '/new', - templateUrl: 'app/tags/tags.new.html', - controller: 'NewTagCtrl', - data: { pageTitle: 'New Tag' } - }) - .state('index.tags.edit', { - url: '/edit/:tagId', - templateUrl: 'app/tags/tags.edit.html', - controller: 'EditTagCtrl', - data: { pageTitle: 'Edit Tag' } - }) - .state('index.work', { - abstract: true, - url: '/work', - templateUrl: 'app/work/work.html', - data: { pageTitle: 'Work Items Management' } - }) - .state('index.work.list', { - url: '/list/:id', - views: { - 'work-details': { - templateUrl: 'app/work/work.details.html' - }, - 'work-list': { - templateUrl: 'app/work/work.list.html', - data: { pageTitle: 'work List' }, - controller: 'WorkListCtrl', - params: { - id: '' - } - }, - 'work-messages': { - templateUrl: 'app/work/work.messages.html', - controller: 'projectController' + } + }) + .state('index.tags.list', { + url: '/list', + templateUrl: 'app/tags/tags.list.html', + controller: 'TagListCtrl', + resolve: { auth: authenticate } + }) + .state('index.tags.new', { + url: '/new', + templateUrl: 'app/tags/tags.new.html', + controller: 'NewTagCtrl', + data: { pageTitle: 'New Tag' }, + resolve: { auth: authenticate } + }) + .state('index.tags.edit', { + url: '/edit/:tagId', + templateUrl: 'app/tags/tags.edit.html', + controller: 'EditTagCtrl', + data: { pageTitle: 'Edit Tag' }, + resolve: { auth: authenticate } + }) + .state('index.work', { + abstract: true, + url: '/work', + templateUrl: 'app/work/work.html', + data: { pageTitle: 'Work Items Management' } + }) + .state('index.work.list', { + url: '/list/:id', + views: { + 'work-details': { + templateUrl: 'app/work/work.details.html' + }, + 'work-list': { + templateUrl: 'app/work/work.list.html', + data: { pageTitle: 'work List' }, + controller: 'WorkListCtrl', + params: { + id: '' } + }, + 'work-messages': { + templateUrl: 'app/work/work.messages.html', + controller: 'projectController' } - }) - .state('index.workStepEdit', { - url: '/work/:id/:stepId', - templateUrl: 'app/work/workStepEdit.html', - data: { pageTitle: 'Edit Step' }, - controller: 'WorkStepEditCtrl', - params: { - id: '', - stepId: '' - } - }) - .state('index.projects', { - url: '/projects', - templateUrl: 'app/work/projects.html', - data: { pageTitle: 'Projects List' }, - controller: 'ProjectListCtrl', - controllerAs: 'vm' - }) - .state('index.clients', { - abstract: true, - url: '/clients', - templateUrl: 'app/clients/clients.html', - data: { pageTitle: 'Clients' }, - controller: 'billingaccount.ClientsController' - }) - .state('index.clients.list', { - url: '/list', - templateUrl: 'app/clients/clients.list.html', - controller: 'billingaccount.ClientsListController' - }) - .state('index.clients.new', { - url: '/new', - templateUrl: 'app/clients/clients.new.html', - controller: 'billingaccount.NewClientController', - data: { pageTitle: 'New Client' } - }) - .state('index.clients.edit', { - url: '/edit/:clientId', - templateUrl: 'app/clients/clients.edit.html', - controller: 'billingaccount.EditClientController', - data: { pageTitle: 'Edit Client' } - }) - .state('index.billingaccounts', { - abstract: true, - url: '/billingaccounts', - templateUrl: 'app/billing_accounts/billingaccounts.html', - data: { pageTitle: 'Billing Accounts' }, - controller: 'billingaccount.BillingAccountsController' - }) - .state('index.billingaccounts.list', { - url: '/list', - templateUrl: 'app/billing_accounts/billingaccounts.list.html', - controller: 'billingaccount.BillingAccountsListController' - }) - .state('index.billingaccounts.new', { - url: '/new', - templateUrl: 'app/billing_accounts/billingaccounts.new.html', - controller: 'billingaccount.NewBillingAccountController', - data: { pageTitle: 'New Billing Account' } - }) - .state('index.billingaccounts.edit', { - url: '/edit/:accountId', - templateUrl: 'app/billing_accounts/billingaccounts.edit.html', - controller: 'billingaccount.EditBillingAccountController', - data: { pageTitle: 'Edit Billing Account' } - }) - .state('index.billingaccounts.view', { - url: '/view/:accountId', - templateUrl: 'app/billing_accounts/billingaccounts.view.html', - controller: 'billingaccount.ViewBillingAccountController', - data: { pageTitle: 'Details - Billing Account' } - }) - .state('index.billingaccountresources', { - abstract: true, - url: '/billingaccountresources', - templateUrl: 'app/billing_account_resources/billingaccountresources.html', - data: { pageTitle: 'Billing Account Resources' }, - controller: 'billingaccount.BillingAccountResourcesController' - }) - .state('index.billingaccountresources.list', { - url: '/list/:accountId', - templateUrl: 'app/billing_account_resources/billingaccountresources.list.html', - controller: 'billingaccount.BillingAccountResourcesListController' - }) - .state('index.billingaccountresources.new', { - url: '/:accountId/new', - templateUrl: 'app/billing_account_resources/billingaccountresources.new.html', - controller: 'billingaccount.NewBillingAccountResourceController', - data: { pageTitle: 'New Billing Account Resource' } - }); + }, + resolve: { auth: authenticate } + }) + .state('index.workStepEdit', { + url: '/work/:id/:stepId', + templateUrl: 'app/work/workStepEdit.html', + data: { pageTitle: 'Edit Step' }, + controller: 'WorkStepEditCtrl', + params: { + id: '', + stepId: '' + }, + resolve: { auth: authenticate } + }) + .state('index.projects', { + url: '/projects', + templateUrl: 'app/work/projects.html', + data: { pageTitle: 'Projects List' }, + controller: 'ProjectListCtrl', + controllerAs: 'vm', + resolve: { auth: authenticate } + }) + .state('index.clients', { + abstract: true, + url: '/clients', + templateUrl: 'app/clients/clients.html', + data: { pageTitle: 'Clients' }, + controller: 'billingaccount.ClientsController' + }) + .state('index.clients.list', { + url: '/list', + templateUrl: 'app/clients/clients.list.html', + controller: 'billingaccount.ClientsListController', + resolve: { auth: authenticate } + }) + .state('index.clients.new', { + url: '/new', + templateUrl: 'app/clients/clients.new.html', + controller: 'billingaccount.NewClientController', + data: { pageTitle: 'New Client' }, + resolve: { auth: authenticate } + }) + .state('index.clients.edit', { + url: '/edit/:clientId', + templateUrl: 'app/clients/clients.edit.html', + controller: 'billingaccount.EditClientController', + data: { pageTitle: 'Edit Client' }, + resolve: { auth: authenticate } + }) + .state('index.billingaccounts', { + abstract: true, + url: '/billingaccounts', + templateUrl: 'app/billing_accounts/billingaccounts.html', + data: { pageTitle: 'Billing Accounts' }, + controller: 'billingaccount.BillingAccountsController' + }) + .state('index.billingaccounts.list', { + url: '/list', + templateUrl: 'app/billing_accounts/billingaccounts.list.html', + controller: 'billingaccount.BillingAccountsListController', + resolve: { auth: authenticate } + }) + .state('index.billingaccounts.new', { + url: '/new', + templateUrl: 'app/billing_accounts/billingaccounts.new.html', + controller: 'billingaccount.NewBillingAccountController', + data: { pageTitle: 'New Billing Account' }, + resolve: { auth: authenticate } + }) + .state('index.billingaccounts.edit', { + url: '/edit/:accountId', + templateUrl: 'app/billing_accounts/billingaccounts.edit.html', + controller: 'billingaccount.EditBillingAccountController', + data: { pageTitle: 'Edit Billing Account' }, + resolve: { auth: authenticate } + }) + .state('index.billingaccounts.view', { + url: '/view/:accountId', + templateUrl: 'app/billing_accounts/billingaccounts.view.html', + controller: 'billingaccount.ViewBillingAccountController', + data: { pageTitle: 'Details - Billing Account' }, + resolve: { auth: authenticate } + }) + .state('index.billingaccountresources', { + abstract: true, + url: '/billingaccountresources', + templateUrl: 'app/billing_account_resources/billingaccountresources.html', + data: { pageTitle: 'Billing Account Resources' }, + controller: 'billingaccount.BillingAccountResourcesController' + }) + .state('index.billingaccountresources.list', { + url: '/list/:accountId', + templateUrl: 'app/billing_account_resources/billingaccountresources.list.html', + controller: 'billingaccount.BillingAccountResourcesListController', + resolve: { auth: authenticate } + }) + .state('index.billingaccountresources.new', { + url: '/:accountId/new', + templateUrl: 'app/billing_account_resources/billingaccountresources.new.html', + controller: 'billingaccount.NewBillingAccountResourceController', + data: { pageTitle: 'New Billing Account Resource' }, + resolve: { auth: authenticate } + }); - $urlRouterProvider.otherwise('/login'); + $urlRouterProvider.otherwise('/index/main'); // $locationProvider.html5Mode(true).hashPrefix('!'); }); diff --git a/src/app/auth/auth.config.js b/src/app/auth/auth.config.js new file mode 100644 index 0000000..27496f0 --- /dev/null +++ b/src/app/auth/auth.config.js @@ -0,0 +1,65 @@ +'use strict'; + +/** + * Inject JWT token into http requests + * + * It inject token V2 for requests to API V2 + * and token V3 for requests to API V3 + */ + +angular.module('supportAdminApp') + .config(function($httpProvider, jwtInterceptorProvider) { + var refreshingToken = null; + + jwtInterceptorProvider.tokenGetter = [ + 'AuthService', '$http', 'API_URL', 'ADMIN_TOOL_URL', 'config', + function($authService, $http, API_URL, ADMIN_TOOL_URL, config) { + // token V2 for API V2 + if (config.url.indexOf(ADMIN_TOOL_URL) > -1) { + if ($authService.getTokenV2()) { + return $authService.getTokenV2(); + } else { + $authService.login(); + } + + // token V3 for API V3 + } else { + var currentToken = $authService.getTokenV3(); + + function handleRefreshResponse(res) { + var newToken, ref, ref1, ref2; + + newToken = (ref = res.data) != null ? (ref1 = ref.result) != null ? (ref2 = ref1.content) != null ? ref2.token : void 0 : void 0 : void 0; + + $authService.setTokenV3(newToken); + + return newToken; + }; + + function refreshingTokenComplete() { + return refreshingToken = null; + }; + + if ($authService.getTokenV3() && $authService.isTokenV3Expired()) { + if (refreshingToken === null) { + refreshingToken = $http({ + method: 'GET', + url: API_URL + "/v3/authorizations/1", + headers: { + 'Authorization': "Bearer " + currentToken + } + }) + .then(handleRefreshResponse)["finally"](refreshingTokenComplete) + .catch(function() { + $authService.login(); + }); + } + return refreshingToken; + } else { + return currentToken; + } + } + }]; + + return $httpProvider.interceptors.push('jwtInterceptor'); + }); diff --git a/src/app/auth/auth.controller.js b/src/app/auth/auth.controller.js new file mode 100644 index 0000000..69a4b7e --- /dev/null +++ b/src/app/auth/auth.controller.js @@ -0,0 +1,42 @@ +'use strict'; + +angular.module('supportAdminApp') + .controller('LoginController', [ + '$q', '$scope', '$state', 'AuthService', + function ($q, $scope, $state, $authService) { + + $scope.logginOut = false; + $scope.errorMessage = ''; + + function onLogOut() { + $authService.login(); + // we could stop loggin out indicator but we don't do it, because redirecting doesn't happen immediately + // so we keep showing loging out indicator even if log out already complete + // anyway we go from this page + // $scope.logginOut = false; + } + + // if we come to this page and user is logged in, and we are not loggin out + // then we shouldn't be on this page so we redirect to index + if ($authService.isLoggedIn() && !$authService.logginOut) { + $state.go('index.users'); + + // if we are loggin out currently, then show "loggin out..." message + } else if ($authService.logginOut) { + $scope.logginOut = true; + $authService.logginOut.then(onLogOut); + + // as we come to this page after AuthService.authenticate() + // the only one case when we can come to this page now if access was denied for current user + // so we show permissions denied error + } else { + $scope.errorMessage = $authService.ERROR.NO_PERMISSIONS; + } + + $scope.logout = function() { + $scope.errorMessage = ''; + $scope.logginOut = true; + $authService.logout().then(onLogOut); + } + + }]); diff --git a/src/app/auth/auth.html b/src/app/auth/auth.html new file mode 100644 index 0000000..b302ab6 --- /dev/null +++ b/src/app/auth/auth.html @@ -0,0 +1,23 @@ +
    +
    + +
    +
    diff --git a/src/app/auth/auth.service.js b/src/app/auth/auth.service.js new file mode 100644 index 0000000..46dffd4 --- /dev/null +++ b/src/app/auth/auth.service.js @@ -0,0 +1,275 @@ +'use strict'; + +angular.module('supportAdminApp') + .factory('AuthService', [ + '$q', '$log', 'jwtHelper', '$cookies', '$window', '$state', 'AUTH_URL', 'ACCOUNTS_CONNECTOR_URL', 'COOKIES_SECURE', 'JWT_V3_NAME', 'JWT_V2_NAME', + function($q, $log, jwtHelper, $cookies, $window, $state, AUTH_URL, ACCOUNTS_CONNECTOR_URL, COOKIES_SECURE, JWT_V3_NAME, JWT_V2_NAME) { + // these constants are for AuthService internal usage only + // they don't depend on the environment thus don't have to be placed in global config + var GET_FRESH_TOKEN_REQUEST = 'GET_FRESH_TOKEN_REQUEST'; + var GET_FRESH_TOKEN_SUCCESS = 'GET_FRESH_TOKEN_SUCCESS'; + var GET_FRESH_TOKEN_FAILURE = 'GET_FRESH_TOKEN_FAILURE'; + + var LOGOUT_REQUEST = 'LOGOUT_REQUEST'; + var LOGOUT_SUCCESS = 'LOGOUT_SUCCESS'; + var LOGOUT_FAILURE = 'LOGOUT_FAILURE'; + + // local variables + var connectorIFrame, url, loading; + + /** + * Create invisible iframe and append it to the body + * + * @param {String} id iframe tag id + * @param {String} src iframe source + * @return {HTMLElement} dom element of the iframe + */ + function createFrame(id, src) { + + var iframe = document.createElement('iframe'); + + iframe.id = id; + iframe.src = src; + iframe.width = 0; + iframe.height = 0; + iframe.frameborder = 0; + + // set inline style cross-browser way to make iframe completely invisible + angular.element(iframe).css({ + display: 'block', + border: '0' + }) + + document.body.appendChild(iframe); + + return iframe; + } + + /** + * Proxies calls to the iframe from main window + * + * @param {String} REQUEST request id + * @param {String} SUCCESS success respond id + * @param {String} FAILURE failure respond id + * @param {Object} params params of the request + * @return {Promise} promise of the request + */ + function proxyCall(REQUEST, SUCCESS, FAILURE, params) { + if (!connectorIFrame) { + throw new Error('connector has not yet been configured.') + } + + var params = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; + + function request() { + return $q(function(resolve, reject) { + function receiveMessage(e) { + var safeFormat = e.data.type === SUCCESS || e.data.type === FAILURE + if (safeFormat) { + window.removeEventListener('message', receiveMessage) + if (e.data.type === SUCCESS) resolve(e.data) + if (e.data.type === FAILURE) reject(e.error) + } + } + + window.addEventListener('message', receiveMessage) + + var payload = $.extend({}, { type: REQUEST }, params) + + connectorIFrame.contentWindow.postMessage(payload, url) + }) + } + + return loading.then(request) + } + + /** + * Create invisible iframe which will be used to retrieve token v3 + * + * @param {Object} options frameId and connectorUrl for the iframe + * @return {Promise} promise on iframe load + */ + function configureConnector(options) { + if (connectorIFrame) { + $log.warn('iframe connector can only be configured once, this request has been ignored.') + } else { + connectorIFrame = createFrame(options.frameId, options.connectorUrl) + url = options.connectorUrl + + loading = $q(function(resolve) { + connectorIFrame.onload = function() { + resolve() + } + }) + } + } + + var AuthService = { + ERROR: { + NO_PERMISSIONS: 'Current user doesn\'t have administrator permissions.' + } + }; + + /** + * Returns promise which is resolved when connector iframe is loaded + * + * @return {Promise} + */ + AuthService.ready = function() { + if (!connectorIFrame) { + throw new Error('AuthService.init() has to be called once when app run before any other methods of AuthService.'); + } + + return loading; + } + + /** + * Retrieves new token v3 using hidden iframe + * check that user has administrator credentials and save it to the cookies + * + * @return {Promise} promise to get token v3 + */ + AuthService.retriveFreshToken = function() { + return proxyCall(GET_FRESH_TOKEN_REQUEST, GET_FRESH_TOKEN_SUCCESS, GET_FRESH_TOKEN_FAILURE) + .then(function(data) { + var user = jwtHelper.decodeToken(data.token); + + if ($.inArray('administrator', user && user.roles) < 0) { + return $q.reject(AuthService.ERROR.NO_PERMISSIONS); + } else { + AuthService.setTokenV3(data.token); + } + }); + } + + /** + * Log out user + * Clear cookies and send request to the server for log out + * + * @return {Promise} promise which is resolved when user is logged out on the server + */ + AuthService.logout = function() { + // send request to the server that we want to log out + // save logginOut promise to be accessed any time + AuthService.logginOut = proxyCall(LOGOUT_REQUEST, LOGOUT_SUCCESS, LOGOUT_FAILURE).then(function() { + AuthService.logginOut = null; + }); + // remove only token V3, which we set from the script manually + // token V2 will be removed automatically during logout server request + $cookies.remove(JWT_V3_NAME); + + return AuthService.logginOut; + } + + AuthService.login = function() { + $window.location.href = AUTH_URL + '?retUrl=' + encodeURIComponent($window.location.href); + } + + /** + * Init auth service + * This has to called once when app starts + */ + AuthService.init = function() { + // add hidden iframe which is used to get API v3 token + configureConnector({ + connectorUrl: ACCOUNTS_CONNECTOR_URL, + frameId: 'tc-accounts-iframe', + }); + } + + /** + * Checks if user is already login or not + * If usr is not login, then redirect to TopCoder login form + * + * @return {Promise} promise to authenticate + */ + AuthService.authenticate = function() { + return AuthService.ready().then(function() { + if (AuthService.isLoggedIn()) { + return $q.resolve(); + } else { + if (AuthService.getTokenV2()) { + return AuthService.retriveFreshToken().catch(function(err) { + // if error about permission denied we will pass this error through + // otherwise got to login page + if (err !== AuthService.ERROR.NO_PERMISSIONS) { + AuthService.login(); + } + return $q.reject(err); + }); + } else { + AuthService.login(); + return $q.reject(); + } + } + }); + } + + /** + * Returns token v3 or null + * + * @return {String} token v3 + */ + AuthService.getTokenV3 = function() { + return $cookies.get(JWT_V3_NAME); + } + + /** + * Save token V3 to cookies + */ + AuthService.setTokenV3 = function(token) { + return $cookies.put(JWT_V3_NAME, token, { + secure: COOKIES_SECURE, + }); + } + + /** + * Check if token V3 is expired or no + * + * @return {Boolean} true if token V3 is expired + */ + AuthService.isTokenV3Expired = function() { + return !AuthService.getTokenV3() || jwtHelper.isTokenExpired(AuthService.getTokenV3(), 300); + } + + /** + * Returns token v2 or null + * + * @return {String} token v2 + */ + AuthService.getTokenV2 = function() { + return $cookies.get(JWT_V2_NAME); + } + + /** + * Check if user is fully logged in + * + * @return {Boolean} true if user is logged in + */ + AuthService.isLoggedIn = function() { + // we have to ckeck only for token v3, as if have this one, it means we have and v2 also + return !!AuthService.getTokenV3(); + } + + /** + * Returns information of the current user, which is retrieved from token v3 + * + * @return {Object} current user object + */ + AuthService.getCurrentUser = function() { + var tctV3 = AuthService.getTokenV3(); + + if (!tctV3) { + return null; + } + + var currentUser = jwtHelper.decodeToken(tctV3); + currentUser.id = currentUser.userId; + currentUser.token = tctV3; + + return currentUser; + } + + return AuthService; + + }]); diff --git a/src/app/billing_account_resources/billingaccountresources.service.js b/src/app/billing_account_resources/billingaccountresources.service.js index 457848b..9186704 100644 --- a/src/app/billing_account_resources/billingaccountresources.service.js +++ b/src/app/billing_account_resources/billingaccountresources.service.js @@ -56,9 +56,11 @@ angular.module('supportAdminApp') var deferred = $q.defer(); $http({ method: 'POST', - data: { - userId: entity.userId - }, + data: angular.toJson({ + param: { + userId: entity.userId + } + }), headers: { 'Content-Type': 'application/json' }, diff --git a/src/app/billing_accounts/billingaccounts.service.js b/src/app/billing_accounts/billingaccounts.service.js index 7cf084f..3e4654c 100644 --- a/src/app/billing_accounts/billingaccounts.service.js +++ b/src/app/billing_accounts/billingaccounts.service.js @@ -101,7 +101,9 @@ angular.module('supportAdminApp') var deferred = $q.defer(); $http({ method: 'POST', - data: request, + data: angular.toJson({ + param: request + }), headers: { 'Content-Type': 'application/json' }, @@ -123,7 +125,9 @@ angular.module('supportAdminApp') var deferred = $q.defer(); $http({ method: 'PATCH', - data: entity, + data: angular.toJson({ + param: entity + }), headers: { 'Content-Type': 'application/json' }, diff --git a/src/app/login/login.controller.js b/src/app/login/login.controller.js deleted file mode 100644 index f3a09bf..0000000 --- a/src/app/login/login.controller.js +++ /dev/null @@ -1,69 +0,0 @@ -'use strict'; - -angular.module('supportAdminApp') - .controller('LoginController', [ - '$log', '$scope', '$rootScope', '$location', '$state', 'AuthService', 'TokenService', 'UserService', 'Alert', - function ($log, $scope, $rootScope, $location, $state, $authService, $tokenService, $userService, $alert) { - - $scope.loggingIn = false; - - $scope.formLogin = { - username: null, - password: null, - loggingIn: false, - valid: function() { - return !!(this.username && this.username.length > 0 && - this.password && this.password.length > 0); - } - }; - - $scope.login = function() { - - $alert.clear(); - - var loginSuccess = function() { - var token = $tokenService.decodeToken(); - $log.debug(token); - if($.inArray('administrator', token && token.roles) < 0) { - $alert.error('Permission denied.', $scope); - $scope.formLogin.loggingIn = false; - return; - } - $userService.findById(token.userId).then( - function(currentUser) { - $rootScope.currentUser = currentUser; - $state.go('index.users'); - }, - function(err) { - $log.error('Failed to get user data.'); - $log.error(err); - $state.go('index.users'); - } - ); - }; - - var loginFailure = function(err) { - $log.error('Login Failed') - $log.error(err) - var reason = err && err.data && err.data.error, - msg = err && err.data && err.data.error_description || err.statusText; - if(reason === "invalid_user_password") { - msg = "Wrong username or password."; - } - $alert.error(msg, $scope); - $scope.formLogin.loggingIn = false; - }; - - var options = { - connection: "TC-User-Database", - username: $scope.formLogin.username, - password: $scope.formLogin.password, - success: loginSuccess, - error: loginFailure - }; - - $scope.formLogin.loggingIn = true; - $authService.login(options); - }; - - }]); diff --git a/src/app/login/login.html b/src/app/login/login.html deleted file mode 100755 index 0af6d1c..0000000 --- a/src/app/login/login.html +++ /dev/null @@ -1,33 +0,0 @@ -
    -
    - -
    -
    diff --git a/src/app/main/main.controller.js b/src/app/main/main.controller.js index 36d6843..59bbfda 100755 --- a/src/app/main/main.controller.js +++ b/src/app/main/main.controller.js @@ -6,11 +6,7 @@ angular.module('supportAdminApp') $scope.logout = function() { $authService.logout(); - $state.go('login'); - }; - - $scope.login = function() { - $state.go('login'); + $state.go('auth') }; // auth diff --git a/src/app/permission_management/permission_management.service.js b/src/app/permission_management/permission_management.service.js index bfd35af..febbd24 100644 --- a/src/app/permission_management/permission_management.service.js +++ b/src/app/permission_management/permission_management.service.js @@ -24,9 +24,16 @@ angular.module('supportAdminApp') * @return {Promise} Resolves to the created role object. */ Service.createRole = function(roleName) { - return $http.post(API_URL + '/v3/roles', { - param: { - roleName: roleName + return $http({ + method: 'POST', + url: API_URL + '/v3/roles', + data: angular.toJson({ + param: { + roleName: roleName + } + }), + headers: { + 'Content-Type': 'application/json' } }).then(function(res) { return res.data.result.content; diff --git a/src/app/tags/tags.edit.controller.js b/src/app/tags/tags.edit.controller.js index f079800..644d471 100755 --- a/src/app/tags/tags.edit.controller.js +++ b/src/app/tags/tags.edit.controller.js @@ -2,8 +2,8 @@ var module = angular.module('supportAdminApp'); -module.controller('EditTagCtrl', ['$rootScope','$scope', 'TagService', '$state','$stateParams', '$log', '$timeout', - function($rootScope, $scope, $tagService, $state, $stateParams, $log, $timeout) { +module.controller('EditTagCtrl', ['AuthService','$scope', 'TagService', '$state','$stateParams', '$log', '$timeout', + function($authService, $scope, $tagService, $state, $stateParams, $log, $timeout) { $scope.loading = true; $scope.processing = false; $scope.editTag = {}; @@ -39,7 +39,7 @@ module.controller('EditTagCtrl', ['$rootScope','$scope', 'TagService', '$state', $scope.submitTag = function() { $scope.$broadcast('alert.ClearAll', {}); $scope.processing = true; - $scope.editTag.updatedBy = $rootScope.currentUser.id; + $scope.editTag.updatedBy = $authService.getCurrentUser().id; $scope.editTag.synonyms = $scope.editForm.synonyms? $scope.editForm.synonyms.split(','):[]; $scope.editTag.categories = []; angular.forEach($scope.editCategories.options, function(c){ diff --git a/src/app/users/users.service.js b/src/app/users/users.service.js index 9c4499a..e8f3974 100644 --- a/src/app/users/users.service.js +++ b/src/app/users/users.service.js @@ -1,11 +1,11 @@ 'use strict'; angular.module('supportAdminApp') - .factory('UserService', ['$log', '$q','$http', 'User', 'API_URL', 'API_VERSION_PATH', + .factory('UserService', ['$log', '$q', '$http', 'User', 'API_URL', 'API_VERSION_PATH', function ($log, $q, $http, User, API_URL, API_VERSION_PATH) { // local dev //var API_URL = 'http://local.topcoder-dev.com:8080'; - + var UserService = {}; /** find user by ID */ @@ -208,7 +208,7 @@ angular.module('supportAdminApp') } ); }, // updateEmail() - + /** * updates a user status */ @@ -249,7 +249,7 @@ angular.module('supportAdminApp') } ); }; // updateStatus() - + /** get achievements for the specified user id */ UserService.getAchievements = function(userId) { if(!userId) { @@ -288,7 +288,7 @@ angular.module('supportAdminApp') } ); }; // getAchievements() - + /** * Instantiate a user object(s) */ @@ -303,8 +303,8 @@ angular.module('supportAdminApp') return User.createInstance(data); } }; - - + + /** get profile by handle */ UserService.getProfile = function(handle) { if(!handle) { @@ -343,10 +343,10 @@ angular.module('supportAdminApp') } ); }; // findById() - + UserService.getProfileEndpoint = function(handle) { return API_URL + '/'+API_VERSION_PATH+'/members/' + handle; } - + return UserService; }]); From d2a386d48d819fdd2a47283cdac239b758e34887 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 7 Jun 2017 14:35:13 +0800 Subject: [PATCH 25/25] Cleared one more file from unnecessary changes --- src/app/users/users.service.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/app/users/users.service.js b/src/app/users/users.service.js index e8f3974..9c4499a 100644 --- a/src/app/users/users.service.js +++ b/src/app/users/users.service.js @@ -1,11 +1,11 @@ 'use strict'; angular.module('supportAdminApp') - .factory('UserService', ['$log', '$q', '$http', 'User', 'API_URL', 'API_VERSION_PATH', + .factory('UserService', ['$log', '$q','$http', 'User', 'API_URL', 'API_VERSION_PATH', function ($log, $q, $http, User, API_URL, API_VERSION_PATH) { // local dev //var API_URL = 'http://local.topcoder-dev.com:8080'; - + var UserService = {}; /** find user by ID */ @@ -208,7 +208,7 @@ angular.module('supportAdminApp') } ); }, // updateEmail() - + /** * updates a user status */ @@ -249,7 +249,7 @@ angular.module('supportAdminApp') } ); }; // updateStatus() - + /** get achievements for the specified user id */ UserService.getAchievements = function(userId) { if(!userId) { @@ -288,7 +288,7 @@ angular.module('supportAdminApp') } ); }; // getAchievements() - + /** * Instantiate a user object(s) */ @@ -303,8 +303,8 @@ angular.module('supportAdminApp') return User.createInstance(data); } }; - - + + /** get profile by handle */ UserService.getProfile = function(handle) { if(!handle) { @@ -343,10 +343,10 @@ angular.module('supportAdminApp') } ); }; // findById() - + UserService.getProfileEndpoint = function(handle) { return API_URL + '/'+API_VERSION_PATH+'/members/' + handle; } - + return UserService; }]);