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

Commit 8baf5eb

Browse files
committed
Fixes for login and copilot payments
1 parent 93448dd commit 8baf5eb

21 files changed

+430
-11
lines changed

TopcoderXDeploy.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,25 @@ To this:
8686
},
8787
```
8888

89+
## Machine-to-machine (M2M) Token generation
90+
The `topcoder-x-processor` uses the Topcoder m2m token to interact with others Topcoder service.
91+
It needs to be configured properly. Please make sure the following items is configured:
92+
93+
- `AUTH0_URL` The Auth0 URL for generating Machine-to-machine token
94+
- `AUTH0_AUDIENCE` The audience of Auth0 to generate M2M Token
95+
- `AUTH0_CLIENT_ID` The Auth0 ClientID for generating Machine-to-machine token
96+
- `AUTH0_CLIENT_SECRET` The Auth0 Client Secret for generating Machine-to-machine token
97+
98+
99+
For local deployment, configuring M2M token generation can use this provided account:
100+
```
101+
export AUTH0_URL=https://topcoder-dev.auth0.com/oauth/token
102+
export AUTH0_AUDIENCE=https://m2m.topcoder-dev.com/
103+
export AUTH0_CLIENT_ID=LU2Nt7YPHQ3lxrFNKitJ82syB4wIMR7G
104+
export AUTH0_CLIENT_SECRET=O8S2YOb-0lI4NS3smR4d4uf0VM9BN0y1Ra4ABRktGUPOXc34mUO25uJrCpU-TBAT
105+
```
106+
107+
89108
## Local DNS setup
90109

91110
For login to work, your local Topcoder-X-UI deployment needs to have a `*.topcoder-dev.com` DNS name. Our development environment uses `x.topcoder-dev.com`
@@ -186,6 +205,10 @@ AWS_ACCESS_KEY_ID: FAKE_ACCESS_KEY_ID
186205
AWS_SECRET_ACCESS_KEY: FAKE_SECRET_ACCESS_KEY
187206
AWS_REGION: FAKE_REGION
188207
IS_LOCAL: true
208+
AUTH0_URL: https://topcoder-dev.auth0.com/oauth/token
209+
AUTH0_AUDIENCE: https://m2m.topcoder-dev.com/
210+
AUTH0_CLIENT_ID: LU2Nt7YPHQ3lxrFNKitJ82syB4wIMR7G
211+
AUTH0_CLIENT_SECRET: O8S2YOb-0lI4NS3smR4d4uf0VM9BN0y1Ra4ABRktGUPOXc34mUO25uJrCpU-TBAT
189212
```
190213

191214
#### Topcoder-X receiver

src/app.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,19 @@ app.use((err, req, res, next) => {
131131
res.status(resultErr.statusCode || 500).json(resObj); // eslint-disable-line no-magic-numbers
132132
});
133133

134+
process.on('uncaughtException', (err) => {
135+
// Check if error related to Dynamodb conn
136+
if (err.code === 'NetworkingError' && err.region) {
137+
logger.error('DynamoDB connection failed.');
138+
}
139+
logger.logFullError(err, 'system');
140+
});
141+
142+
// handle and log unhanled rejection
143+
process.on('unhandledRejection', (err) => {
144+
logger.logFullError(err, 'system');
145+
});
146+
134147
const port = config.PORT;
135148
app.listen(port, '0.0.0.0');
136149
logger.info('Topcoder X server listening on port %d', port);

src/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ module.exports = {
4545
{name: 'tcx_NotReady', color: '000000'},
4646
{name: 'tcx_Canceled', color: '000000'},
4747
],
48+
OPEN_FOR_PICKUP_ISSUE_LABEL: process.env.OPEN_FOR_PICKUP_ISSUE_LABEL || 'tcx_OpenForPickup',
4849
ALLOWED_TOPCODER_ROLES: process.env.ALLOWED_TOPCODER_ROLES || ['administrator', 'admin', 'connect manager', 'connect admin', 'copilot', 'connect copilot'],
4950
COPILOT_ROLE: process.env.COPILOT_ROLE || 'copilot',
5051
HELP_LINK: process.env.HELP_LINK || 'https://github.com/topcoder-platform/topcoder-x-ui/wiki',

