Skip to content

A web application for online judge, built with MEAN stack(MongoDB, Express, Angular and Node.js).

License

Notifications You must be signed in to change notification settings

Bit-Developer/online-judge-mean

Repository files navigation

Online Judge

A web application for online judge(algorithm questions), built with MEAN stack(MongoDB, Express, Angular and Node.js).

image

image

Function

This application is used to solve algorithm questions. You can submit the solution to see if it passes all test cases. Below are the available features.

  • Token Based Authentication - Register, Login, Auto Login, User Profile, Reset Password, etc.
  • User Management - Create, Update, Delete user.
  • Question Management - Create, Update, Delete question.
  • Database Management - Import and Export data with csv files for users, questions and submissions.
  • Judging System - Judging Engine, Solution Template, Submission History, Multi-programming language support.
  • Programming Languages - Three languages are currently supported, including Java, Javascript and Python.
  • UI - RichTextEditor, Code Editor, Progress Bar, Loading Image are applied.

The following functions are under development.

  • Contest - Generate contest by randomly selecting four questions from the question library.
  • Collaborative code editor - Different users can work on the same solution simultaneously.

Technology

The Server is built with Express and MongoDB. The used libraries for server are listed as follows.

  • RESTful API: express, express router, mongoose, cors
  • Logging: morgan, winston
  • User Authentication: jsonwebtoken, passport, cookie-parser, express-jwt
  • Import/Export Data: multer, csv-express, fast-csv

The Client is built with Angular and 3rd-party libraries, see below.

  • CSS and Icon: bootstrap, font-awesome
  • Rich Text Editor: ngx-quill
  • Code Editor: ngx-monaco-editor
  • Progress Bar: ngx-progressbar

Demo

Three available demos:

Note: The demo websites may be slow when you access them for the first time. Be patient!

Try it out on any live demo website with the following accounts:

  • Regular User: demo / 123456
  • Administrator: admin / 123456

Setup Locally

1. Source Files

git clone https://github.com/jojozhuang/online-judge-mean.git
cd online-judge-mean
npm install
npm run dev

Access http://localhost:9020/ in web browser, enjoy!

npm install -g win-node-env

2. Configuration

Notice, four different environments are configured for this app. Edit './server/config/server-config.js' to setup your site, especially the MongoDB connection url.

Environment Command Description
local npm run local Development environment using local MongoDB.
dev npm run dev Development environment using remote MongoDB hosted on mLab.
stage npm run stage Testing environment using remote MongoDB hosted on mLab.
prod npm run prod Production environment for deployment.

3. Master Date

When the server is initially started, use admin user 'jojozhuang' and password '111111' to login. Go to 'Database' to import data for 'users' and 'questions'. The data files are located in 'backup_csv' folder.

Deployment

Follow tutorial Online Judge - Deploying Full Stack Angular App to Heroku to deploy this app to Heroku(RESTful API + Frontend Angular).

Follow tutorial Online Judge - Continuously Deploy MEAN Stack App to Heroku and Netlify with Travis-CI to continuously deploy this Full Stack app to Heroku(RESTful API) and Netlify(Frontend Angular).

Steps(Updated on July 17, 2021)

Manually deploy the same git repo to two apps in heroku. Use Multi Procfile buildpack to deploy multiple apps in a monorepo.

Server

Create app online-judge-api for backend api.

cd online-judge-mean
heroku login
heroku create -a online-judge-api
heroku buildpacks:add -a online-judge-api heroku-community/multi-procfile
heroku buildpacks:add -a online-judge-api heroku/nodejs
heroku config:set -a online-judge-api PROCFILE=server/Procfile
git push https://git.heroku.com/online-judge-api.git HEAD:master

Output.

-----> Building on the Heroku-20 stack
-----> Using buildpacks:
       1. heroku-community/multi-procfile
       2. heroku/nodejs
-----> Multi-procfile app detected
       Copied server/Procfile as Procfile successfully
-----> Node.js app detected

-----> Creating runtime environment

       NPM_CONFIG_LOGLEVEL=error
       NODE_VERBOSE=false
       NODE_ENV=production
       NODE_MODULES_CACHE=true

