Skip to content

Commit 42b22ee

Browse files
author
James Cori
committed
Merge branch 'dev'
2 parents 8af41f2 + 039fe04 commit 42b22ee

18 files changed

+465
-74
lines changed

README.md

+2-4
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ The following configuration parameters are available:
4343
| TERMS_V5_API_URL | URL of the v5 Terms API |
4444
| CHALLENGES_V5_API_URL | URL of the v5 Challenges API |
4545
| RESOURCE_V5_API_URL | URL of the v5 Resources API |
46+
| MEMBER_V5_API_URL | URL of the v5 Member API |
4647
| AGREE_FOR_DOCUSIGN_TEMPLATE | UUID from Database of the `"DocuSign Template"` Agreeable type |
4748
| AGREE_ELECTRONICALLY | UUID from Database of the `Electronically` Agreeable Type |
4849
| DEFAULT_TERMS_TYPE_ID | The default terms type id |
@@ -54,15 +55,12 @@ The following configuration parameters are available:
5455

5556
## Start the Application
5657

57-
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.
58-
5958
Simply execute the following command to start the app in development mode (with browsersync)
6059
```
6160
npm install
62-
npm run build
6361
npm run dev
6462
```
65-
Application will be hosted and running at http://local.topcoder-dev.com:3000.
63+
Application will be hosted and running at http://localhost:3000.
6664

6765
## Execute E2E Tests
6866

config.json

+10-6
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,20 @@
44
"ADMIN_TOOL_URL": "https://api.topcoder-dev.com/v2",
55
"API_VERSION_PATH": "v3",
66
"COOKIES_SECURE": false,
7-
"AUTH_URL": "https://accounts.topcoder-dev.com/member",
8-
"ACCOUNTS_CONNECTOR_URL": "https://accounts.topcoder-dev.com/connector.html",
7+
"AUTH_URL": "http://localhost:5000",
8+
"ACCOUNTS_CONNECTOR_URL": "http://localhost:5000",
99
"JWT_V3_NAME": "v3jwt",
1010
"JWT_V2_NAME": "tcjwt",
1111
"OAUTH2_TOKEN_NAME": "oa2spigit",
1212
"OAUTH2_TOKEN_EXPIRETIME_TAGNAME": "oa2expire",
1313
"SPIGIT_API_URL": "spigit.com",
1414
"SPIGIT_API_VERSION_PATH": "/api/v1",
15-
"GROUP_V5_API_URL": "http://localhost:3000/v5",
16-
"LOOKUP_V5_API_URL": "http://localhost:3000/v5",
17-
"TERMS_V5_API_URL": "http://localhost:3000/v5",
15+
"GROUP_V5_API_URL": "https://api.topcoder-dev.com/v5",
16+
"LOOKUP_V5_API_URL": "https://api.topcoder-dev.com/v5",
17+
"TERMS_V5_API_URL": "https://api.topcoder-dev.com/v5",
1818
"CHALLENGES_V5_API_URL": "https://api.topcoder-dev.com/v5",
1919
"RESOURCE_V5_API_URL": "https://api.topcoder-dev.com/v5",
20+
"MEMBER_V5_API_URL": "https://api.topcoder-dev.com/v5",
2021
"AGREE_FOR_DOCUSIGN_TEMPLATE": "999a26ad-b334-453c-8425-165d4cf496d7",
2122
"AGREE_ELECTRONICALLY": "5b2798b2-ae82-4210-9b4d-5d6428125ccb",
2223
"DEFAULT_TERMS_TYPE_ID": 5,
@@ -43,6 +44,7 @@
4344
"TERMS_V5_API_URL": "https://api.topcoder-dev.com/v5",
4445
"CHALLENGES_V5_API_URL": "https://api.topcoder-dev.com/v5",
4546
"RESOURCE_V5_API_URL": "https://api.topcoder-dev.com/v5",
47+
"MEMBER_V5_API_URL": "https://api.topcoder-dev.com/v5",
4648
"AGREE_FOR_DOCUSIGN_TEMPLATE": "999a26ad-b334-453c-8425-165d4cf496d7",
4749
"AGREE_ELECTRONICALLY": "5b2798b2-ae82-4210-9b4d-5d6428125ccb",
4850
"DEFAULT_TERMS_TYPE_ID": 5,
@@ -69,6 +71,7 @@
6971
"TERMS_V5_API_URL": "http://localhost:3000/v5",
7072
"CHALLENGES_V5_API_URL": "https://api.topcoder-dev.com/v5",
7173
"RESOURCE_V5_API_URL": "https://api.topcoder-dev.com/v5",
74+
"MEMBER_V5_API_URL": "https://api.topcoder-dev.com/v5",
7275
"AGREE_FOR_DOCUSIGN_TEMPLATE": "999a26ad-b334-453c-8425-165d4cf496d7",
7376
"AGREE_ELECTRONICALLY": "5b2798b2-ae82-4210-9b4d-5d6428125ccb",
7477
"DEFAULT_TERMS_TYPE_ID": 5,
@@ -94,7 +97,8 @@
9497
"LOOKUP_V5_API_URL": "https://api.topcoder.com/v5",
9598
"TERMS_V5_API_URL": "https://api.topcoder.com/v5",
9699
"CHALLENGES_V5_API_URL": "https://api.topcoder.com/v5",
97-
"RESOURCE_V5_API_URL": "https://api.topcoder.com/v5",
100+
"RESOURCE_V5_API_URL": "https://api.topcoder.com/v5",
101+
"MEMBER_V5_API_URL": "https://api.topcoder.com/v5",
98102
"AGREE_FOR_DOCUSIGN_TEMPLATE": "1363a7ab-fd3e-4d7c-abbb-2f7440b8b355",
99103
"AGREE_ELECTRONICALLY": "2db6c920-4089-4755-9cd1-99b0df0af961",
100104
"DEFAULT_TERMS_TYPE_ID": 5,