src/controllers/IssueController.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,19 @@ async function search(req) {
2121
return await IssueService.search(req.query, req.currentUser.handle);
2222
}
2323

24+
/**
25+
* create an issue
26+
* @param {Object} req the request
27+
* @param {Object} res the response
28+
* @returns {Object} the result
29+
*/
30+
async function create(req) {
31+
return await IssueService.create(req.body, req.currentUser);
32+
}
33+
2434
module.exports = {
2535
search,
36+
create
2637
};
2738

2839
helper.buildController(module.exports);

src/controllers/UserController.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,17 @@ async function getUserSetting(req) {
2323
return await UserService.getUserSetting(topcoderUsername);
2424
}
2525

26+
/**
27+
* Gets user setting.
28+
* @param {Object} req the request
29+
* @param {Object} res the response
30+
* @returns {Object} the result
31+
*/
32+
async function revokeUserSetting(req) {
33+
const topcoderUsername = req.query.topcoderUsername;
34+
const provider = req.query.provider;
35+
return await UserService.revokeUserSetting(topcoderUsername, provider);
36+
}
2637

2738
/**
2839
* Gets user access token.
@@ -36,6 +47,7 @@ async function getUserToken(req) {
3647

3748
module.exports = {
3849
getUserSetting,
50+
revokeUserSetting,
3951
getUserToken,
4052
};
4153

src/front/src/app/app.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ angular.module('topcoderX', [
9494
data: { pageTitle: 'Project Management' },
9595
resolve: { auth: authenticate }
9696
})
97+
.state('app.issue', {
98+
url: '/upsertissue',
99+
controller: 'IssueController',
100+
controllerAs: 'vm',
101+
templateUrl: 'app/upsertissue/upsertissue.html',
102+
data: { pageTitle: 'Project Management' },
103+
resolve: { auth: authenticate }
104+
})
97105
// following code is commented to hide the menu
98106
// un comment this when pages are developed
99107
// .state('app.challenges', {

src/front/src/app/auth/auth.service.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,11 @@ angular.module('topcoderX')
206206
}
207207
AuthService.PermissionDenied = true;
208208
return $q.reject(AuthService.ERROR.NO_PERMISSIONS);
209-
}).catch(function (err) { return $q.reject(err); });
209+
}).catch(function (err) {
210+
AuthService.logout();
211+
$state.go('auth');
212+
return $q.reject(err);
213+
});
210214
}
211215

212216
/**

src/front/src/app/less/custom.less

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,12 @@
1818

1919
.green-check-icon {
2020
color: green;
21-
font-size: 15px;
21+
font-size: 16px;
22+
}
23+
24+
.white-remove-icon {
25+
color: white;
26+
font-size: 16px;
2227
}
2328

2429
.lh-40 .row{
@@ -33,3 +38,7 @@
3338
float: left;
3439
text-align: left;
3540
}
41+
42+
.pull-right-button {
43+
margin-left: 20px;
44+
}

src/front/src/app/main/issue.service.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,15 @@ angular.module('topcoderX')
1919
});
2020
};
2121

22+
/**
23+
* Create an Issue
24+
* @param issue the issue to be created
25+
*/
26+
service.create = function (issue) {
27+
return $http.post(Helper.baseUrl + '/api/v1/issues', issue).then(function (response) {
28+
return response;
29+
});
30+
};
31+
2232
return service;
2333
}]);

src/front/src/app/main/main.html

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,11 @@
33
<h2>Dashboard</h2>
44
</div>
55
<div class="col-lg-2 with-button pull-right">
6-
<button class="btn btn-sm btn-info pull-right" ui-sref="app.project">
6+
<button class="btn btn-sm btn-primary pull-right pull-right-button" ui-sref="app.issue">
7+
<i class="fa fa-plus"></i> Add Issue</button>
8+
<button class="btn btn-sm btn-info pull-right pull-right-button" ui-sref="app.project">
79
<i class="fa fa-plus"></i> Add Project</button>
8-
</div>
10+
</div>
911
</div>
1012

