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

changes for #17 #15 #16 #20

Merged
merged 1 commit into from
Jun 18, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ Note: heroku domain should match subdomain of topcoder-dev or topcoder depending

## Verification

- run `npm serve` to start the app
- run `npm run serve` to start the app
- go to topcoderx.topcoder-dev.com and it will redirect to Topcoder login page, after successful login it will redirect back to Topcoder x app.
- go to settings by clicking username at top right corner
- setup both git provider to authorize topcoder-x to manage your repo on behalf of you
Expand Down
367 changes: 337 additions & 30 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"mongoose": "^4.11.9",
"octonode": "^0.9.2",
"pace-js": "~1.0.2",
"parse-domain": "^2.1.2",
"shortid": "^2.2.8",
"superagent": "^3.6.0",
"superagent-promise": "^1.1.0",
Expand Down
43 changes: 42 additions & 1 deletion src/common/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,16 @@ const getParams = require('get-parameter-names');
const bluebird = require('bluebird');
const uuid = require('uuid/v4');
const bcrypt = require('bcryptjs');
const parseDomain = require('parse-domain');
const config = require('../config');
const logger = require('./logger');
const errors = require('./errors');
const constants = require('./constants');
const NotFoundError = require('./errors').NotFoundError;
const ValidationError = require('./errors').ValidationError;

bluebird.promisifyAll(bcrypt);
bluebird.promisifyAll(parseDomain);

/**
* Convert array with arguments to object
Expand Down Expand Up @@ -82,7 +85,7 @@ function _decorateWithValidators(service) {
const params = getParams(method);
service[name] = async function serviceMethodWithValidation(...args) {
const value = _combineObject(params, args);
const normalized = Joi.attempt(value, method.schema, {abortEarly: false});
const normalized = Joi.attempt(value, method.schema, { abortEarly: false });
// Joi will normalize values
// for example string number '1' to 1
// if schema type is number
Expand Down Expand Up @@ -188,6 +191,42 @@ async function ensureExists(Model, criteria) {
return result;
}

/**
* get the provider name from git repo url
* @param {String} repoUrl the project repo URL
* @returns {String} the provider
*/
async function getProviderType(repoUrl) {
const parsedDomain = await parseDomain(repoUrl);
if (!parsedDomain || !parsedDomain.domain || (parsedDomain.domain !== 'github' && parsedDomain.domain !== 'gitlab')) {
throw new ValidationError('Invalid git repo url');
}
return parsedDomain.domain;
}

/**
* gets the git username of copilot for a project
* @param {Object} models the db models
* @param {Object} project the db project detail
* @param {String} provider the git provider
* @returns {Object} the owner/copilot for the project
*/
async function getProjectOwner(models, project, provider) {
const userMapping = await models.UserMapping.findOne({
topcoderUsername: project.username,
});

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

const copilot = await models.User.findOne({
username: provider === 'github' ? userMapping.githubUsername : userMapping.gitlabUsername,
type: provider,
});
return copilot;
}


/**
* Generate an unique identifier
Expand All @@ -206,4 +245,6 @@ module.exports = {
convertGitLabError,
ensureExists,
generateIdentifier,
getProviderType,
getProjectOwner,
};
10 changes: 5 additions & 5 deletions src/controllers/ProjectController.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ const ProjectService = require('../services/ProjectService');
* @returns {Object} the result
*/
async function create(req) {
return await ProjectService.create(req.body);
return await ProjectService.create(req.body, req.currentUser.handle);
}

/**
Expand All @@ -28,7 +28,7 @@ async function create(req) {
* @returns {Object} the result
*/
async function update(req) {
return await ProjectService.update(req.body);
return await ProjectService.update(req.body, req.currentUser.handle);
}

/**
Expand All @@ -37,7 +37,7 @@ async function update(req) {
* @returns {Array} the result
*/
async function getAll(req) {
return await ProjectService.getAll(req.query.status);
return await ProjectService.getAll(req.query.status, req.currentUser.handle);
}

/**
Expand All @@ -47,7 +47,7 @@ async function getAll(req) {
* @returns {Object} the result
*/
async function createLabel(req) {
return await ProjectService.createLabel(req.body);
return await ProjectService.createLabel(req.body, req.currentUser.handle);
}

/**
Expand All @@ -57,7 +57,7 @@ async function createLabel(req) {
* @returns {Object} the result
*/
async function createHook(req) {
return await ProjectService.createHook(req.body);
return await ProjectService.createHook(req.body, req.currentUser.handle);
}