gulp/server.js

+2-3
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,11 @@ function browserSyncInit(baseDir, files, browser) {
2828
routes: routes
2929
},
3030
browser: browser,
31-
host: 'local.topcoder-dev.com',
32-
open: 'external'
31+
host: 'localhost'
3332
});
3433
}
3534

36-
gulp.task('serve', ['watch'], function () {
35+
gulp.task('serve', ['ng-config', 'watch'], function () {
3736
browserSyncInit([
3837
paths.tmp + '/serve',
3938
paths.src

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
"browserify-css": "0.10.1",
4545
"browserify-shim": "^3.8.10",
4646
"chalk": "~0.5.1",
47+
"cross-env": "^5.2.1",
4748
"del": "~2.2.2",
4849
"ejsify": "1.0.0",
4950
"gulp": "^3.8.11",
@@ -89,6 +90,6 @@
8990
"build": "gulp build",
9091
"start": "gulp publish",
9192
"test": "gulp protractor",
92-
"dev": "gulp serve"
93+
"dev": "cross-env BUILD_ENV=local gulp serve"
9394
}
9495
}

src/app/challenges/challenges.service.js

+34-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
'use strict';
22

33
angular.module('supportAdminApp')
4-
.factory('ChallengeService', ['$q', '$http', 'API_URL', 'CHALLENGES_V5_API_URL', 'RESOURCE_V5_API_URL',
5-
function ($q, $http, API_URL, V5_API_URL, RESOURCE_V5_API_URL) {
4+
.factory('ChallengeService', ['$q', '$http', 'API_URL', 'CHALLENGES_V5_API_URL', 'RESOURCE_V5_API_URL', 'MEMBER_V5_API_URL', '$httpParamSerializer',
5+
function ($q, $http, API_URL, V5_API_URL, RESOURCE_V5_API_URL, MEMBER_V5_API_URL, $httpParamSerializer) {
66

77
var service = {
88
findChallengeById: findChallengeById,
@@ -17,6 +17,7 @@ angular.module('supportAdminApp')
1717
getChallengeByLegacyId: getChallengeByLegacyId,
1818
getChallengeResources: getChallengeResources,
1919
getResourceRoles: getResourceRoles,
20+
getResourceEmails: getResourceEmails,
2021
deleteChallengeResource: deleteChallengeResource,
2122
addChallengeResource: addChallengeResource
2223
}
@@ -380,6 +381,37 @@ angular.module('supportAdminApp')
380381
return deferred.promise;
381382
};
382383

384+
/**
385+
* gets a list of e-mails based on a list of users
386+
* @returns {Promise} the promise with a list of userIds and e-mails.
387+
*/
388+
function getResourceEmails(users) {
389+
var deferred = $q.defer();
390+
var qs = ""
391+
if (users.length > 1) {
392+
qs = $httpParamSerializer({
393+
userIds: users.map(function(user) { return user.memberId })
394+
});
395+
} else { // need to check if the list is made of just one user, in this case the qs parameter must be userId instead of userIds
396+
qs = $httpParamSerializer({
397+
userId: users.map(function(user) { return user.memberId })
398+
});
399+
}
400+
401+
$http({
402+
method: 'GET',
403+
url: MEMBER_V5_API_URL + '/members?' + qs + '&fields=userId,email&perPage=' + users.length,
404+
headers: {
405+
'Content-Type': 'application/json',
406+
}
407+
}).then(function (response) {
408+
deferred.resolve(response.data);
409+
}).catch(function (error) {
410+
handleError(error, deferred);
411+
});
412+
return deferred.promise;
413+
}
414+
383415
/**
384416
* delete the challenge resource.
385417
* @param {object} data the data.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
.multiple-member-handle {
2+
border: 1px solid #e5e6e7;
3+
background: #ffffff;
4+
display: flex;
5+
flex-wrap: wrap;
6+
padding: 3px 1px 3px 3px;
7+
flex: 1;
8+
9+
.multiple-member-handle-tag {
10+
display: inline-flex;margin: 0 2px 2px 0;
11+
height: 24px;
12+
align-items: center;
13+
font-size: 14px;
14+
font-weight: normal;
15+
}
16+
17+
.multiple-member-handle-input {
18+
border: 0px #ffffff;
19+
display: inline-flex;
20+
flex-grow: 1;
21+
width: 10%;
22+
min-width: 20px;
23+
height: 26px;
24+
padding: 0px;
25+
outline: none;
26+
box-shadow: none;
27+
}
28+
29+
a {
30+
color: #3333;
31+
margin-left:5px
32+
}
33+
}

src/app/less/style.less

+1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
// Components
3131
@import "challenge-users-stats.directive.less";
3232
@import "track-icon.directive.less";
33+
@import "multiple-member-handler.directive.less";
3334

3435
// Landing page styles
3536
@import "landing.less";

src/app/sso/sso.service.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ angular.module('supportAdminApp')
44
.factory('SSOService', ['$log', '$q','$http', 'API_URL',
55
function ($log, $q, $http, API_URL) {
66
// local dev
7-
// var API_URL = 'http://local.topcoder-dev.com:8080';
7+
// var API_URL = 'http://localhost:8080';
88
return ({
99
/* add sso user */
1010
addSSOUser: function(jsonInput, activate, showFullResponse) {
@@ -70,4 +70,4 @@ angular.module('supportAdminApp')
7070

7171
}, // addSSOUser()
7272
});
73-
}]);
73+
}]);

src/app/users/users.service.js

+21-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,9 @@ angular
1010
'API_URL',
1111
'API_VERSION_PATH',
1212
'helper',
13-
function ($log, $q, $http, User, API_URL, API_VERSION_PATH, helper) {
14-
// local dev var API_URL = 'http://local.topcoder-dev.com:8080'; The base path
13+
'MEMBER_V5_API_URL',
14+
function ($log, $q, $http, User, API_URL, API_VERSION_PATH, helper, MEMBER_V5_API_URL) {
15+
// local dev var API_URL = 'http://localhost:8080'; The base path
1516
// of the API including version.
1617
var basePath = API_URL + '/' + API_VERSION_PATH;
1718

@@ -405,6 +406,24 @@ angular
405406
}, helper.handleError)
406407
};
407408