1113
<div class="wrapper wrapper-content animated fadeInRight">

src/front/src/app/projects/projects.controller.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,11 @@ angular.module('topcoderX')
2626
$state.go('app.project');
2727
};
2828

29+
//go to a add issue page
30+
$scope.goIssue = function () {
31+
$state.go('app.issue');
32+
};
33+
2934
//the actived project list
3035
$scope.projects = [];
3136
//the archived project list

src/front/src/app/projects/projects.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
<h2>{{title}}</h2>
66
</div>
77
<div class="col-lg-2 with-button pull-right">
8-
<button class="btn btn-sm btn-info pull-right" ng-click="goProject()">
8+
<button class="btn btn-sm btn-primary pull-right pull-right-button" ng-click="goIssue()">
9+
<i class="fa fa-plus"></i> Add Issue</button>
10+
<button class="btn btn-sm btn-info pull-right pull-right-button" ng-click="goProject()">
911
<i class="fa fa-plus"></i> Add Project</button>
1012
</div>
1113
</div>

src/front/src/app/settings/settings.controller.js

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use strict';
22

33
angular.module('topcoderX').controller('SettingController', ['currentUser', '$scope', 'OWNER_LOGIN_GITHUB_URL',
4-
'OWNER_LOGIN_GITLAB_URL', 'SettingService', '$rootScope', 'Alert', 'Helper',
4+
'OWNER_LOGIN_GITLAB_URL', 'SettingService', '$rootScope', 'Dialog', 'Alert', 'Helper',
55
function (currentUser, $scope, OWNER_LOGIN_GITHUB_URL,
6-
OWNER_LOGIN_GITLAB_URL, SettingService, $rootScope, Alert, Helper) {
6+
OWNER_LOGIN_GITLAB_URL, SettingService, $rootScope, Dialog, Alert, Helper) {
77
$scope.settings = {};
88
$scope.isLoaded = false;
99

@@ -23,5 +23,21 @@ angular.module('topcoderX').controller('SettingController', ['currentUser', '$sc
2323
github: Helper.baseUrl + OWNER_LOGIN_GITHUB_URL,
2424
gitlab: Helper.baseUrl + OWNER_LOGIN_GITLAB_URL,
2525
}
26-
26+
27+
// Revoke gitlab or github account
28+
$scope.revoke = function(provider) {
29+
$scope.$on('dialog.finished', function (event, args) {
30+
if (args.proceed) {
31+
SettingService.revokeUserSetting(currentUser.handle, provider).then(function () {
32+
_getSetting();
33+
}).catch(function (error) {
34+
var errMsg = error.data ? error.data.message : "An error occurred while revoking the account."
35+
Alert.error(errMsg, $scope);
36+
});
37+
} else {
38+
$rootScope.dialog = {};
39+
}
40+
});
41+
Dialog.show('Are you sure you want to revoke the authorization token for ' + provider + '?', $scope);
42+
}
2743
}]);

src/front/src/app/settings/settings.html

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ <h2>Settings</h2>
55
<div class="col-lg-2">
66
</div>
77
</div>
8+
<div ng-include src="'components/dialog/dialog.html'"></div>
89
<div class="col-md-10 col-md-offset-1" ng-include src="'components/alert/alert.html'"></div>
910
<div class="wrapper wrapper-content animated fadeInRight">
1011
<div class="row">
@@ -15,7 +16,8 @@ <h2>Settings</h2>
1516
<div class="col-xs-6 col-md-2">Github</div>
1617
<div class="col-xs-6 col-md-2" ng-if='isLoaded'>
1718
<div ng-if='settings.github'>
18-
<i class="fa fa-check green-check-icon"></i>
19+
<i class="btn fa fa-check green-check-icon"></i>&nbsp;&nbsp;
20+
<i class="btn btn-sm btn-danger fa fa-remove white-remove-icon" ng-click="revoke('github')"></i>
1921
</div>
2022
<div ng-if='!settings.github'>
2123
<a class="btn btn-sm btn-info" ng-href="{{loginUrl.github}}">
@@ -28,7 +30,8 @@ <h2>Settings</h2>
2830
<div class="col-xs-6 col-md-2">Gitlab</div>
2931
<div class="col-xs-6 col-md-2" ng-if='isLoaded'>
3032
<div ng-if='settings.gitlab'>
31-
<i class="fa fa-check green-check-icon"></i>
33+
<i class="btn fa fa-check green-check-icon"></i>&nbsp;&nbsp;
34+
<i class="btn btn-sm btn-danger fa fa-remove white-remove-icon" ng-click="revoke('gitlab')"></i>
3235
</div>
3336
<div ng-if='!settings.gitlab'>
3437
<a class="btn btn-sm btn-info" ng-href="{{loginUrl.gitlab}}" target="_self">

src/front/src/app/settings/settings.service.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,15 @@ angular.module('topcoderX')
1919
});
2020
};
2121

