Skip to content
This repository was archived by the owner on Mar 13, 2025. It is now read-only.

Commit acd5be3

Browse files
committed
March 2020 Release Challenge
1 parent f460d53 commit acd5be3

17 files changed

+601
-155
lines changed

src/controllers/GithubController.js

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const config = require('../config');
1919
const GithubService = require('../services/GithubService');
2020
const UserService = require('../services/UserService');
2121
const OwnerUserTeam = require('../models').OwnerUserTeam;
22+
const UserTeamMapping = require('../models').UserTeamMapping;
2223
const UserMapping = require('../models').UserMapping;
2324
const constants = require('../common/constants');
2425

@@ -102,7 +103,8 @@ async function getTeamRegistrationUrl(req) {
102103
if (!user || !user.accessToken) {
103104
throw new errors.UnauthorizedError('You have not setup for Github.');
104105
}
105-
return await GithubService.getTeamRegistrationUrl(user.accessToken, user.username, req.params.id);
106+
return await GithubService.getTeamRegistrationUrl(user.accessToken, user.username, req.params.id,
107+
req.params.accessLevel);
106108
}
107109

108110
/**
@@ -152,7 +154,7 @@ async function addUserToTeamCallback(req, res) {
152154
const token = result.body.access_token;
153155
// add user to team
154156
console.log(`adding ${token} to ${team.teamId} with ${team.ownerToken}`); /* eslint-disable-line no-console */
155-
const githubUser = await GithubService.addTeamMember(team.teamId, team.ownerToken, token);
157+
const githubUser = await GithubService.addTeamMember(team.teamId, team.ownerToken, token, team.accessLevel);
156158
// associate github username with TC username
157159
const mapping = await dbHelper.scanOne(UserMapping, {
158160
topcoderUsername: {eq: req.session.tcUsername},
@@ -175,6 +177,22 @@ async function addUserToTeamCallback(req, res) {
175177
});
176178
}
177179

180+
// associate github username and teamId
181+
const githubUserToTeamMapping = await dbHelper.scanOne(UserTeamMapping, {
182+
teamId: {eq: team.teamId},
183+
githubUserName: {eq: githubUser.username},
184+
githubOrgId: {eq: team.githubOrgId},
185+
});
186+
187+
if (!githubUserToTeamMapping) {
188+
await dbHelper.create(UserTeamMapping, {
189+
id: helper.generateIdentifier(),
190+
teamId: team.teamId,
191+
githubUserName: githubUser.username,
192+
githubOrgId: team.githubOrgId,
193+
});
194+
}
195+
178196
// check if user is already in the team or not yet
179197
if (githubUser.state === 'active') {
180198
// redirect user to the success page, to let user know that he is already in the team
@@ -190,6 +208,40 @@ async function addUserToTeamCallback(req, res) {
190208
}
191209
}
192210

211+
/**
212+
* Delete users from a team.
213+
* @param {Object} req the request
214+
* @param {Object} res the response
215+
*/
216+
async function deleteUsersFromTeam(req, res) {
217+
let teamInDB;
218+
const teamId = req.params.id;
219+
try {
220+
teamInDB = await helper.ensureExists(OwnerUserTeam, {teamId}, 'OwnerUserTeam');
221+
} catch (err) {
222+
if (!(err instanceof errors.NotFoundError)) {
223+
throw err;
224+
}
225+
}
226+
// If teamInDB not exists, then just return
227+
if (teamInDB) {
228+
try {
229+
const githubOrgId = teamInDB.githubOrgId;
230+
const token = teamInDB.ownerToken;
231+
const userTeamMappings = await dbHelper.scan(UserTeamMapping, {
232+
teamId: req.params.id,
233+
});
234+
// eslint-disable-next-line no-restricted-syntax
235+
for (const userTeamMapItem of userTeamMappings) {
236+
await GithubService.deleteUserFromGithubTeam(token, teamId, githubOrgId, userTeamMapItem.githubUserName);
237+
await dbHelper.remove(UserTeamMapping, {id: userTeamMapItem.id});
238+
}
239+
} catch (err) {
240+
throw err;
241+
}
242+
}
243+
res.send({});
244+
}
193245

