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

Commit aa99384

Browse files
committed
Initial commit of combined Ragnar / TC-X-UI / TC-X-Backend
0 parents  commit aa99384

File tree

145 files changed

+31943
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

145 files changed

+31943
-0
lines changed

.DS_Store

8 KB
Binary file not shown.

Procfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
web: node app.js

README.md

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# lagertha
2+
3+
## Requirements
4+
5+
- Nodejs 8 is required
6+
- MongoDB 3.2
7+
- kafka
8+
9+
10+
## Install dependencies
11+
12+
```shell
13+
npm install
14+
```
15+
16+
## Source code lint
17+
18+
eslint is used to lint the javascript source code:
19+
20+
```shell
21+
npm run lint
22+
```
23+
24+
## Endpoints
25+
26+
- GET /github/owneruser/login - github owner user login, using GitHub OAuth
27+
- GET /github/owneruser/callback - github owner user login OAuth callback
28+
- GET /github/owneruser/teams - github owner user views his/her teams
29+
- GET /github/teams/:id/registrationurl - github owner user creates a registration URL for his/her team
30+
- GET /github/teams/registration/:identifier - normal user registers a team via this API, it will do GitHub OAuth
31+
- GET /github/normaluser/callback - normal user GitHub OAuth callback
32+
33+
- GET /gitlab/owneruser/login - gitlab owner user login, using GitLab OAuth
34+
- GET /gitlab/owneruser/callback - gitlab owner user login OAuth callback
35+
- GET /gitlab/owneruser/groups - gitlab owner user views his/her groups
36+
- GET /gitlab/groups/:id/registrationurl - gitlab owner user creates a registration URL for his/her group
37+
- GET /gitlab/groups/registration/:identifier - normal user registers a group via this API, it will do GitLab OAuth
38+
- GET /gitlab/normaluser/callback - normal user GitLab OAuth callback
39+
40+
- GET /tclogin - TopCoder login
41+
- GET /admin/tcuser - get TopCoder/GitLab/GitHub user mapping
42+
43+
- GET /projects - gets the projects
44+
- POST /projects - creates a project
45+
- put /projects - updates the project
46+
- post /projects/label - create labels in project
47+
- post /projects/hook - create webhooks in the project repository
48+
- GET /users/settings - gets the current user's setup
49+
- GET /users/accessToken - gets the user's access token
50+
51+
## Configuration
52+
53+
Map the localhost to topcoderx.topcoder.com by editing `hosts` file.
54+
55+
The following config parameters are supported, they are defined in `config.js` and can be configured in system environment:
56+
57+
58+
| Name | Description | Default |
59+
| :------------------------------------- | :----------------------------------------: | :------------------------------: |
60+
| PORT | the port the application will listen on | 80 |
61+
| API_VERSION | the API version | v1 |
62+
| LOG_LEVEL | the log level | info |
63+
| MONGODB_URI | the MongoDB URI | mongodb://localhost:27017/topcoderx |
64+
| PASSWORD_HASH_SALT_LENGTH | the password hash salt length | 10 |
65+
| SESSION_SECRET | the session secret | kjsdfkj34857 |
66+
| GITHUB_CLIENT_ID | the GitHub client id | |
67+
| GITHUB_CLIENT_SECRET | the GitHub client secret | |
68+
| GITLAB_CLIENT_ID | the GitLab client id | |
69+
| GITLAB_CLIENT_SECRET | the GitLab client secret | |
70+
| WEBSITE | used as base to construct various URLs | http://topcoderx.topcoder.com/ |
71+
72+
| GITLAB_API_BASE_URL | The Gitlab API base URL | https://gitlab.com/api/v4 |
73+
74+
| TC_LOGIN_URL | URL to do TopCoder login | |
75+
| TC_USER_PROFILE_URL | URL to to call TopCoder API to get profile from token | https://accounts.topcoder.com/member?retUrl=http:%2F%2Ftopcoderx.topcoder.com%2Fapi%2Fv1%2Ftclogin |
76+
|TOPIC | kafka topic| |
77+
|KAFKA_OPTIONS | kafka options| |
78+
79+
Other are just constants which don't need to be changed unless modified in code level.
80+
81+
## FE Configs
82+
83+
The frontend config file contains following variables to be configured in `src/front/config.js`
84+
85+
| Name | Description |
86+
|--------------------------|---------------------------------|
87+
| ADMIN_TOOL_URL | URL of the admin tool API |
88+
| COOKIES_SECURE | If true the cookies set by this App will only be transmitted over secure protocols like https. |
89+
| AUTH_URL | Url of Topcoder auth form |
90+
| ACCOUNTS_CONNECTOR_URL | Url to TC account connector |
91+
| JWT_V3_NAME | jwt V3 cookie name |
92+
| JWT_V2_NAME | jwt V2 cookie name |
93+
| DIRECT_URL_BASE | URL to be used for constructing the direct url|
94+
| LABELS | Labels we are going to add to the repository|
95+
| LABELS_COLOR | The colors for each label above |
96+
| HOOK_BASE_URL | The generated ngrok url of receiver service|
97+
98+
## GitHub OAuth App Setup
99+
100+
- login into github.com
101+
- click the upper right avatar, then click `Settings`
102+
- click the left panel --> Developer settings --> OAuth Apps
103+
- click the `Register a new application`, fill in the fields,
104+
note that the `Authorization callback URL` should be the deployed web site,
105+
for local deployment, it should be `http://topcoderx.topcoder.com`
106+
- after creating the OAuth app, you can see its client id and client secret,
107+
these should be set to GITHUB_CLIENT_ID and GITHUB_CLIENT_SECRET environment variables
108+
109+
## GitLab OAuth App Setup
110+
111+
- login into gitlab.com
112+
- click the upper right avatar, then click `Settings`
113+
- click the `Applications` tab
114+
- enter application name, e.g. `Topcoder-x`
115+
- for Redirect URI, enter two callback URLs, one callback URL per line, so there are two lines:
116+
http://topcoderx.topcoder.com/api/v1/gitlab/owneruser/callback
117+
http://topcoderx.topcoder.com/api/v1/gitlab/normaluser/callback
118+
- for Scopes, check the `api` and `read_user`, the `api` is for owner user, the `read_user` is for normal user
119+
- finally click `Save application` to save the OAuth app, then you will see its generated Application Id and Secret,
120+
these should be set to GITLAB_CLIENT_ID and GITLAB_CLIENT_SECRET environment variables
121+
122+
## Local Setup
123+
124+
```shell
125+
npm run serve
126+
```
127+
128+
Server should be started at port 80.
129+
130+
## Postman
131+
132+
Import docs/Ragnar.postman_collection.json and docs/Ragnar.postman_environment.json to Postman.
133+
134+
After admin login, the admin token is automatically set to ADMIN-TOKEN environment variable,
135+
then you may run the `Save GitHub User` and `Save GitLab User` tests to create owner user of your GitHub/GitLab usernames,
136+
note that you must modify the request body username to use your GitHub/GitLab user names.
137+
For the `Get User Mapping` test, you may quety mapping by providing either topcoderUsername, githubUsername or gitlabUsername.
138+
139+
## Verification
140+
141+
- run `npm serve` to start the app
142+
- go to topcoderx.topcoder.com and it will redirect to Topcoder login page, after successful login it will redirect back to Topcoder x app.
143+
- go to settings by clicking username at top right corner
144+
- setup both git provider to authorize topcoder-x to manage your repo on behalf of you
145+
- go to project management and create/edit projects, create hook and label
146+
- go to git access control menu and check list of groups have authorized
147+
- click get link button to get the shareable link which can be used by topcoder member to self assign to the repository.
148+
149+
## Heroku Deployment
150+
Follow the below steps to deploy the app to heroku
151+
1. `heroku login`
152+
2. `heroku create`
153+
3. `heroku config:set NPM_CONFIG_PRODUCTION=false` so that heroku will install dev dependencies
154+
5. `git push heroku master` or `git push heroku develop:master` to deploy develop branch
155+
6. `heroku open` to load the app on browser
156+
157+
NOTE: Once environment variable are changed in heroku please run
158+
`heroku run npm run build`