-----> Installing binaries
       engines.node (package.json):  14.16.1
       engines.npm (package.json):   6.14.12

       Resolving node version 14.16.1...
       Downloading and installing node 14.16.1...
       npm 6.14.12 already installed with node

-----> Installing dependencies
       Installing node modules

       > [email protected] install /tmp/build_8088dee8/node_modules/webpack-dev-server/node_modules/fsevents
       > node install.js


       Skipping 'fsevents' build as platform linux is not supported

       > [email protected] postinstall /tmp/build_8088dee8/node_modules/@angular-devkit/build-angular/node_modules/core-js
       > node -e "try{require('./postinstall')}catch(e){}"


       > [email protected] postinstall /tmp/build_8088dee8/node_modules/nodemon
       > node bin/postinstall || exit 0

       Love nodemon? You can now support the project via the open collective:
        > https://opencollective.com/nodemon/donate


       > [email protected] postinstall /tmp/build_8088dee8/node_modules/core-js
       > node -e "try{require('./postinstall')}catch(e){}"


       > @angular/[email protected] postinstall /tmp/build_8088dee8/node_modules/@angular/cli
       > node ./bin/postinstall/script.js

       added 1973 packages in 35.405s

-----> Build
       Running build

       > [email protected] build /tmp/build_8088dee8
       > ng build --configuration production

- Generating browser application bundles (phase: setup)...
Compiling @angular/core : es2015 as esm2015
Compiling @angular/common : es2015 as esm2015
Compiling @angular/platform-browser : es2015 as esm2015
Compiling @angular/platform-browser-dynamic : es2015 as esm2015
Compiling @angular/router : es2015 as esm2015
Compiling ngx-bootstrap/utils : es2015 as esm2015
Compiling ngx-bootstrap/alert : es2015 as esm2015
Compiling ngx-bootstrap/positioning : es2015 as esm2015
Compiling ngx-bootstrap/component-loader : es2015 as esm2015
Compiling ngx-bootstrap/modal : es2015 as esm2015
Compiling @angular/common/http : es2015 as esm2015
Compiling ngx-progressbar : es2015 as esm2015
Compiling ngx-progressbar/http : es2015 as esm2015
Compiling @angular/forms : es2015 as esm2015
Compiling ngx-quill : es2015 as esm2015
✔ Browser application bundle generation complete.
- Generating ES5 bundles for differential loading...
✔ Browser application bundle generation complete.
✔ ES5 bundle generation complete.
- Copying assets...
✔ Copying assets complete.
- Generating index html...
✔ Index html generation complete.

       Initial Chunk Files                      | Names                |      Size
       main-es5.90ba2f4cb80e5b7dd7ab.js         | main                 | 601.20 kB
       main-es2015.90ba2f4cb80e5b7dd7ab.js      | main                 | 516.32 kB
       scripts.21f0c1bd71e842514f91.js          | scripts              | 460.58 kB
       styles.c5cddc00a67a7685f4e0.css          | styles               | 201.41 kB
       polyfills-es5.848e1e43cddfc69fa565.js    | polyfills-es5        | 132.31 kB
       polyfills-es2015.656bc0fb7423ef9ac49a.js | polyfills            |  36.13 kB
       runtime-es2015.fa0d675be33153add91d.js   | runtime              |   3.50 kB
       runtime-es5.fa0d675be33153add91d.js      | runtime              |   3.50 kB

       | Initial ES5 Total    |   1.37 MB
       | Initial ES2015 Total |   1.19 MB

       Lazy Chunk Files                         | Names                |      Size
       161-es5.6c645a8d348aedb1bc37.js          | -                    | 208.98 kB
       161-es2015.6c645a8d348aedb1bc37.js       | -                    | 208.98 kB

       Build at: 2021-07-18T07:54:32.380Z - Hash: f951e994350c45380bd0 - Time: 159327ms