194246
module.exports = {
195247
ownerUserLogin,
@@ -198,6 +250,7 @@ module.exports = {
198250
getTeamRegistrationUrl,
199251
addUserToTeam,
200252
addUserToTeamCallback,
253+
deleteUsersFromTeam,
201254
};
202255

203256
helper.buildController(module.exports);

src/controllers/GitlabController.js

Lines changed: 54 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ const UserService = require('../services/UserService');
2121
const User = require('../models').User;
2222
const OwnerUserGroup = require('../models').OwnerUserGroup;
2323
const UserMapping = require('../models').UserMapping;
24+
const UserGroupMapping = require('../models').UserGroupMapping;
2425

2526
const request = superagentPromise(superagent, Promise);
2627

@@ -114,7 +115,7 @@ async function getGroupRegistrationUrl(req) {
114115
if (!user || !user.accessToken) {
115116
throw new errors.UnauthorizedError('You have not setup for Gitlab.');
116117
}
117-
return await GitlabService.getGroupRegistrationUrl(user.username, req.params.id);
118+
return await GitlabService.getGroupRegistrationUrl(user.username, req.params.id, req.params.accessLevel);
118119
}
119120

120121
/**
@@ -170,27 +171,7 @@ async function addUserToGroupCallback(req, res) {
170171
throw new errors.NotFoundError('The owner user is not found or not accessible.');
171172
}
172173

173-
// refresh the owner user access token if needed
174-
if (ownerUser.accessTokenExpiration && ownerUser.accessTokenExpiration.getTime() <=
175-
new Date().getTime() + constants.GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION * MS_PER_SECOND) {
176-
const refreshTokenResult = await request
177-
.post('https://gitlab.com/oauth/token')
178-
.query({
179-
client_id: config.GITLAB_CLIENT_ID,
180-
client_secret: config.GITLAB_CLIENT_SECRET,
181-
refresh_token: ownerUser.refreshToken,
182-
grant_type: 'refresh_token',
183-
redirect_uri: `${config.WEBSITE}/api/${config.API_VERSION}/gitlab/owneruser/callback`,
184-
})
185-
.end();
186-
// save user token data
187-
const expiresIn = refreshTokenResult.body.expires_in || constants.GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION;
188-
await dbHelper.update(User, ownerUser.id, {
189-
accessToken: refreshTokenResult.body.access_token,
190-
accessTokenExpiration: new Date(new Date().getTime() + expiresIn * MS_PER_SECOND),
191-
refreshToken: refreshTokenResult.body.refresh_token,
192-
});
193-
}
174+
await GitlabService.refreshGitlabUserAccessToken(ownerUser);
194175

195176
// exchange code to get normal user token
196177
const result = await request
@@ -212,7 +193,7 @@ async function addUserToGroupCallback(req, res) {
212193
});
213194

214195
// add user to group
215-
const gitlabUser = await GitlabService.addGroupMember(group.groupId, ownerUser.accessToken, token);
196+
const gitlabUser = await GitlabService.addGroupMember(group.groupId, ownerUser.accessToken, token, group.accessLevel);
216197
// associate gitlab username with TC username
217198
const mapping = await dbHelper.scanOne(UserMapping, {
218199
topcoderUsername: {eq: req.session.tcUsername},
@@ -230,17 +211,67 @@ async function addUserToGroupCallback(req, res) {
230211
gitlabUserId: gitlabUser.id,
231212
});
232213
}
214+
// We get gitlabUser.id and group.groupId and
215+
// associate github username and teamId
216+
const gitlabUserToGroupMapping = await dbHelper.scanOne(UserGroupMapping, {
217+
groupId: {eq: group.groupId},
218+
gitlabUserId: {eq: gitlabUser.id},
219+
});
220+
221+
if (!gitlabUserToGroupMapping) {
222+
await dbHelper.create(UserGroupMapping, {
223+
id: helper.generateIdentifier(),
224+
groupId: group.groupId,
225+
gitlabUserId: gitlabUser.id,
226+
});
227+
}
233228
// redirect to success page
234229
res.redirect(`${constants.USER_ADDED_TO_TEAM_SUCCESS_URL}/gitlab/${currentGroup.full_path}`);
235230
}
236231

232+
233+
/**
234+
* Delete users from a group.
235+
* @param {Object} req the request
236+
* @param {Object} res the response
237+
*/
238+
async function deleteUsersFromTeam(req, res) {
239+
const groupId = req.params.id;
240+
let groupInDB;
241+
try {
242+
groupInDB = await helper.ensureExists(OwnerUserGroup, {groupId}, 'OwnerUserGroup');
243+
} catch (err) {
244+
if (!(err instanceof errors.NotFoundError)) {
245+
throw err;
246+
}
247+
}
248+
// If groupInDB not exists, then just return
249+
if (groupInDB) {
250+
try {
251+
const ownerUser = await helper.ensureExists(User,
252+
{username: groupInDB.ownerUsername, type: constants.USER_TYPES.GITLAB, role: constants.USER_ROLES.OWNER}, 'User');
253+
await GitlabService.refreshGitlabUserAccessToken(ownerUser);
254+
const userGroupMappings = await dbHelper.scan(UserGroupMapping, {groupId});
255+
// eslint-disable-next-line no-restricted-syntax
256+
for (const userGroupMapItem of userGroupMappings) {
257+
await GitlabService.deleteUserFromGitlabGroup(ownerUser.accessToken, groupId, userGroupMapItem.gitlabUserId);
258+
await dbHelper.remove(UserGroupMapping, {id: userGroupMapItem.id});
259+
}
260+
} catch (err) {
261+
throw err;
262+
}
263+
}
264+
res.send({});
265+
}
266+
237267
module.exports = {
238268
ownerUserLogin,
239269
ownerUserLoginCallback,
240270
listOwnerUserGroups,
241271
getGroupRegistrationUrl,
242272
addUserToGroup,
243273
addUserToGroupCallback,
274+
deleteUsersFromTeam,
244275
};
245276

246277
helper.buildController(module.exports);

src/front/src/app/git-access-control/access-control.html

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,13 @@ <h2>Git Access Control</h2>
2727
</span>
2828
</div>
2929
</div>
30-
</div>
30+
</div>
3131
<table ng-if="tableConfig.github.items.length!=0 || tableConfig.github.allItems.length!=0" class="footable table table-stripped toggle-arrow-tiny">
3232
<thead>
3333
<tr>
3434
<th class="col-lg-2" data-sort-ignore="true">Team Name</th>
3535
<th class="col-lg-2" data-sort-ignore="true">Get Link</th>
36+
<th class="col-lg-2" data-sort-ignore="true">Remove All Users</th>
3637
</tr>
3738
</thead>
3839
<tbody>
@@ -56,6 +57,14 @@ <h2>Git Access Control</h2>
5657
</a>
5758
</div>
5859
</td>
60+
<td class="col-lg-2">
61+
<button class="btn btn-sm btn-danger" ng-hide="item.removingUsers" ng-click="removeAllUsers(item, 'github')">
62+
<strong>Remove All Users</strong>
63+
</button>
64+
<button class="btn btn-sm btn-success disabled" ng-show="item.removingUsers">
65+
<i class="fa fa-spinner fa-spin"></i>
66+
</button>
67+
</td>
5968
</tr>
6069
</tbody>
6170
<tfoot>
@@ -103,7 +112,7 @@ <h2>Git Access Control</h2>
103112
<uib-tab index="1" heading="Gitlab" select="tabChanged('gitlab')">
104113
<br/>
105114
<div ng-if="settings.gitlab==true">
106-
<div ng-show="tableConfig.gitlab.initialized">
115+
<div ng-show="tableConfig.gitlab.initialized">
107116
<div ng-if="tableConfig.gitlab.items.length!=0 || tableConfig.gitlab.allItems.length!=0" class="row">
108117
<div class="col-lg-3">
109118
<div class="input-group custom-search-form">
@@ -144,6 +153,14 @@ <h2>Git Access Control</h2>
144153
</a>
145154
</div>
146155
</td>
156+
<td class="col-lg-2">
157+
<button class="btn btn-sm btn-danger" ng-hide="item.removingUsers" ng-click="removeAllUsers(item, 'gitlab')">
158+
<strong>Remove All Users</strong>
159+
</button>
160+
<button class="btn btn-sm btn-success disabled" ng-show="item.removingUsers">
161+
<i class="fa fa-spinner fa-spin"></i>
162+
</button>
163+
</td>
147164
</tr>
148165
</tbody>
149166
<tfoot>
@@ -194,4 +211,4 @@ <h2>Git Access Control</h2>
194211
</div>
195212
</div>
196213
</div>
197-
</div>
214+
</div>

src/front/src/app/git-access-control/access-control.service.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ angular.module('topcoderX')
2424
* get gitlab shareable link
2525
*
2626
*/
27-
service.getGitlabShareableLink = function (groupId) {
28-
return $http.get(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/registrationurl').then(function (response) {
27+
service.getGitlabShareableLink = function (groupId, accessLevel) {
28+
return $http.get(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/registrationurl/' + accessLevel).then(function (response) {
2929
return response;
3030
});
3131
};
@@ -44,8 +44,28 @@ angular.module('topcoderX')
4444
* get github shareable link
4545
*
4646
*/
47-
service.getGithubShareableLink = function (teamId) {
48-
return $http.get(baseUrl + '/api/v1/github/teams/' + teamId + '/registrationurl').then(function (response) {
47+
service.getGithubShareableLink = function (teamId, accessLevel) {
48+
return $http.get(baseUrl + '/api/v1/github/teams/' + teamId + '/registrationurl/' + accessLevel).then(function (response) {
49+
return response;
50+
});
51+
};
52+
53+
/**
54+
* remove all users from a github team
55+
*
56+
*/
57+
service.removeAllGithubUsers = function (teamId) {
58+
return $http.delete(baseUrl + '/api/v1/github/teams/' + teamId + '/users').then(function (response) {
59+
return response;
60+
});
61+
};
62+
63+
/**
64+
* remove all users from a gitlab group
65+
*
66+
*/
67+
service.removeAllGitlabUsers = function (groupId) {
68+
return $http.delete(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/users').then(function (response) {
4969
return response;
5070
});
5171
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// controller for transfer ownership dialog
2+
'use strict';
3+
4+
angular.module('topcoderX').controller('GitAccessDialogController', [
5+
'$scope',
6+
'$uibModalInstance',
7+
'provider',
8+
function (
9+
$scope,
10+
$uibModalInstance,
11+
provider
12+
) {
13+
$scope.provider = provider;
14+
$scope.accessLevel = '';
15+
if ($scope.provider === 'github') {
16+
$scope.accessLevel = 'member';
17+
} else {
18+
$scope.accessLevel = '30';
19+
}
20+
21+
/**
22+
* Update the access level
23+
*/
24+
$scope.updateAccessLevel = function (accessLevel) {
25+
$scope.accessLevel = accessLevel;
26+
};
27+
28+
/**
29+
* Set changes to father controller
30+
*/
31+
$scope.setChanges = function () {
32+
$uibModalInstance.close({
33+
accessLevel: $scope.accessLevel,
34+
});
35+
};
36+
37+
/**
38+
* Close dialog
39+
*/
40+
$scope.close = function () {
41+
$uibModalInstance.close();
42+
};
43+
},
44+
]);

0 commit comments

Comments
 (0)