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

Version 1.2.2 #461

Merged
merged 26 commits into from
Jun 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
8368b32
Drop down selector for Connect project instead of text field
jmgasper May 18, 2022
43ad8ea
Deploy for testing
jmgasper May 18, 2022
638b3e3
Updates for timeout
jmgasper May 18, 2022
0ad0c52
Further timeout test
jmgasper May 19, 2022
8d73ae2
Let’s try this
jmgasper May 19, 2022
7077279
Use ui-select (https://angular-ui.github.io/ui-select/) as dropdown s…
gets0ul May 19, 2022
eb360cf
Merge pull request #446 from gets0ul/issue-445
jmgasper May 19, 2022
cef4344
Archived projects still using copilot handle
jmgasper May 20, 2022
446b2c3
https://github.com/topcoder-platform/topcoder-x-ui/issues/448
52cs May 25, 2022
e82f6c6
Merge pull request #449 from 52cs/issue-448
jmgasper May 25, 2022
131b236
Refresh owner user/copilot Gitlab access token automatically when needed
gets0ul May 25, 2022
54055a2
Merge pull request #450 from gets0ul/issue_447
jmgasper May 25, 2022
e29301e
small fix on PR #449 for issue #448
52cs May 27, 2022
595d71c
Merge pull request #451 from 52cs/issue-448-fix
jmgasper May 30, 2022
c4e694f
Changes to Connect ID dropdown:
gets0ul May 31, 2022
8b4bf6b
Merge pull request #454 from gets0ul/issue_452
jmgasper May 31, 2022
9d11673
https://github.com/topcoder-platform/topcoder-x-ui/issues/453
52cs Jun 2, 2022
5e2a247
Merge pull request #455 from 52cs/issue-453
jmgasper Jun 2, 2022
03f10ce
fix lint of PR#455 for Issue453
52cs Jun 2, 2022
855879d
Merge pull request #456 from 52cs/fix-lint-455
jmgasper Jun 2, 2022
2d04d6a
https://github.com/topcoder-platform/topcoder-x-ui/issues/453
52cs Jun 2, 2022
5c2afde
Merge pull request #457 from 52cs/fix-issue-453
jmgasper Jun 2, 2022
c334ca3
fix-empty-tags
52cs Jun 3, 2022
aec774d
Merge pull request #458 from 52cs/fix-empty-tags/Issue#453
jmgasper Jun 3, 2022
9935ebb
https://github.com/topcoder-platform/topcoder-x-ui/issues/459
52cs Jun 14, 2022
c92f485
Merge pull request #460 from 52cs/issue-459
jmgasper Jun 14, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file modified .DS_Store
Binary file not shown.
17 changes: 15 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@ install_dependency: &install_dependency
sudo apt install jq
sudo pip install awscli --upgrade
sudo pip install docker-compose
no_output_timeout: 30m


install_deploysuite: &install_deploysuite
name: Installation of install_deploysuite.
command: |
git clone --branch v1.4.1 https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript
cp ./../buildscript/master_deploy.sh .
cp ./../buildscript/buildenv.sh .
cp ./../buildscript/awsconfiguration.sh .
no_output_timeout: 30m

build_app: &build_app
name: Build the app
command: |
./build.sh
no_output_timeout: 30m


restore_cache_settings_for_build: &restore_cache_settings_for_build
key: docker-node-modules-{{ checksum "package-lock.json" }}

Expand All @@ -29,7 +41,7 @@ builddeploy_steps: &builddeploy_steps
- run: *install_dependency
- run: *install_deploysuite
- restore_cache: *restore_cache_settings_for_build
- run: ./build.sh
- run: *build_app
- save_cache: *save_cache_settings
- deploy:
name: Running MasterScript.
Expand All @@ -39,6 +51,7 @@ builddeploy_steps: &builddeploy_steps
./buildenv.sh -e $DEPLOY_ENV -b ${DEPLOY_ENV}-${APPNAME}-deployvar
source buildenvvar
./master_deploy.sh -d ECS -e $DEPLOY_ENV -t latest -s ${DEPLOY_ENV}-global-appvar,${DEPLOY_ENV}-${APPNAME}-appvar -i ${APPNAME}



jobs:
Expand Down Expand Up @@ -66,7 +79,7 @@ workflows:
context : org-global
filters:
branches:
only: [develop, "feature/Auth0-RS256-Token"]
only: [develop, "issue_443"]

# Production builds are exectuted only on tagged commits to the
# master branch.
Expand Down
1 change: 1 addition & 0 deletions configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ The following config parameters are supported, they are defined in `src/config.j
|AWS_CONNECTION_TIMEOUT | The timeout used to check if the app is healthy. |10000 |
|TC_LOGIN_URL | TC login url | |
|DYNAMODB_WAIT_TABLE_FOR_ACTIVE_TIMEOUT | Dynamodb wait for active timeout |10 minutes |
|TC_API_V5_URL | Topcoder API v5 url for retrieving list of Connect Projects | |


## GitHub OAuth App Setup
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@
"superagent-promise": "^1.1.0",
"typescript": "~2.3.3",
"uuid": "^3.3.2",
"ui-select": "~0.19.8",
"winston": "^2.3.1",
"tc-auth-lib": "topcoder-platform/tc-auth-lib#1.0.1"
},
Expand Down
6 changes: 3 additions & 3 deletions src/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ const GITLAB_MAX_PER_PAGE = Number.MAX_SAFE_INTEGER;
// the access level can be: 10 - GUEST, 20 - REPORTER, 30 - DEVELOPER, 40 - MASTER, 50 - OWNER
const GITLAB_DEFAULT_GROUP_ACCESS_LEVEL = 30;

// The Gitlab access token default expiration in seconds
const GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION = 3600 * 24 * 14;
// The Gitlab access token default expiration in seconds (2 hours expiration)
const GITLAB_ACCESS_TOKEN_DEFAULT_EXPIRATION = 3600 * 2;

// The Gitlab refresh token time in seconds before expiration
// The Gitlab refresh token time in seconds before expiration (5 minute before expiration)
const GITLAB_REFRESH_TOKEN_BEFORE_EXPIRATION = 300;

const GITHUB_OWNER_CALLBACK_URL = '/api/v1/github/owneruser/callback';
Expand Down
97 changes: 94 additions & 3 deletions src/common/db-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,43 @@ async function queryOneIssue(model, repositoryId, number, provider) {
});
}

/**
* Get Issue's id and challengeUUID by repoUrl
* @param {String} repoUrl The repo url
* @returns {Promise<Object>}
*/
async function queryIssueIdChallengeUUIDByRepoUrl(repoUrl) {
return await new Promise((resolve, reject) => {
models.Issue.scan('repoUrl').eq(repoUrl)
.attributes(['id', 'challengeUUID'])
.exec((err, result) => {
if (err) {
return reject(err);
}
return resolve(result);
});
});
}


/**
* Get CopilotPayment's id by challengeUUID
* @param {String} challengeUUID The challengeUUID
* @returns {Promise<String>}
*/
async function queryPaymentIdByChallengeUUID(challengeUUID) {
return await new Promise((resolve, reject) => {
models.CopilotPayment.scan('challengeUUID').eq(challengeUUID)
.attributes(['id'])
.exec((err, result) => {
if (err) {
return reject(err);
}
return resolve(result.id);
});
});
}

/**
* Get single data by query parameters
* @param {Object} model The dynamoose model to query
Expand Down Expand Up @@ -248,6 +285,27 @@ async function queryOneUserMappingByTCUsername(model, tcusername) {
});
}

/**
* Get single data by query parameters
* @param {Object} model The dynamoose model to query
* @param {String} provider The git provider
* @param {String} gitUsername The git username
* @returns {Promise<void>}
*/
async function queryTCUsernameByGitUsername(model, provider, gitUsername) {
return await new Promise((resolve, reject) => {
model.queryOne(`${provider}Username`).eq(gitUsername)
.all()
.exec((err, result) => {
if (err) {
logger.debug(`queryTCUsernameByGitUsername. Error. ${err}`);
return reject(err);
}
return resolve(result.topcoderUsername);
});
});
}

/**
* Get single data by query parameters
* @param {Object} model The dynamoose model to query
Expand All @@ -257,7 +315,7 @@ async function queryOneUserMappingByTCUsername(model, tcusername) {
async function queryOneActiveProject(model, repoUrl) {
return await new Promise((resolve, reject) => {
queryOneActiveRepository(models.Repository, repoUrl).then((repo) => {
if (!repo) resolve(null);
if (!repo || repo.length === 0) resolve(null);
else model.queryOne('id').eq(repo.projectId).consistent()
.exec((err, result) => {
if (err) {
Expand Down Expand Up @@ -470,6 +528,35 @@ async function queryOneOrganisation(model, organisation) {
});
}

/**
* Query one active repository
* @param {String} url the repository url
* @returns {Promise<Object>}
*/
async function queryOneRepository(url) {
return await new Promise((resolve, reject) => {
models.Repository.query({
url,
})
.all()
.exec((err, repos) => {
if (err) {
return reject(err);
}
if (!repos || repos.length === 0) resolve(null);
if (repos.length > 1) {
let error = `Repository's url is unique in this version.
This Error must be caused by old data in the Repository table.
The old version can only guarrentee that the active Repository's url is unique.
Please migrate the old Repository table.`;
logger.debug(`queryOneRepository. Error. ${error}`);
reject(error);
}
return resolve(repos[0]);
});
});
}

/**
* Query one active repository
* @param {Object} model the dynamoose model
Expand All @@ -480,8 +567,8 @@ async function queryOneActiveRepository(model, url) {
return await new Promise((resolve, reject) => {
model.queryOne({
url,
archived: 'false'
})
.filter('archived').eq('false')
.all()
.exec((err, result) => {
if (err) {
Expand All @@ -502,8 +589,8 @@ async function queryActiveRepositoriesExcludeByProjectId(url, projectId) {
return await new Promise((resolve, reject) => {
models.Repository.query({
url,
archived: 'false'
})
.filter('archived').eq('false')
.filter('projectId')
.not().eq(projectId)
.all()
Expand Down Expand Up @@ -580,6 +667,8 @@ async function populateRepoUrls(projectId) {
}

module.exports = {
queryIssueIdChallengeUUIDByRepoUrl,
queryPaymentIdByChallengeUUID,
getById,
getByKey,
scan,
Expand All @@ -597,13 +686,15 @@ module.exports = {
queryOneActiveProject,
queryOneActiveProjectWithFilter,
queryOneActiveRepository,
queryOneRepository,
queryOneOrganisation,
queryOneIssue,
queryOneUserByType,
queryOneUserByTypeAndRole,
queryOneUserGroupMapping,
queryOneUserTeamMapping,
queryOneUserMappingByTCUsername,
queryTCUsernameByGitUsername,
queryRepositoriesByProjectId,
queryRepositoryByProjectIdFilterUrl
};
61 changes: 55 additions & 6 deletions src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const bcrypt = require('bcryptjs');
const moment = require('moment');
const parseDomain = require('parse-domain');
const config = require('../config');
const kafka = require('../utils/kafka');
const models = require('../models');
const logger = require('./logger');
const errors = require('./errors');
const constants = require('./constants');
Expand Down Expand Up @@ -120,6 +122,52 @@ function buildController(controller) {
});
}

/**
* Convert github api error.
* @param {String} copilotHandle the copilot handle
* @param {String} provider the git provider
*/
async function sendTokenExpiredEvent(copilotHandle, provider) {
const notificationTokenExpiredEvent = {
event: 'notification.tokenExpired',
data: {
copilotHandle,
provider,
},
};
await kafka.send(JSON.stringify(notificationTokenExpiredEvent));
}

/**
* Convert github api error.
* @param {Error} err the github api error
* @param {String} message the error message
* @param {String} gitUsername the git username
* @returns {Error} converted error
*/
async function convertGitHubErrorAsync(err, message, gitUsername) {
if (err.statusCode === 401 && gitUsername) { // eslint-disable-line no-magic-numbers
const copilotHandle = await dbHelper.queryTCUsernameByGitUsername(models.GithubUserMapping, 'github', gitUsername);
await sendTokenExpiredEvent(copilotHandle, 'Github');
}
return convertGitHubError(err, message);
}

/**
* Convert gitlab api error.
* @param {Error} err the gitlab api error
* @param {String} message the error message
* @param {String} gitUsername the git username
* @returns {Error} converted error
*/
async function convertGitLabErrorAsync(err, message, gitUsername) {
if (err.statusCode === 401 && gitUsername) { // eslint-disable-line no-magic-numbers
const copilotHandle = await dbHelper.queryTCUsernameByGitUsername(models.GitlabUserMapping, 'gitlab', gitUsername);
await sendTokenExpiredEvent(copilotHandle, 'Gitlab');
}
return convertGitLabError(err, message);
}

/**
* Convert github api error.
* @param {Error} err the github api error
Expand Down Expand Up @@ -209,24 +257,23 @@ async function getProviderType(repoUrl) {

/**
* gets the git username of copilot/owner for a project
* @param {Object} models the db models
* @param {Object} project the db project detail
* @param {String} provider the git provider
* @param {Boolean} isCopilot if true, then get copilot, otherwise get owner
* @returns {Object} the owner/copilot for the project
*/
async function getProjectCopilotOrOwner(models, project, provider, isCopilot) {
async function getProjectCopilotOrOwner(project, provider, isCopilot) {
const userMapping = await dbHelper.queryOneUserMappingByTCUsername(
provider === 'github' ? models.GithubUserMapping : models.GitlabUserMapping,
provider === 'github' ? models.GithubUserMapping : models.GitlabUserMapping,
isCopilot ? project.copilot : project.owner);

if (!userMapping ||
(provider === 'github' && !userMapping.githubUserId)
if (!userMapping ||
(provider === 'github' && !userMapping.githubUserId)
|| (provider === 'gitlab' && !userMapping.gitlabUserId)) {
throw new Error(`Couldn't find ${isCopilot ? 'copilot' : 'owner'} username for '${provider}' for this repository.`);
}