Warning: /tmp/build_8088dee8/src/app/interceptor/error.interceptor.ts depends on 'rxjs/add/operator/catch'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_8088dee8/src/app/interceptor/error.interceptor.ts depends on 'rxjs/add/operator/do'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_8088dee8/src/app/interceptor/error.interceptor.ts depends on 'rxjs/observable/throw'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_8088dee8/src/app/interceptor/timeout.interceptor.ts depends on 'rxjs/add/operator/timeout'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_8088dee8/src/app/services/alert.service.ts depends on 'rxjs/Subject'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_8088dee8/src/app/services/user.service.ts depends on 'rxjs/add/operator/map'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies

-----> Caching build
       - node_modules

-----> Pruning devDependencies
       removed 1269 packages and audited 705 packages in 17.322s

       44 packages are looking for funding
         run `npm fund` for details

       found 1 moderate severity vulnerability
         run `npm audit fix` to fix them, or `npm audit` for details

-----> Build succeeded!
-----> Discovering process types
       Procfile declares types -> web
-----> Compressing...
       Done: 108.9M
-----> Launching...
       Released v5
       https://online-judge-api.herokuapp.com/ deployed to Heroku

Client

Create app online-judge-mean for client website.

cd online-judge-mean
heroku login
heroku create -a online-judge-mean
heroku buildpacks:add -a online-judge-mean heroku-community/multi-procfile
heroku buildpacks:add -a online-judge-mean heroku/nodejs
heroku config:set -a online-judge-mean PROCFILE=Procfile
git push https://git.heroku.com/online-judge-mean.git HEAD:master

Output.

-----> Building on the Heroku-20 stack
-----> Using buildpacks:
       1. heroku-community/multi-procfile
       2. heroku/nodejs
-----> Multi-procfile app detected
cp: '/tmp/build_d0cd865f/Procfile' and '/tmp/build_d0cd865f/Procfile' are the same file
       Copied Procfile as Procfile successfully
-----> Node.js app detected

-----> Creating runtime environment

       NPM_CONFIG_LOGLEVEL=error
       NODE_VERBOSE=false
       NODE_ENV=production
       NODE_MODULES_CACHE=true

-----> Installing binaries
       engines.node (package.json):  14.16.1
       engines.npm (package.json):   6.14.12

       Resolving node version 14.16.1...
       Downloading and installing node 14.16.1...
       npm 6.14.12 already installed with node

-----> Installing dependencies
       Installing node modules

       > [email protected] install /tmp/build_d0cd865f/node_modules/webpack-dev-server/node_modules/fsevents
       > node install.js


       Skipping 'fsevents' build as platform linux is not supported

       > [email protected] postinstall /tmp/build_d0cd865f/node_modules/@angular-devkit/build-angular/node_modules/core-js
       > node -e "try{require('./postinstall')}catch(e){}"


       > [email protected] postinstall /tmp/build_d0cd865f/node_modules/nodemon
       > node bin/postinstall || exit 0

       Love nodemon? You can now support the project via the open collective:
        > https://opencollective.com/nodemon/donate


       > [email protected] postinstall /tmp/build_d0cd865f/node_modules/core-js
       > node -e "try{require('./postinstall')}catch(e){}"


       > @angular/[email protected] postinstall /tmp/build_d0cd865f/node_modules/@angular/cli
       > node ./bin/postinstall/script.js

       added 1973 packages in 36.795s

-----> Build
       Running build

       > [email protected] build /tmp/build_d0cd865f
       > ng build --configuration production