22+
/**
23+
* Revoke user setting on github or gitlab
24+
*/
25+
service.revokeUserSetting = function (handle, provider) {
26+
return $http.delete(Helper.baseUrl + '/api/v1/users/setting?topcoderUsername=' + handle + '&provider=' + provider).then(function (response) {
27+
return response;
28+
});
29+
};
30+
2231
/**
2332
* tryAuth Try to authenticate the user based on code & state params
2433
* @param {string} code from github oAuth
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2018 TopCoder, Inc. All rights reserved.
3+
*
4+
* This is the upsertproject controller.
5+
*/
6+
'use strict';
7+
8+
angular.module('topcoderX').controller('IssueController', ['currentUser', '$scope', '$timeout', 'ProjectService', 'IssueService',
9+
'$rootScope', '$state', 'Alert',
10+
function (currentUser, $scope, $timeout, ProjectService, IssueService, $rootScope, $state,
11+
Alert) {
12+
// Maintain the navigation state.
13+
$timeout(function () {
14+
angular.element('#projectsManagement').addClass('active');
15+
}, 0);
16+
17+
// get topcoderx projects
18+
$scope.getProjects = function () {
19+
ProjectService.getProjects('active', false).then(function (response) {
20+
$scope.projects = response.data;
21+
if ($scope.projects.length === 0) {
22+
_handleError({}, 'There are no projects in Topcoder-X. Please <a href="/#/app/upsertproject">Create a project</a> first.');
23+
}
24+
}).catch(function (error) {
25+
_handleError(error, 'There are no projects in Topcoder-X. Please <a href="/#/app/upsertproject">Create a project</a> first.');
26+
});
27+
};
28+
$scope.getProjects();
29+
30+
// handle error output
31+
function _handleError(error, defaultMsg) {
32+
const errMsg = error.data ? error.data.message : defaultMsg;
33+
Alert.error(errMsg, $scope);
34+
}
35+
36+
$scope.selectedProject = null;
37+
$scope.issue = {
38+
projectId: '',
39+
prize: null,
40+
title: '',
41+
comment: '',
42+
repoUrl: ''
43+
};
44+
$scope.title = 'Add an Issue';
45+
46+
// save the issue info.
47+
$scope.save = function () {
48+
const selectedProject = angular.fromJson($scope.selectedProject);
49+
$scope.issue.projectId = selectedProject.id;
50+
$scope.issue.repoUrl = selectedProject.repoUrl;
51+
52+
IssueService.create($scope.issue).then(function (response) {
53+
$scope.selectedProject = null;
54+
$scope.issue = {
55+
projectId: '',
56+
prize: null,
57+
title: '',
58+
comment: '',
59+
repoUrl: ''
60+
};
61+
Alert.info('<a href="' + response.data.url+ '" target="_blank"><b><u>Issue #' + response.data.number + '</u></b></a> has been created', $scope);
62+
}).catch(function (error) {
63+
Alert.error(error.data.message, $scope);
64+
});
65+
};
66+
}]);

0 commit comments

Comments
 (0)