module.exports = {
Expand Down
35 changes: 20 additions & 15 deletions src/front/src/.eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
"rules": {
"angular/no-service-method": 0,
"angular/window-service": 0,
"angular/di": [2, "array"],
"angular/di": [
2,
"array"
],
"angular/angularelement": 0,
"angular/timeout-service": 0,
"max-params": 0,
Expand All @@ -14,24 +17,26 @@
"valid-jsdoc": 0,
"require-jsdoc": 0,
"no-magic-numbers": 0,
"no-invalid-this" : 0,
"no-nested-ternary" : 0,
"no-void" : 0,
"consistent-return" : 0,
"lodash/prefer-includes" : 0,
"one-var" : 0,
"no-restricted-syntax" : 0,
"func-style" : 0,
"vars-on-top" : 0,
"func-names" : 0,
"prefer-rest-params" : 0,
"no-var":0,
"no-inner-declarations":0
"no-invalid-this": 0,
"no-nested-ternary": 0,
"no-void": 0,
"consistent-return": 0,
"lodash/prefer-includes": 0,
"one-var": 0,
"no-restricted-syntax": 0,
"func-style": 0,
"vars-on-top": 0,
"func-names": 0,
"prefer-rest-params": 0,
"no-var": 0,
"no-inner-declarations": 0,
"prefer-arrow-callback": 0,
"prefer-template":0,
},
"env": {
"browser": true,
"commonjs": true,
"es6": true,
"jquery": true
}
}
}
2 changes: 1 addition & 1 deletion src/front/src/app/projects/projects.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ <h4>You don't have active projects right now. Please
</tr>
</thead>
<tbody>
<tr ng-repeat="project in projects" class="animate-repeat" ng-class-even="'footable-even'" ng-class-odd="'footable-odd'">
<tr ng-repeat="project in projects" ng-class-even="'footable-even'" ng-class-odd="'footable-odd'">
<td class="col-lg-2">{{project.title}}</td>
<td class="col-lg-2">
<a href="{{directUrlBase}}{{project.tcDirectId}}" target="_blank">{{project.tcDirectId}}</a>
Expand Down
99 changes: 21 additions & 78 deletions src/front/src/app/upsertproject/upsertproject.controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,20 +8,20 @@
angular.module('topcoderX').controller('ProjectController', ['currentUser', '$scope', '$timeout', 'ProjectService',
'$rootScope', '$state', 'Alert', function (currentUser, $scope, $timeout, ProjectService, $rootScope, $state, Alert) {

//Maintain the navigation state.
// Maintain the navigation state.
$timeout(function () {
angular.element('#projectsManagement').addClass('active');
}, 0);

//below logic is trying to identify whether we are editing a project
// below logic is trying to identify whether we are editing a project
$scope.editing = true;
$scope.project = {
'title': '',
'tcDirectId': '',
'repoUrl': '',
'rocketChatWebhook': null,
'rocketChatChannelName': null,
'archived': false
title: '',
tcDirectId: '',
repoUrl: '',
rocketChatWebhook: null,
rocketChatChannelName: null,
archived: false,
};
if ($rootScope.project) {
$scope.title = 'Edit a Project';
Expand All @@ -33,97 +33,40 @@ angular.module('topcoderX').controller('ProjectController', ['currentUser', '$sc
$scope.editing = false;
}

//represents the repo owner
$scope.repoOwner = '';

//represents the repo name
$scope.repoName = '';

//represents the repo is located at github or gitlab
$scope.repoType = '';

//function to get the repo's owner and the repo's name based on repoUrl
const getRepoDetail = function (repoUrl, callback, errorCallBack) {
$scope.$broadcast('alert.ClearAll', {});
if (repoUrl.endsWith('/')) {
repoUrl = repoUrl.slice(0, -1);
}
const results = repoUrl.split('/');
$scope.repoName = results[results.length - 1];
$scope.repoOwner = results[results.length - 2];
$scope.repoType = results[results.length - 3].split('.')[0];
ProjectService.getUserToken($scope.repoOwner, $scope.repoType).then(function (response) {
if (angular.isDefined(response.data.token)) {
$scope.token = response.data.token;
return callback();
} else {
const erroMessage = 'Token not found for the user ' + $scope.repoOwner + ' of type ' + $scope.repoType + ' please complete profile setting';
Alert.error(erroMessage, $scope);
}
}, function (error) {
errorCallBack(error);
});
};

//function to add labels to the current project.
// function to add labels to the current project.
$scope.addLabels = function () {
getRepoDetail($scope.project.repoUrl, function () {
// for (var i = 0; i < $rootScope.config.LABELS.length; i++) {
var objc = {
'repoOwner': $scope.repoOwner,
'repoName': $scope.repoName,
'repoToken': $scope.token,

'repoType': $scope.repoType
};
ProjectService.createLabel(objc).then(function () {
Alert.info('Label Added Successfully', $scope);
}).catch(function (error) {
Alert.error(error.data.message, $scope);
});
// }
}, function (error) {
ProjectService.createLabel({ projectId: $scope.project.id }).then(function () {
Alert.info('Label Added Successfully', $scope);
}).catch(function (error) {
Alert.error(error.data.message, $scope);
});
};

//function to add hooks to the current project.
// function to add hooks to the current project.
$scope.addHooks = function () {
getRepoDetail($scope.project.repoUrl, function () {
var objc = {
'repoOwner': $scope.repoOwner,
'repoName': $scope.repoName,
'repoToken': $scope.token,
'repoType': $scope.repoType,
'projectId': $scope.project.id
};
ProjectService.createHooks(objc).then(function () {
Alert.info('Webhook Added Successfully', $scope);
}).catch(function (error) {
Alert.error(error.data.message, $scope);
});
}, function (error) {
ProjectService.createHooks({ projectId: $scope.project.id }).then(function () {
Alert.info('Webhook Added Successfully', $scope);
}).catch(function (error) {
Alert.error(error.data.message, $scope);
});
};

//save the project info to database, and go back to project list view.
// save the project info to database, and go back to project list view.
$scope.save = function () {
$scope.project.username = $rootScope.currentUser.handle;
if ($scope.editing) {
ProjectService.update($scope.project).then(function () {
Alert.info('Project Updated Successfully', $scope);
$state.go('app.projects');
}).catch((function (error) {
}).catch(function (error) {
Alert.error(error.data.message, $scope);
}))
});
} else {
ProjectService.create($scope.project).then(function () {
Alert.info('Project Created Successfully', $scope);
$state.go('app.projects');
}).catch(function (error) {
Alert.error(error.data.message, $scope);
})
});
}
}
};
}]);
Loading