- Generating browser application bundles (phase: setup)...
Compiling @angular/core : es2015 as esm2015
Compiling @angular/common : es2015 as esm2015
Compiling @angular/platform-browser : es2015 as esm2015
Compiling @angular/platform-browser-dynamic : es2015 as esm2015
Compiling @angular/router : es2015 as esm2015
Compiling ngx-bootstrap/utils : es2015 as esm2015
Compiling ngx-bootstrap/alert : es2015 as esm2015
Compiling ngx-bootstrap/positioning : es2015 as esm2015
Compiling ngx-bootstrap/component-loader : es2015 as esm2015
Compiling ngx-bootstrap/modal : es2015 as esm2015
Compiling @angular/common/http : es2015 as esm2015
Compiling ngx-progressbar : es2015 as esm2015
Compiling ngx-progressbar/http : es2015 as esm2015
Compiling @angular/forms : es2015 as esm2015
Compiling ngx-quill : es2015 as esm2015
✔ Browser application bundle generation complete.
- Generating ES5 bundles for differential loading...
✔ Browser application bundle generation complete.
✔ ES5 bundle generation complete.
- Copying assets...
✔ Copying assets complete.
- Generating index html...
✔ Index html generation complete.

       Initial Chunk Files                      | Names                |      Size
       main-es5.90ba2f4cb80e5b7dd7ab.js         | main                 | 601.20 kB
       main-es2015.90ba2f4cb80e5b7dd7ab.js      | main                 | 516.32 kB
       scripts.21f0c1bd71e842514f91.js          | scripts              | 460.58 kB
       styles.c5cddc00a67a7685f4e0.css          | styles               | 201.41 kB
       polyfills-es5.848e1e43cddfc69fa565.js    | polyfills-es5        | 132.31 kB
       polyfills-es2015.656bc0fb7423ef9ac49a.js | polyfills            |  36.13 kB
       runtime-es2015.fa0d675be33153add91d.js   | runtime              |   3.50 kB
Warning: /tmp/build_d0cd865f/src/app/interceptor/error.interceptor.ts depends on 'rxjs/add/operator/catch'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_d0cd865f/src/app/interceptor/error.interceptor.ts depends on 'rxjs/add/operator/do'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_d0cd865f/src/app/interceptor/error.interceptor.ts depends on 'rxjs/observable/throw'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_d0cd865f/src/app/interceptor/timeout.interceptor.ts depends on 'rxjs/add/operator/timeout'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_d0cd865f/src/app/services/alert.service.ts depends on 'rxjs/Subject'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
Warning: /tmp/build_d0cd865f/src/app/services/user.service.ts depends on 'rxjs/add/operator/map'. CommonJS or AMD dependencies can cause optimization bailouts.
For more info see: https://angular.io/guide/build#configuring-commonjs-dependencies
       runtime-es5.fa0d675be33153add91d.js      | runtime              |   3.50 kB

       | Initial ES5 Total    |   1.37 MB
       | Initial ES2015 Total |   1.19 MB

       Lazy Chunk Files                         | Names                |      Size
       161-es5.6c645a8d348aedb1bc37.js          | -                    | 208.98 kB
       161-es2015.6c645a8d348aedb1bc37.js       | -                    | 208.98 kB

       Build at: 2021-07-18T07:59:51.947Z - Hash: 147819932479913ef35d - Time: 169249ms

-----> Caching build
       - node_modules

-----> Pruning devDependencies
       removed 1269 packages and audited 705 packages in 17.991s

       44 packages are looking for funding
         run `npm fund` for details

       found 1 moderate severity vulnerability
         run `npm audit fix` to fix them, or `npm audit` for details

-----> Build succeeded!
-----> Discovering process types
       Procfile declares types -> web
-----> Compressing...
       Done: 109M
-----> Launching...
       Released v4
       https://online-judge-mean.herokuapp.com/ deployed to Heroku

Update

Server.

cd online-judge-mean
heroku login
heroku git:remote -a online-judge-api
git commit --allow-empty -m "Upgrading to heroku-20"
git push heroku master

Client.

cd online-judge-mean
heroku login
heroku git:remote -a online-judge-mean
git commit --allow-empty -m "Upgrading to heroku-20"
git push heroku master

How to deploy Angular app to Heroku and serve it as static site(Fake PHP App)

1. composer.json

A PHP app on Heroku requires a composer.json at the root of the directory structure, or an index.php for legacy behavior. Create composer.json in Angular root directory. In composer.json, add the following line.

{}

2. index.php

Create index.php in src folder. In index.php, add the following line:

<?php include_once("home.html"); ?>

3. home.html

Create src/home.html by copying file src/index.html.

4. Copy home.html and index.php to dist folder