let user = await dbHelper.queryOneUserByType(models.User,
let user = await dbHelper.queryOneUserByType(models.User,
provider === 'github' ? userMapping.githubUsername : // eslint-disable-line no-nested-ternary
userMapping.gitlabUsername, provider);

Expand Down Expand Up @@ -270,6 +317,8 @@ module.exports = {
buildController,
convertGitHubError,
convertGitLabError,
convertGitHubErrorAsync,
convertGitLabErrorAsync,
ensureExists,
ensureExistsWithKey,
generateIdentifier,
Expand Down
10 changes: 10 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,4 +83,14 @@ module.exports.frontendConfigs = {
TOPCODER_URL: process.env.TOPCODER_URL || 'https://topcoder-dev.com',
GITHUB_TEAM_URL: process.env.GITHUB_TEAM_URL || 'https://github.com/orgs/',
GITLAB_GROUP_URL: process.env.GITLAB_GROUP_URL || 'https://gitlab.com/groups/',
TC_API_V5_URL: process.env.TC_API_V5_URL || 'https://api.topcoder-dev.com/v5',
TOPCODER_VALUES: {
dev: {
TC_API_V4_URL: process.env.TC_API_V4_URL || 'https://api.topcoder-dev.com/v4',
},
prod: {
TC_API_V4_URL: process.env.TC_API_V4_URL || 'https://api.topcoder.com/v4',
},
},
TOPCODER_ENV: process.env.TOPCODER_ENV || 'dev',
};
8 changes: 5 additions & 3 deletions src/controllers/GithubController.js
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ async function addUserToTeamCallback(req, res) {
const token = result.body.access_token;

// get team details
const teamDetails = await GithubService.getTeamDetails(team.ownerToken, team.teamId);
const teamDetails = await GithubService.getTeamDetails(team.ownerUsername, team.ownerToken, team.teamId);
const organisation = teamDetails.organization.login;

// Add member to organisation
Expand All @@ -173,7 +173,8 @@ async function addUserToTeamCallback(req, res) {

// add user to team
console.log(`adding ${token} to ${team.teamId} with ${team.ownerToken}`); /* eslint-disable-line no-console */
const githubUser = await GithubService.addTeamMember(team.teamId, team.ownerToken, token, team.accessLevel);
const githubUser = await GithubService.addTeamMember(
team.ownerUsername, team.teamId, team.ownerToken, token, team.accessLevel);
// associate github username with TC username
const mapping = await dbHelper.queryOneUserMappingByTCUsername(GithubUserMapping, req.session.tcUsername);

Expand Down Expand Up @@ -247,7 +248,8 @@ async function deleteUsersFromTeam(req, res) {
});
// eslint-disable-next-line no-restricted-syntax
for (const userTeamMapItem of userTeamMappings) {
await GithubService.deleteUserFromGithubTeam(token, teamId, githubOrgId, userTeamMapItem.githubUserName);
await GithubService.deleteUserFromGithubTeam(
teamInDB.ownerUsername, token, teamId, githubOrgId, userTeamMapItem.githubUserName);
await dbHelper.removeById(UserTeamMapping, userTeamMapItem.id);
}
} catch (err) {
Expand Down
Loading