diff --git a/package.json b/package.json index b0b388b..aed6a92 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "angular-touch": "~1.7.4", "angular-ui-bootstrap": "~2.5.0", "angular-ui-router": "~1.0.23", + "angularjs-datepicker": "^2.1.23", "auth0-angular": "~4.0.4", "auth0-js": "^9.11.3", "auth0-lock": "^11.17.2", diff --git a/src/controllers/GitlabController.js b/src/controllers/GitlabController.js index 3575005..a1ed04a 100644 --- a/src/controllers/GitlabController.js +++ b/src/controllers/GitlabController.js @@ -115,7 +115,11 @@ async function getGroupRegistrationUrl(req) { if (!user || !user.accessToken) { throw new errors.UnauthorizedError('You have not setup for Gitlab.'); } - return await GitlabService.getGroupRegistrationUrl(user.username, req.params.id, req.params.accessLevel); + return await GitlabService.getGroupRegistrationUrl( + user.username, + req.params.id, + req.params.accessLevel, + req.params.expiredAt); } /** @@ -193,7 +197,12 @@ async function addUserToGroupCallback(req, res) { }); // add user to group - const gitlabUser = await GitlabService.addGroupMember(group.groupId, ownerUser.accessToken, token, group.accessLevel); + const gitlabUser = await GitlabService.addGroupMember( + group.groupId, + ownerUser.accessToken, + token, + group.accessLevel, + group.expiredAt); // associate gitlab username with TC username const mapping = await dbHelper.scanOne(UserMapping, { topcoderUsername: {eq: req.session.tcUsername}, diff --git a/src/front/src/app/app.js b/src/front/src/app/app.js index 33f89c9..c3e6911 100644 --- a/src/front/src/app/app.js +++ b/src/front/src/app/app.js @@ -12,7 +12,8 @@ angular.module('topcoderX', [ 'ui.router', 'ui.bootstrap', 'angular-clipboard', - 'angular-jwt']) + 'angular-jwt', + '720kb.datepicker']) // In the run phase of your Angular application .run(['AuthService', function (AuthService) { // init AuthService, it has to be done once, when app starts diff --git a/src/front/src/app/git-access-control/access-control.service.js b/src/front/src/app/git-access-control/access-control.service.js index dadf140..fcc9eec 100644 --- a/src/front/src/app/git-access-control/access-control.service.js +++ b/src/front/src/app/git-access-control/access-control.service.js @@ -24,7 +24,12 @@ angular.module('topcoderX') * get gitlab shareable link * */ - service.getGitlabShareableLink = function (groupId, accessLevel) { + service.getGitlabShareableLink = function (groupId, accessLevel, expiredAt) { + if (expiredAt) { + return $http.get(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/registrationurl/' + accessLevel + '/' + expiredAt).then(function (response) { + return response; + }); + } return $http.get(baseUrl + '/api/v1/gitlab/groups/' + groupId + '/registrationurl/' + accessLevel).then(function (response) { return response; }); diff --git a/src/front/src/app/git-access-control/git-access-dialog.controller.js b/src/front/src/app/git-access-control/git-access-dialog.controller.js index 1823278..6838f17 100644 --- a/src/front/src/app/git-access-control/git-access-dialog.controller.js +++ b/src/front/src/app/git-access-control/git-access-dialog.controller.js @@ -12,10 +12,12 @@ angular.module('topcoderX').controller('GitAccessDialogController', [ ) { $scope.provider = provider; $scope.accessLevel = ''; + $scope.expiredAt = ''; if ($scope.provider === 'github') { $scope.accessLevel = 'member'; } else { $scope.accessLevel = '30'; + $scope.dateLimit = new Date().toDateString(); } /** @@ -25,12 +27,20 @@ angular.module('topcoderX').controller('GitAccessDialogController', [ $scope.accessLevel = accessLevel; }; + /** + * Update the expired at params + */ + $scope.updateExpired = function (expiredAt) { + $scope.expiredAt = expiredAt; + }; + /** * Set changes to father controller */ $scope.setChanges = function () { $uibModalInstance.close({ accessLevel: $scope.accessLevel, + expiredAt: $scope.expiredAt }); }; diff --git a/src/front/src/app/git-access-control/git-access-dialog.html b/src/front/src/app/git-access-control/git-access-dialog.html index d0794a6..570ec13 100644 --- a/src/front/src/app/git-access-control/git-access-dialog.html +++ b/src/front/src/app/git-access-control/git-access-dialog.html @@ -9,14 +9,21 @@ <h4 class="modal-title" id="reg-dialog-label">Configure Access Level and Valid P <div class="row"> <label class="form-label">Access Level:</label> <select class="form-control" ng-if="provider === 'gitlab'" ng-model="accessLevel" ng-change="updateAccessLevel(accessLevel)" required> - <option value ="30">Developer</option> + <option value ="10">Guest</option> <option value ="20">Reporter</option> + <option value ="30">Developer</option> + <option value ="40">Maintainer</option> + <option value ="50">Owner</option> </select> <select class="form-control" ng-if="provider === 'github'" ng-model="accessLevel" ng-change="updateAccessLevel(accessLevel)" required> <option value ="member">Member</option> <option value ="maintainer">Maintainer</option> </select> <br /> + <label ng-if="provider === 'gitlab'" class="form-label">Expired At:</label> + <datepicker ng-if="provider === 'gitlab'" date-format="yyyy-MM-dd" date-min-limit="{{dateLimit}}"> + <input class="form-control" ng-model="expiredAt" type="text" ng-change="updateExpired(expiredAt)"/> + </datepicker> </div> </div> <div class="modal-footer"> @@ -27,4 +34,4 @@ <h4 class="modal-title" id="reg-dialog-label">Configure Access Level and Valid P Cancel </button> </div> -</div> +</div> \ No newline at end of file diff --git a/src/front/src/app/git-access-control/gitAccessControl.controller.js b/src/front/src/app/git-access-control/gitAccessControl.controller.js index ea615c3..5ce60ee 100644 --- a/src/front/src/app/git-access-control/gitAccessControl.controller.js +++ b/src/front/src/app/git-access-control/gitAccessControl.controller.js @@ -88,8 +88,13 @@ angular.module('topcoderX').controller('GitAccessController', ['currentUser', '$ function (data) { if (data) { const accessLevel = data.accessLevel; + const expiredAt = data.expiredAt; var config = $scope.tableConfig[provider]; - config.accessLinkMethod.apply(vm, [team.id, accessLevel]).then(function (response) { + var params = [team.id, accessLevel]; + if (expiredAt) { + params.push(expiredAt); + } + config.accessLinkMethod.apply(vm, params).then(function (response) { team.accessLink = response.data.url; team.showLink = true; team.gettingLink = false; diff --git a/src/front/src/index.css b/src/front/src/index.css index 0d851b9..8b80263 100644 --- a/src/front/src/index.css +++ b/src/front/src/index.css @@ -1,4 +1,5 @@ /*add css dependencies in node_modules here*/ @import url("../../../node_modules/metismenu/dist/metisMenu.css"); -@import url("../../../node_modules/footable/css/footable.core.css"); \ No newline at end of file +@import url("../../../node_modules/footable/css/footable.core.css"); +@import url("../../../node_modules/angularjs-datepicker/dist/angular-datepicker.min.css"); \ No newline at end of file diff --git a/src/front/src/index.js b/src/front/src/index.js index 4a1cc7f..95a2e5c 100644 --- a/src/front/src/index.js +++ b/src/front/src/index.js @@ -29,4 +29,5 @@ require('metismenu'); require('pace-js'); require('footable'); require('jquery-ui-dist/jquery-ui'); +require('angularjs-datepicker'); window.shortid = require('shortid') \ No newline at end of file diff --git a/src/models/OwnerUserGroup.js b/src/models/OwnerUserGroup.js index 7c8662b..c3b729e 100644 --- a/src/models/OwnerUserGroup.js +++ b/src/models/OwnerUserGroup.js @@ -64,6 +64,10 @@ const schema = new Schema({ name: 'AccessLevelIndex', }, }, + expiredAt: { + type: String, + required: false + } }); diff --git a/src/routes.js b/src/routes.js index 168a5f9..b2649bb 100644 --- a/src/routes.js +++ b/src/routes.js @@ -86,6 +86,12 @@ module.exports = { method: 'getGroupRegistrationUrl', }, }, + '/gitlab/groups/:id/registrationurl/:accessLevel/:expiredAt': { + get: { + controller: 'GitlabController', + method: 'getGroupRegistrationUrl', + }, + }, '/gitlab/groups/:id/users': { delete: { controller: 'GitlabController', diff --git a/src/services/GitlabService.js b/src/services/GitlabService.js index 77edd8e..5e25524 100644 --- a/src/services/GitlabService.js +++ b/src/services/GitlabService.js @@ -145,9 +145,10 @@ listOwnerUserGroups.schema = Joi.object().keys({ * @param {String} ownerUsername the owner user name * @param {String} groupId the group id * @param {String} accessLevel the group access level + * @param {String} expiredAt the expired at params to define how long user joined teams. can be null * @returns {Promise} the promise result */ -async function getGroupRegistrationUrl(ownerUsername, groupId, accessLevel) { +async function getGroupRegistrationUrl(ownerUsername, groupId, accessLevel, expiredAt) { // generate identifier const identifier = helper.generateIdentifier(); @@ -159,6 +160,7 @@ async function getGroupRegistrationUrl(ownerUsername, groupId, accessLevel) { groupId, identifier, accessLevel, + expiredAt }); // construct URL @@ -170,6 +172,7 @@ getGroupRegistrationUrl.schema = Joi.object().keys({ ownerUsername: Joi.string().required(), groupId: Joi.string().required(), accessLevel: Joi.string().required(), + expiredAt: Joi.string() }); /** @@ -178,9 +181,10 @@ getGroupRegistrationUrl.schema = Joi.object().keys({ * @param {String} ownerUserToken the owner user token * @param {String} normalUserToken the normal user token * @param {String} accessLevel the access level + * @param {String} expiredAt the expired at params to define how long user joined teams. can be null * @returns {Promise} the promise result */ -async function addGroupMember(groupId, ownerUserToken, normalUserToken, accessLevel) { +async function addGroupMember(groupId, ownerUserToken, normalUserToken, accessLevel, expiredAt) { let username; let userId; try { @@ -195,11 +199,15 @@ async function addGroupMember(groupId, ownerUserToken, normalUserToken, accessLe throw new errors.UnauthorizedError('Can not get user id from the normal user access token.'); } + let body = `user_id=${userId}&access_level=${accessLevel}`; + if (expiredAt) { + body = body + `&expires_at=${expiredAt} `; + } // add user to group await request .post(`${config.GITLAB_API_BASE_URL}/api/v4/groups/${groupId}/members`) .set('Authorization', `Bearer ${ownerUserToken}`) - .send(`user_id=${userId}&access_level=${accessLevel}`) + .send(body) .end(); // return gitlab username return { @@ -222,6 +230,7 @@ addGroupMember.schema = Joi.object().keys({ ownerUserToken: Joi.string().required(), normalUserToken: Joi.string().required(), accessLevel: Joi.string().required(), + expiredAt: Joi.string() }); /**