gulp/browserify.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
var gulp = require('gulp');
2+
3+
var paths = gulp.paths;
4+
5+
var browserify = require('browserify');
6+
var uglify = require('gulp-uglify');
7+
var buffer = require('vinyl-buffer');
8+
var source = require('vinyl-source-stream');
9+
var gutil = require('gulp-util');
10+
var fs = require('fs');
11+
12+
gulp.task('browserify', ['styles'], function () {
13+
14+
var cssFilePath = paths.tmp + '/serve/app/bundle.css';
15+
16+
//delete file if exist
17+
if (fs.existsSync(cssFilePath)) {
18+
fs.unlinkSync(cssFilePath);
19+
}
20+
21+
return browserify('./src/front/src/index.js')
22+
.transform(require('browserify-css'), {
23+
rootDir: 'src',
24+
debug: true,
25+
onFlush: function (options, done) {
26+
fs.appendFileSync(cssFilePath, options.data);
27+
28+
// Do not embed CSS into a JavaScript bundle
29+
done(null);
30+
}
31+
})
32+
.bundle()
33+
.on('error', function (e) {
34+
gutil.log("Browserify Error", gutil.colors.red(e.message))
35+
})
36+
//Pass desired output filename to vinyl-source-stream
37+
.pipe(source('bundle.js'))
38+
.pipe(buffer())
39+
.pipe(uglify())
40+
.pipe(gulp.dest(paths.tmp + '/serve/app'))
41+
});