Edit angular.json, modify build/options/index and add index.php to assets. Thus, home.html and index.php will be copied into the output folder dist during build.

  "build": {
    "builder": "@angular-devkit/build-angular:browser",
    "options": {
      "outputPath": "dist",
      "index": "src/home.html",
      ...
      "assets": [
        ...
        "src/index.php"
      ],

5. Procfile

A Procfile is a text file in the root directory of your application that defines process types and explicitly declares what command should be executed to start your app. Create Procfile as follows. It will direct heroku to start apache server to serve folder dist.

web: vendor/bin/heroku-php-apache2 dist/

6. Create heroku app and add buildpack

You can do it through heroku CLI or its website.

6.1 Heroku CLI

cd online-judge-mean
heroku login
heroku create -a online-judge-mean
heroku buildpacks:add -a online-judge-mean heroku/nodejs
heroku buildpacks:add -a online-judge-mean heroku/php

The above commands creates a heroku app named online-judge-mean. And adds nodejs buildpack and php buildpack. The nodejs buildpack will compile the Angular app and the php buildpack will serve the output static files as php site.

6.2 Heroku Dashboard

You can also create the app through heorku website. Go to https://dashboard.heroku.com/apps, click Create new app, provide the app name. Go to settings->Buildpacks->Add buildpack, heroku/nodejs first, heroku/php second.

7. Deploy site

Switch to Deploy tab and connect it to your GitHub repo. Then, click Deploy Branch button. Heroku will start the build and launch your site successfully.

8. Example logs

-----> Building on the Heroku-20 stack
-----> Using buildpacks:
       1. heroku/nodejs
       2. heroku/php
-----> Node.js app detected

-----> Creating runtime environment

       NPM_CONFIG_LOGLEVEL=error
       NODE_VERBOSE=false
       NODE_ENV=production
       NODE_MODULES_CACHE=true

-----> Installing binaries
       engines.node (package.json):  14.16.1
       engines.npm (package.json):   6.14.12

       Resolving node version 14.16.1...
       Downloading and installing node 14.16.1...
       npm 6.14.12 already installed with node

-----> Installing dependencies
       Installing node modules
       ...
-----> Build
       Running build

       > [email protected] build /tmp/build_2955a863
       > ng build --configuration production

       ...

-----> Caching build
       - node_modules
       ...

-----> Build succeeded!
-----> PHP app detected
-----> Bootstrapping...
-----> Installing platform packages...
       NOTICE: No runtime required in composer.lock; using PHP ^7.3.0 | ^8.0.0
       - php (8.0.9)
       - composer (1.10.22)
       - apache (2.4.48)
       - nginx (1.20.1)
-----> Installing dependencies...
       Composer version 1.10.22 2021-04-27 13:10:45
-----> Preparing runtime environment...
-----> Checking for additional extensions to install...
-----> Discovering process types
       Procfile declares types -> web
-----> Compressing...
       Done: 123.2M
-----> Launching...
       Released v3
       https://online-judge-mean.herokuapp.com/ deployed to Heroku

9. References

Troubleshooting

Check the buildpack.

$ heroku git:remote -a online-judge-api
$ heroku buildpacks
=== online-judge-api Buildpack URLs
1. heroku-community/multi-procfile
2. heroku/nodejs

Use the default nodejs buildpack.

heroku buildpacks:set heroku/nodejs

Don't select "Wait for CI to pass before deploy" as Travis-CI is not configured for this GitHub repo.

References:

Portfolio

Read portfolio Online Judge(MEAN) to learn the main functions of this MEAN stack app.

Tutorial

Read tutorial Online Judge - Building Web App with MEAN Stack to learn how this MEAN stack app is built.

Docker

Build for production. All the compiled html files and js files will be generated in dist.

npm run build-nas

Create image with node.

docker build -t jojozhuang/online-judge-server .
docker build -t jojozhuang/online-judge-web .

Create container.

docker run --name online-judge-server -p 9021:80 -d jojozhuang/online-judge-server
docker run --name online-judge-web -p 9020:80 -d jojozhuang/online-judge-web

Access http://192.168.0.2:9020/ in browser.

Rich text editor

To show the math formula correctly in description or solution, need to install katex and add its css and js to angular.js.

  "styles": [
    "./node_modules/katex/dist/katex.min.css",
  ],
  "scripts": [
    "./node_modules/katex/dist/katex.min.js"
  ],