409+
/**
410+
* gets a list of members given a list of handles.
411+
* @param {Array} handles the handle.
412+
*/
413+
UserService.getMembersByHandle = function (handles) {
414+
var qs = "";
415+
handles.forEach(function(handle) {
416+
qs += "&handlesLower[]=" + handle.toLowerCase();
417+
})
418+
var request = $http({
419+
method: 'GET',
420+
url: MEMBER_V5_API_URL +'/members?fields=userId,handle' + qs
421+
});
422+
return request.then(function (response) {
423+
return response.data;
424+
}, helper.handleError)
425+
};
426+
408427
return UserService;
409428
}
410429
]);

src/app/v5_challenges/add-user-challenge.controller.js

+33-23
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
module.controller('v5challenge.AddUserController', [
22
'$scope',
3-
'$timeout',
3+
'$q',
44
'$uibModalInstance',
55
'UserService',
66
'ChallengeService',
77
'Alert',
88
'parentScope',
99
'challenge',
10-
function ($scope, $timeout, $modalInstance, UserService, $challengeService, $alert, $parentScope, challenge) {
10+
function ($scope, $q, $modalInstance, UserService, $challengeService, $alert, $parentScope, challenge) {
1111
$scope.challenge = challenge
1212
$scope.handle = '';
1313
$scope.isLoading = false;
@@ -28,35 +28,45 @@ module.controller('v5challenge.AddUserController', [
2828
$modalInstance.close();
2929
};
3030

31-
/**
32-
* searches the handle.
33-
* @param {string} filter the filter.
34-
*/
35-
$scope.searchHandle = function (filter) {
36-
$scope.isLoading = true;
37-
return UserService.getMemberSuggestByHandle(filter).then(function (data) {
38-
$scope.isLoading = false;
39-
return _.map(data, function (x) { return x.handle });
40-
})
41-
};
31+
4232

4333
/**
4434
* handles save click.
4535
*/
4636
$scope.save = function () {
4737
$scope.clearError()
4838
$scope.isLoading = true;
39+
var success = [];
40+
var errors = [];
41+
42+
var promiseArray = $scope.handles.map(function(handle) {
43+
return $challengeService.v5.addChallengeResource({
44+
challengeId: $scope.challenge.id,
45+
memberHandle: handle,
46+
roleId: $scope.roleId
47+
}).then(function () {
48+
success.push({handle: handle});
49+
}).catch(function (error) {
50+
errors.push({handle: handle, message: error.error});
51+
})
52+
})
4953

50-
$challengeService.v5.addChallengeResource({
51-
challengeId: $scope.challenge.id,
52-
memberHandle: $scope.handle,
53-
roleId: $scope.roleId
54-
}).then(function () {
55-
$alert.success('User has been added.', $scope);
56-
$parentScope.search();
57-
}).catch(function (error) {
58-
$alert.error(error.error, $scope);
59-
}).finally(function () {
54+
$q.all(promiseArray)
55+
.finally(function () {
56+
if (success.length) {
57+
$parentScope.search();
58+
if (success.length > 1)
59+
$alert.success(success.length + ' users have been added.', $scope);
60+
else
61+
$alert.success('User has been added.', $scope);
62+
}
63+
if (errors.length) {
64+
var messages = [];
65+
messages = errors.map(function(error) {
66+
return error.handle + ": " + error.message;
67+
})
68+
$alert.error(messages, $scope);
69+
}
6070
$scope.isLoading = false;
6171
});
6272
};

src/app/v5_challenges/add-user-challenge.html

+3-5
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@ <h4 class="modal-title" id="reg-dialog-label">Add User</h4>
88
<div class="modal-body">
99
<div class="row">
1010
<form role="form" name="addUserForm" data-toggle="validator" autocomplete="off">
11-
<div class="col-md-12" ng-include src="'components/alert/alert.html'"></div>
11+
<div class="col-md-12" ng-include src="'components/alert/alert-list.html'"></div>
1212
<div class="form-group scrollable-dropdown-menu"
1313
ng-class="{'has-error': addUserForm.handle.$touched && addUserForm.handle.$invalid}">
1414
<label for="auto-handle">Handle</label>
15-
<input id="auto-handle" type="text" class="form-control" ng-model="handle"
16-
uib-typeahead="handle for handle in searchHandle($viewValue)" name="handle"
17-
required="required">
15+
<multiple-member-handler handles="handles"/>
1816
</div>
1917
<div class="form-group" ng-class="{'has-error': addUserForm.roleId.$touched && addUserForm.roleId.$invalid}">
2018
<label for="role">Role</label>
@@ -31,7 +29,7 @@ <h4 class="modal-title" id="reg-dialog-label">Add User</h4>
3129
Close
3230
</button>
3331
<button type="button" class="btn btn-primary" ng-click="save()"
34-
ng-disabled="addUserForm.$invalid || isLoading">
32+
ng-disabled="handles.length < 1 || !roleId || isLoading">
3533
Add User
3634
</button>
3735
</div>

0 commit comments

Comments
 (0)