gulp/build.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
'use strict';
2+
3+
var gulp = require('gulp');
4+
var eslint = require('gulp-eslint');
5+
6+
var paths = gulp.paths;
7+
8+
var $ = require('gulp-load-plugins')({
9+
pattern: ['gulp-*', 'uglify-save-license', 'del']
10+
});
11+
12+
gulp.task('partials', function () {
13+
return gulp.src([
14+
paths.src + '/{app,components}/**/*.html',
15+
paths.tmp + '/{app,components}/**/*.html'
16+
])
17+
.pipe($.minifyHtml({
18+
empty: true,
19+
spare: true,
20+
quotes: true
21+
}))
22+
.pipe($.angularTemplatecache('templateCacheHtml.js', {
23+
module: 'topcoderX'
24+
}))
25+
.pipe(gulp.dest(paths.tmp + '/partials/'));
26+
});
27+
28+
gulp.task('html', ['inject', 'partials'], function () {
29+
var partialsInjectFile = gulp.src(paths.tmp + '/partials/templateCacheHtml.js', { read: false });
30+
var partialsInjectOptions = {
31+
starttag: '<!-- inject:partials -->',
32+
ignorePath: paths.tmp + '/partials',
33+
addRootSlash: false
34+
};
35+
36+
var htmlFilter = $.filter('*.html');
37+
var jsFilter = $.filter('**/*.js');
38+
var cssFilter = $.filter('**/*.css');
39+
var assets;
40+
41+
return gulp.src(paths.tmp + '/serve/*.html')
42+
.pipe($.inject(partialsInjectFile, partialsInjectOptions))
43+
.pipe(assets = $.useref.assets())
44+
.pipe($.rev())
45+
.pipe(jsFilter)
46+
.pipe($.ngAnnotate())
47+
.pipe($.uglify({ preserveComments: $.uglifySaveLicense }))
48+
.pipe(jsFilter.restore())
49+
.pipe(cssFilter)
50+
.pipe($.replace(/\.?\.?\/node_modules\/\w+-?\/?\w+\/fonts\/?/g, '../fonts/'))
51+
.pipe($.csso())
52+
.pipe(cssFilter.restore())
53+
.pipe(assets.restore())
54+
.pipe($.useref())
55+
.pipe($.revReplace())
56+
.pipe(htmlFilter)
57+
.pipe($.minifyHtml({
58+
empty: true,
59+
spare: true,
60+
quotes: true
61+
}))
62+
.pipe(htmlFilter.restore())
63+
.pipe(gulp.dest(paths.dist + '/'))
64+
.pipe($.size({ title: paths.dist + '/', showFiles: true }));
65+
});
66+
67+
gulp.task('images', function () {
68+
return gulp.src(paths.src + '/assets/images/**/*')
69+
.pipe(gulp.dest(paths.dist + '/assets/images/'));
70+
});
71+
72+
gulp.task('fonts', function () {
73+
return gulp.src([
74+
"node_modules/bootstrap/dist/fonts/*.{eot,svg,ttf,woff,woff2}",
75+
"node_modules/footable/css/fonts/*.{eot,svg,ttf,woff,woff2}"
76+
])
77+
.pipe($.filter('**/*.{eot,svg,ttf,woff,woff2}'))
78+
.pipe($.flatten())
79+
.pipe(gulp.dest(paths.dist + '/fonts/'))
80+
.pipe(gulp.dest(paths.dist + '/styles/fonts/'));
81+
});
82+
83+
gulp.task('fontawesome', function () {
84+
return gulp.src('node_modules/font-awesome/fonts/*.{eot,svg,ttf,woff,woff2}')
85+
.pipe(gulp.dest(paths.dist + '/fonts/'));
86+
});
87+
88+
gulp.task('misc', function () {
89+
return gulp.src(paths.src + '/**/*.ico')
90+
.pipe(gulp.dest(paths.dist + '/'));
91+
});
92+
93+
gulp.task('clean', function (done) {
94+
$.del([paths.dist + '/', paths.tmp + '/', paths.src + '/app/config.js'], done);
95+
});
96+
97+
gulp.task('lint', () => {
98+
// ESLint ignores files with "node_modules" paths.
99+
// So, it's best to have gulp ignore the directory as well.
100+
// Also, Be sure to return the stream from the task;
101+
// Otherwise, the task may end before the stream has finished.
102+
return gulp.src(['src/**/*.js', '!src/front/e2e/**/*.js', '!src/public/**', '!gulp/**', '!node_modules/**'])
103+
// eslint() attaches the lint output to the "eslint" property
104+
// of the file object so it can be used by other modules.
105+
.pipe(eslint({
106+
fix: true
107+
}))
108+
// eslint.format() outputs the lint results to the console.
109+
// Alternatively use eslint.formatEach() (see Docs).
110+
.pipe(eslint.format())
111+
// To have the process exit with an error code (1) on
112+
// lint error, return the stream and pipe to failAfterError last.
113+
.pipe(eslint.failAfterError());
114+
});
115+
116+
gulp.task('build', ['ng-config', 'lint', 'html', 'images', 'fonts', 'fontawesome', 'misc']);
117+
gulp.task('build:watch', ['watch:build']);

gulp/e2e-tests.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
'use strict';
2+
3+
var gulp = require('gulp');
4+
5+
var $ = require('gulp-load-plugins')();
6+
7+
var browserSync = require('browser-sync');
8+
9+
var paths = gulp.paths;
10+
11+
// Downloads the selenium webdriver
12+
gulp.task('webdriver-update', $.protractor.webdriver_update);
13+
14+
gulp.task('webdriver-standalone', $.protractor.webdriver_standalone);
15+
16+
function runProtractor (done) {
17+
18+
gulp.src(paths.e2e + '/**/*.js')
19+
.pipe($.protractor.protractor({
20+
configFile: 'protractor.conf.js',
21+
}))
22+
.on('error', function (err) {
23+
// Make sure failed tests cause gulp to exit non-zero
24+
throw err;
25+
})
26+
.on('end', function () {
27+
// Close browser sync server
28+
browserSync.exit();
29+
done();
30+
});
31+
}
32+
33+
gulp.task('protractor', ['protractor:src']);
34+
gulp.task('protractor:src', ['serve:e2e', 'webdriver-update'], runProtractor);
35+
gulp.task('protractor:dist', ['serve:e2e-dist', 'webdriver-update'], runProtractor);

gulp/inject.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
var gulp = require('gulp');
4+
5+
var paths = gulp.paths;
6+
7+
var $ = require('gulp-load-plugins')();
8+
9+
10+
gulp.task('inject', ['browserify'], function () {
11+
12+
var injectStyles = gulp.src([
13+
paths.tmp + '/serve/{app,components}/**/*.css',
14+
'!' + paths.tmp + '/serve/app/vendor.css'
15+
], { read: false });
16+
17+
var injectScripts = gulp.src([
18+
paths.src + '/{app,components}/**/*.js',
19+
'!' + paths.src + '/{app,components}/**/*.spec.js',
20+
'!' + paths.src + '/{app,components}/**/*.mock.js'
21+
]).pipe($.angularFilesort());
22+
23+
var injectOptions = {
24+
ignorePath: [paths.src, paths.tmp + '/serve'],
25+
addRootSlash: false
26+
};
27+
28+
return gulp.src(paths.src + '/*.html')
29+
.pipe($.inject(injectStyles, injectOptions))
30+
.pipe($.inject(injectScripts, injectOptions))
31+
.pipe(gulp.dest(paths.tmp + '/serve'));
32+
33+
});

0 commit comments

Comments
 (0)