From: Brendan Hansen Date: Thu, 29 Aug 2019 23:53:59 +0000 (-0500) Subject: initial commit X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=16b973d07a7550f4b344d3d6fff4edfd43c3992b;p=codebox.git initial commit --- 16b973d07a7550f4b344d3d6fff4edfd43c3992b diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2549b3d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.env diff --git a/codebox/.gitignore b/codebox/.gitignore new file mode 100644 index 0000000..536871b --- /dev/null +++ b/codebox/.gitignore @@ -0,0 +1,4 @@ +logs/ +nginx.conf.compiled +*.lua +.tup diff --git a/codebox/Tupfile b/codebox/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/Tuprules.tup b/codebox/Tuprules.tup new file mode 100644 index 0000000..5fa92eb --- /dev/null +++ b/codebox/Tuprules.tup @@ -0,0 +1 @@ +: foreach *.moon |> moonc %f |> %B.lua diff --git a/codebox/app.moon b/codebox/app.moon new file mode 100644 index 0000000..f3e5c87 --- /dev/null +++ b/codebox/app.moon @@ -0,0 +1,3 @@ +-- Doing this allows for the app/ folder to be mounted +-- via a docker container for faster reloading +require "app.app" diff --git a/codebox/app/Tupfile b/codebox/app/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/app/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/app/app.moon b/codebox/app/app.moon new file mode 100644 index 0000000..25200f7 --- /dev/null +++ b/codebox/app/app.moon @@ -0,0 +1,34 @@ +lapis = require "lapis" +console = require "lapis.console" + +import Users from require "models" +bind = require "utils.binding" + +bind\bind 'test', -> 'Test called!!!' + +bind\bind_static 'executer', require 'facades.executer' +bind\bind_static 'crypto', -> require 'services.crypto' + +class extends lapis.Application + layout: require "views.partials.layout" + + views_prefix: 'views' + flows_prefix: 'flows' + middleware_prefix: 'middleware' + + @before_filter => + @navbar = {} + @navbar.selected = 1 + + ['index': "/"]: require "controllers.index" + ['account.login': "/login"]: require "controllers.account.login" + ['account.logout': "/logout"]: require "controllers.account.logout" + ['account.register': "/register"]: require "controllers.account.register" + + ['executer.status_update': "/executer/status_update"]: require "controllers.executer.status_update" + ['executer.request': '/executer/request']: require "controllers.executer.request" + + [test: "/test"]: => + "Your value is over 10" + + "/console": console.make! diff --git a/codebox/config.moon b/codebox/config.moon new file mode 100644 index 0000000..f6819e2 --- /dev/null +++ b/codebox/config.moon @@ -0,0 +1,15 @@ +config = require "lapis.config" + +config "development", -> + port 8888 + + secret (os.getenv 'APP_SECRET') + req_secret (os.getenv 'REQ_SECRET') + + postgres -> + -- Have to use a fixed ip since the container name + -- was not resolving correctly + host "192.168.0.2" + database (os.getenv 'POSTGRES_DB') + user (os.getenv 'POSTGRES_USER') + password (os.getenv 'POSTGRES_PASSWORD') diff --git a/codebox/controllers/Tupfile b/codebox/controllers/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/controllers/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/controllers/account/Tupfile b/codebox/controllers/account/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/controllers/account/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/controllers/account/login.moon b/codebox/controllers/account/login.moon new file mode 100644 index 0000000..c6caa48 --- /dev/null +++ b/codebox/controllers/account/login.moon @@ -0,0 +1,33 @@ +import make_controller from require "controllers.controller" +import Users from require 'models' +import assert_valid from require "lapis.validate" + +utils = require "lapis.util" + +make_controller + inject: + crypto: 'crypto' + + middleware: { 'logged_out' } + + get: => + @flow 'csrf_setup' + render: 'account.login' + + post: => + @flow 'csrf_validate' + + assert_valid @params, { + { "username", exists: true, min_length: 2 } + { "password", exists: true, min_length: 2 } + } + + users = Users\select "where username = ? limit 1", @params.username + if #users > 0 + if @crypto.verify @params.password, users[1].password_hash + @session.user_id = users[1].id + return redirect_to: @url_for 'index' + + render: 'account.login' + + diff --git a/codebox/controllers/account/logout.moon b/codebox/controllers/account/logout.moon new file mode 100644 index 0000000..23bd44f --- /dev/null +++ b/codebox/controllers/account/logout.moon @@ -0,0 +1,7 @@ +import make_controller from require "controllers.controller" + +make_controller { + get: => + @session.user_id = nil + return redirect_to: @url_for 'index' +} diff --git a/codebox/controllers/account/register.moon b/codebox/controllers/account/register.moon new file mode 100644 index 0000000..9bb399b --- /dev/null +++ b/codebox/controllers/account/register.moon @@ -0,0 +1,48 @@ +import make_controller from require "controllers.controller" +import Users from require 'models' +import assert_valid from require "lapis.validate" +import capture_errors from require 'lapis.application' + +make_controller + inject: + crypto: 'crypto' + + middleware: { 'logged_out' } + + get: => + @flow 'csrf_validate' + render: 'account.register' + + post: capture_errors => + @flow 'csrf_validate' + + assert_valid @params, { + { "username", exists: true, min_length: 2 } + { "nickname", exists: true, min_length: 2 } + { "email", exists: true, min_length: 4, matches_pattern: "%S+@%S+%.%S+" } + { "password", exists: true, min_length: 2 } + { "password_confirmation", exists: true, min_length: 2, equals: @params.password, 'Passwords must be the same' } + } + + users = Users\find username: @params.username + if users + -- Account already exists + @errors or= {} + table.insert @errors, 'Username already taken' + return render: 'account.register' + + user_id = Users\create { + username: @params.username + email: @params.email + nickname: @params.nickname + password_hash: @crypto.encrypt @params.password + } + + unless user_id + @errors or= {} + table.insert @errors, 'Error creating account' + return render: 'account.register' + + @session.user_id = user_id + redirect_to: @url_for 'index' + diff --git a/codebox/controllers/controller.moon b/codebox/controllers/controller.moon new file mode 100644 index 0000000..a9519e1 --- /dev/null +++ b/codebox/controllers/controller.moon @@ -0,0 +1,20 @@ +import respond_to from require "lapis.application" +bind = require 'utils.binding' + +{ + make_controller: (routes) -> + respond_to { + before: => + if routes.inject + for inj, dep in pairs routes.inject + @[inj] = bind\make dep + + return if not routes.middleware + + for middleware in *routes.middleware + require("#{@app.middleware_prefix}.#{middleware}") @ + + GET: => routes.get(@) + POST: => routes.post(@) + } +} diff --git a/codebox/controllers/executer/Tupfile b/codebox/controllers/executer/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/controllers/executer/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/controllers/executer/request.moon b/codebox/controllers/executer/request.moon new file mode 100644 index 0000000..aad1c7a --- /dev/null +++ b/codebox/controllers/executer/request.moon @@ -0,0 +1,25 @@ +import make_controller from require "controllers.controller" +import assert_valid from require "lapis.validate" +import capture_errors from require 'lapis.application' + +make_controller + inject: + executer: 'executer' + + middleware: { 'internal_request' } + + post: capture_errors (=> + assert_valid @params, { + { 'lang', exists: true } + { 'code', exists: true } + { 'problem_id', exists: true, is_integer: true } + } + + id = @executer\request @params.lang, @params.code + + json: id + ), => + json: { status: 'error occured', errors: @errors } + + + diff --git a/codebox/controllers/executer/status_update.moon b/codebox/controllers/executer/status_update.moon new file mode 100644 index 0000000..3a934ff --- /dev/null +++ b/codebox/controllers/executer/status_update.moon @@ -0,0 +1,8 @@ +import make_controller from require "controllers.controller" + +make_controller + middleware: { 'internal_request' } + + post: => + print 'Hit status' + json: { status: 'success' } diff --git a/codebox/controllers/index.moon b/codebox/controllers/index.moon new file mode 100644 index 0000000..a788ddb --- /dev/null +++ b/codebox/controllers/index.moon @@ -0,0 +1,11 @@ +import make_controller from require "controllers.controller" + +import Users, Jobs from require 'models' + +make_controller + middleware: { 'logged_in' } + + get: => + @users = Users\select! + @jobs = @user\get_c_jobs! + render: "index" diff --git a/codebox/facades/Tupfile b/codebox/facades/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/facades/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/facades/executer.moon b/codebox/facades/executer.moon new file mode 100644 index 0000000..f14ec60 --- /dev/null +++ b/codebox/facades/executer.moon @@ -0,0 +1,13 @@ +http = require 'lapis.nginx.http' +import from_json, to_json from require 'lapis.util' + +class ExecuterFacade + request: (lang, code) => + body = http.simple 'http://192.168.0.4:8080/submit', { + lang: lang + code: code + } + + from_json(body).id + + diff --git a/codebox/flows/Tupfile b/codebox/flows/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/flows/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/flows/csrf_setup.moon b/codebox/flows/csrf_setup.moon new file mode 100644 index 0000000..a360fe3 --- /dev/null +++ b/codebox/flows/csrf_setup.moon @@ -0,0 +1,5 @@ +csrf = require "lapis.csrf" + +=> + @csrf_token = csrf.generate_token @ + return diff --git a/codebox/flows/csrf_validate.moon b/codebox/flows/csrf_validate.moon new file mode 100644 index 0000000..54ca956 --- /dev/null +++ b/codebox/flows/csrf_validate.moon @@ -0,0 +1,5 @@ +csrf = require "lapis.csrf" + +=> + csrf.assert_token @ + @csrf_token = csrf.generate_token @ diff --git a/codebox/middleware/Tupfile b/codebox/middleware/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/middleware/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/middleware/internal_request.moon b/codebox/middleware/internal_request.moon new file mode 100644 index 0000000..edca0af --- /dev/null +++ b/codebox/middleware/internal_request.moon @@ -0,0 +1,8 @@ +config = (require 'lapis.config').get! + +=> + if @params.request_token != config.req_secret + @write { + status: 401 + json: { status: 'Unauthorized' } + } diff --git a/codebox/middleware/logged_in.moon b/codebox/middleware/logged_in.moon new file mode 100644 index 0000000..55b17ad --- /dev/null +++ b/codebox/middleware/logged_in.moon @@ -0,0 +1,12 @@ +import Users from require 'models' + +=> + if not @session.user_id + @write redirect_to: @url_for 'account.login' + return + + @user = Users\find(@session.user_id) + if not @user + @session.user_id = nil + @write redirect_to: @url_for 'account.login' + return diff --git a/codebox/middleware/logged_out.moon b/codebox/middleware/logged_out.moon new file mode 100644 index 0000000..4d80975 --- /dev/null +++ b/codebox/middleware/logged_out.moon @@ -0,0 +1,6 @@ +import Users from require 'models' + +=> + if @session.user_id + @user = Users\find(@session.user_id) + @write redirect_to: @url_for 'index' if @user diff --git a/codebox/migrations.moon b/codebox/migrations.moon new file mode 100644 index 0000000..74e2f8d --- /dev/null +++ b/codebox/migrations.moon @@ -0,0 +1,38 @@ +import create_table, types from require "lapis.db.schema" + +{ + [1]: => + create_table "users", { + { "id", types.serial }, + { "username", types.varchar }, + { "password_hash", types.varchar }, + { "nickname", types.varchar }, + { "email", types.varchar }, + + "PRIMARY KEY (id)" + } + + [2]: => + create_table "jobs", { + { "id", types.serial }, + { "user_id", types.foreign_key }, + { "problem_id", types.foreign_key }, + { "status", types.text null: true }, + { "lang", types.varchar }, + { "code", types.text null: true }, + { "time_initiated", types.time }, + + "PRIMARY KEY (id)" + } + + [3]: => + create_table "problems", { + { "id", types.serial }, + { "name", types.varchar }, + { "kind", types.enum }, + { "description", types.text null: true }, + { "time_limit", types.integer }, + + "PRIMARY KEY (id)" + } +} diff --git a/codebox/mime.types b/codebox/mime.types new file mode 100644 index 0000000..292f886 --- /dev/null +++ b/codebox/mime.types @@ -0,0 +1,81 @@ +types { + text/html html htm shtml; + text/css css; + text/xml xml; + image/gif gif; + image/jpeg jpeg jpg; + application/x-lua lua; + application/x-moonscript moon; + application/x-javascript js; + application/atom+xml atom; + application/rss+xml rss; + + text/mathml mml; + text/plain txt; + text/vnd.sun.j2me.app-descriptor jad; + text/vnd.wap.wml wml; + text/x-component htc; + + image/png png; + image/tiff tif tiff; + image/vnd.wap.wbmp wbmp; + image/x-icon ico; + image/x-jng jng; + image/x-ms-bmp bmp; + image/svg+xml svg svgz; + image/webp webp; + + application/java-archive jar war ear; + application/mac-binhex40 hqx; + application/msword doc; + application/pdf pdf; + application/postscript ps eps ai; + application/rtf rtf; + application/vnd.ms-excel xls; + application/vnd.ms-powerpoint ppt; + application/vnd.wap.wmlc wmlc; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; + application/x-7z-compressed 7z; + application/x-cocoa cco; + application/x-java-archive-diff jardiff; + application/x-java-jnlp-file jnlp; + application/x-makeself run; + application/x-perl pl pm; + application/x-pilot prc pdb; + application/x-rar-compressed rar; + application/x-redhat-package-manager rpm; + application/x-sea sea; + application/x-shockwave-flash swf; + application/x-stuffit sit; + application/x-tcl tcl tk; + application/x-x509-ca-cert der pem crt; + application/x-xpinstall xpi; + application/xhtml+xml xhtml; + application/zip zip; + + application/octet-stream bin exe dll; + application/octet-stream deb; + application/octet-stream dmg; + application/octet-stream eot; + application/octet-stream iso img; + application/octet-stream msi msp msm; + + audio/midi mid midi kar; + audio/mpeg mp3; + audio/ogg ogg; + audio/x-m4a m4a; + audio/x-realaudio ra; + + video/3gpp 3gpp 3gp; + video/mp4 mp4; + video/mpeg mpeg mpg; + video/quicktime mov; + video/webm webm; + video/x-flv flv; + video/x-m4v m4v; + video/x-mng mng; + video/x-ms-asf asx asf; + video/x-ms-wmv wmv; + video/x-msvideo avi; +} diff --git a/codebox/models.moon b/codebox/models.moon new file mode 100644 index 0000000..70be8f2 --- /dev/null +++ b/codebox/models.moon @@ -0,0 +1,2 @@ +import autoload from require "lapis.util" +autoload "models" diff --git a/codebox/models/Tupfile b/codebox/models/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/models/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/models/jobs.moon b/codebox/models/jobs.moon new file mode 100644 index 0000000..45be721 --- /dev/null +++ b/codebox/models/jobs.moon @@ -0,0 +1,7 @@ +import Model from require "lapis.db.model" + +class Jobs extends Model + @relations: { + { 'user', belongs_to: 'Users' } + { 'problem', belongs_to: 'Problems' } + } diff --git a/codebox/models/problems.moon b/codebox/models/problems.moon new file mode 100644 index 0000000..577e475 --- /dev/null +++ b/codebox/models/problems.moon @@ -0,0 +1,12 @@ +import Model, enum from require "lapis.db.model" + +class Problems extends Model + @kinds: enum { + code: 1 + golf: 2 + word: 3 + } + + @relations: { + { "jobs", has_many: 'Jobs' } + } diff --git a/codebox/models/users.moon b/codebox/models/users.moon new file mode 100644 index 0000000..d8b29e9 --- /dev/null +++ b/codebox/models/users.moon @@ -0,0 +1,10 @@ +import Model from require "lapis.db.model" + +class Users extends Model + @relations: { + { 'jobs', has_many: 'Jobs' } + { 'c_jobs' + has_many: 'Jobs' + where: { lang: 'C' } + } + } diff --git a/codebox/nginx.conf b/codebox/nginx.conf new file mode 100644 index 0000000..c90f83e --- /dev/null +++ b/codebox/nginx.conf @@ -0,0 +1,62 @@ +worker_processes ${{NUM_WORKERS}}; +error_log stderr notice; +daemon off; +pid logs/nginx.pid; + +events { + worker_connections 1024; +} + +env APP_SECRET; +env REQ_SECRET; +env POSTGRES_DB; +env POSTGRES_USER; +env POSTGRES_PASSWORD; + +http { + include mime.types; + + server { + listen ${{PORT}}; + lua_code_cache ${{CODE_CACHE}}; + + location / { + set $_url "http://192.168.0.4:8080"; + + default_type text/html; + content_by_lua ' + require("lapis").serve("app") + '; + } + + location /static/ { + alias static/; + } + + location /favicon.ico { + alias static/favicon.ico; + } + location /proxy { + internal; + rewrite_by_lua " + local req = ngx.req + + for k,v in pairs(req.get_headers()) do + if k ~= 'content-length' then + req.clear_header(k) + end + end + + if ngx.ctx.headers then + for k,v in pairs(ngx.ctx.headers) do + req.set_header(k, v) + end + end + "; + + resolver 8.8.8.8; + proxy_http_version 1.1; + proxy_pass $_url; + } + } +} diff --git a/codebox/services/Tupfile b/codebox/services/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/services/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/services/crypto.moon b/codebox/services/crypto.moon new file mode 100644 index 0000000..1ebedaa --- /dev/null +++ b/codebox/services/crypto.moon @@ -0,0 +1,14 @@ +bcrypt = require "bcrypt" + +import Users from require "models" + +ROUNDS = 10 + +{ + encrypt: (data) -> + bcrypt.digest(data, ROUNDS) + + verify: (data, digest) -> + bcrypt.verify(data, digest) +} + diff --git a/codebox/static/Tupfile b/codebox/static/Tupfile new file mode 100644 index 0000000..a7ec031 --- /dev/null +++ b/codebox/static/Tupfile @@ -0,0 +1,2 @@ +: scss/core.scss |> sass %f:css/%B.css |> css/%B.css css/%B.css.map +: coffee/*.coffee |> coffee -c -m -o js/%B.js %f |> js/%B.js js/%B.js.map diff --git a/codebox/static/coffee/main.coffee b/codebox/static/coffee/main.coffee new file mode 100644 index 0000000..478d195 --- /dev/null +++ b/codebox/static/coffee/main.coffee @@ -0,0 +1,2 @@ +main = -> + console.log "Hello world!" diff --git a/codebox/static/css/core.css b/codebox/static/css/core.css new file mode 100644 index 0000000..5b2439b --- /dev/null +++ b/codebox/static/css/core.css @@ -0,0 +1,105 @@ +.navbar { + z-index: 10000; + width: 100%; + background: #0077c2; + height: 47px; + position: relative; + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.7); + display: grid; + grid-template-columns: 1fr 6fr 1fr; +} +.navbar .navbar-logo { + padding-left: 8px; + text-align: center; +} +.navbar .navbar-logo img { + max-height: calc(47px - 2px); + display: inline; +} +.navbar ul { + display: block; + text-align: center; + font-size: 0; +} +.navbar ul a li { + margin: 0; + display: inline-block; + cursor: pointer; + font-size: 24px; + list-style: none; + line-height: 40px; + padding-left: 30px; + padding-right: 30px; + padding-top: 4px; + color: #f2f2f2; + border-top-color: #0077c2; + transition: 200ms all; +} +.navbar ul a li.selected, .navbar ul a li:hover { + border-bottom: 2px solid #ffe766; + color: white; +} + +.sidebar-problem-list { + z-index: 50; + box-shadow: 0 10px 0 0 transparent, 0 10px 0 0 transparent, 10px 0 0 0 transparent, 0 8px 8px 2px rgba(0, 0, 0, 0.5); + background: #003252; + position: relative; + min-height: calc(100vh - 47px); +} +.sidebar-problem-list .sidebar-problem { + width: 100%; + display: grid; + grid-template-columns: 32px 1fr; + border-left-width: 24px; + border-left-style: solid; + transition: background-color 200ms east-in-out; + transition: width 200ms east-in-out; + background-color: inherit; + cursor: pointer; +} +.sidebar-problem-list .sidebar-problem[selected], .sidebar-problem-list .sidebar-problem:hover { + width: calc(100% + 24px); +} +.sidebar-problem-list .sidebar-problem[selected] { + background-color: #42a5f5 !important; +} +.sidebar-problem-list .sidebar-problem:hover { + background-color: #128ef2; +} +.sidebar-problem-list .sidebar-problem-letter { + text-align: center; + background-color: #001929; + padding-top: 20px; + padding-bottom: 20px; + font-size: 1.2rem; +} +.sidebar-problem-list .sidebar-problem-name { + text-align: left; + font-size: 1.2rem; + padding-left: 5px; + padding-top: 20px; + padding-bottom: 20px; + margin-left: 10px; + margin-right: 10px; +} + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + font-size: 16px; +} + +body { + font-family: sans-serif; + background: url(/static/imgs/grain_background.png); + background-color: #111; + background-repeat: repeat; + color: white; +} + +/*# sourceMappingURL=core.css.map */ diff --git a/codebox/static/css/core.css.map b/codebox/static/css/core.css.map new file mode 100644 index 0000000..ce00981 --- /dev/null +++ b/codebox/static/css/core.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["../scss/_navbar.scss","../scss/_vars.scss","../scss/problem/_sidebar.scss","../scss/core.scss"],"names":[],"mappings":"AAAA;EACC;EACA;EACA,YCIc;EDHd,QCgBe;EDff;EAEA;EAEA;EACA;;AAEA;EACC;EACA;;AAEA;EACC;EACA;;AAIF;EACC;EACA;EACA;;AAEA;EACC;EACA;EACA;EAEA;EAEA;EACA;EACA;EACA;EACA;EAEA;EACA,kBClCY;EDoCZ;;AAEA;EACC;EACA;;;AE/CJ;EACC;EACA;EACA;EACA;EACA;;AAEA;EACC;EAEA;EACA;EAEA;EACA;EAEA;EACA;EACA;EAEA;;AAEA;EACC;;AAGD;EACC;;AAGD;EACC;;AAIF;EACC;EACA;EACA;EACA;EACA;;AAGD;EACC;EACA;EAEA;EACA;EACA;EAEA;EACA;;;AC9CF;EACC;EACA;EACA;;;AAGD;EACC;;;AAGD;EACC;EAEA;EACA;EACA;EACA","file":"core.css"} \ No newline at end of file diff --git a/codebox/static/imgs/grain_background.png b/codebox/static/imgs/grain_background.png new file mode 100644 index 0000000..765bd27 Binary files /dev/null and b/codebox/static/imgs/grain_background.png differ diff --git a/codebox/static/imgs/logo.png b/codebox/static/imgs/logo.png new file mode 100644 index 0000000..16fc502 Binary files /dev/null and b/codebox/static/imgs/logo.png differ diff --git a/codebox/static/js/main.js b/codebox/static/js/main.js new file mode 100644 index 0000000..695d933 --- /dev/null +++ b/codebox/static/js/main.js @@ -0,0 +1,11 @@ +// Generated by CoffeeScript 2.4.1 +(function() { + var main; + + main = function() { + return console.log("Hello world!"); + }; + +}).call(this); + +//# sourceMappingURL=main.js.map diff --git a/codebox/static/js/main.js.map b/codebox/static/js/main.js.map new file mode 100644 index 0000000..7e307dd --- /dev/null +++ b/codebox/static/js/main.js.map @@ -0,0 +1,13 @@ +{ + "version": 3, + "file": "main.js", + "sourceRoot": "..", + "sources": [ + "coffee/main.coffee" + ], + "names": [], + "mappings": ";AAAA;AAAA,MAAA;;EAAA,IAAA,GAAO,QAAA,CAAA,CAAA;WACN,OAAO,CAAC,GAAR,CAAY,cAAZ;EADM;AAAP", + "sourcesContent": [ + "main = ->\n\tconsole.log \"Hello world!\"\n" + ] +} \ No newline at end of file diff --git a/codebox/static/scss/_elevate.scss b/codebox/static/scss/_elevate.scss new file mode 100644 index 0000000..7a212bc --- /dev/null +++ b/codebox/static/scss/_elevate.scss @@ -0,0 +1,3 @@ +@mixin elevate($e, $col) { + box-shadow: 0px $e (3 * $e) ($e / 4) $col; +} diff --git a/codebox/static/scss/_navbar.scss b/codebox/static/scss/_navbar.scss new file mode 100644 index 0000000..36ef2d1 --- /dev/null +++ b/codebox/static/scss/_navbar.scss @@ -0,0 +1,52 @@ +.navbar { + z-index: 10000; + width: 100%; + background: $primary-dark; + height: $navbar-height; + position: relative; + + box-shadow: 0px 0px 10px 0px rgba(0, 0, 0, 0.7); + + display: grid; + grid-template-columns: 1fr 6fr 1fr; + + .navbar-logo { + padding-left: 8px; + text-align: center; + + img { + max-height: calc(#{$navbar-height} - 2px); + display: inline; + } + } + + ul { + display: block; + text-align: center; + font-size: 0; + + a li { + margin: 0; + display: inline-block; + cursor: pointer; + + font-size: 24px; + + list-style: none; + line-height: 40px; + padding-left: 30px; + padding-right: 30px; + padding-top: 4px; + + color: darken($white, 5); + border-top-color: $primary-dark; + + transition: 200ms all; + + &.selected, &:hover { + border-bottom: 2px solid $secondary-light; + color: white; + } + } + } +} diff --git a/codebox/static/scss/_utils.scss b/codebox/static/scss/_utils.scss new file mode 100644 index 0000000..3d48d4b --- /dev/null +++ b/codebox/static/scss/_utils.scss @@ -0,0 +1,21 @@ +.content { + width: 100%; + padding: 10px 5%; +} + +.right { + float: right; +} + +.left { + float: left; +} + +.hidden { + visibility: hidden; +} + +a { + text-decoration: none; + color: inherit; +} diff --git a/codebox/static/scss/_vars.scss b/codebox/static/scss/_vars.scss new file mode 100644 index 0000000..ccd82bf --- /dev/null +++ b/codebox/static/scss/_vars.scss @@ -0,0 +1,21 @@ +$white: #fff; +$black: #000; + +$content-background: #232323; + +$primary: #42a5f5; +$primary-light: #80d6ff; +$primary-dark: #0077c2; + +$secondary: #FFD700; +$secondary-light: lighten(#FFD700, 20); +$secondary-dark: darken(#FFD700, 20); + +$primary-text: $white; +$secondary-text: $black; + +$test-case-good: #50ff50; +$test-case-bad: #ff5050; +$test-case-pending: #5050ff; + +$navbar-height: 47px; diff --git a/codebox/static/scss/core.scss b/codebox/static/scss/core.scss new file mode 100644 index 0000000..d76fe8c --- /dev/null +++ b/codebox/static/scss/core.scss @@ -0,0 +1,24 @@ +@import '_vars'; +@import '_elevate'; +@import '_navbar'; +@import 'problem/_list.scss'; +@import 'problem/_sidebar.scss'; + +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + font-size: 16px; +} + +body { + font-family: sans-serif; + + background: url(/static/imgs/grain_background.png); + background-color: #111; + background-repeat: repeat; + color: white; +} diff --git a/codebox/static/scss/problem/_list.scss b/codebox/static/scss/problem/_list.scss new file mode 100644 index 0000000..e69de29 diff --git a/codebox/static/scss/problem/_sidebar.scss b/codebox/static/scss/problem/_sidebar.scss new file mode 100644 index 0000000..663b739 --- /dev/null +++ b/codebox/static/scss/problem/_sidebar.scss @@ -0,0 +1,55 @@ +.sidebar-problem-list { + z-index: 50; + box-shadow: 0 10px 0 0 transparent, 0 10px 0 0 transparent, 10px 0 0 0 transparent, 0 8px 8px 2px rgba(0, 0, 0, 0.5); + background: darken($primary-dark, 22); + position: relative; + min-height: calc(100vh - #{$navbar-height}); + + .sidebar-problem { + width: 100%; + + display: grid; + grid-template-columns: 32px 1fr; + + border-left-width: 24px; + border-left-style: solid; + + transition: background-color 200ms east-in-out; + transition: width 200ms east-in-out; + background-color: inherit; + + cursor: pointer; + + &[selected], &:hover { + width: calc(100% + 24px); + } + + &[selected] { + background-color: $primary !important; + } + + &:hover { + background-color: darken($primary, 10); + } + } + + .sidebar-problem-letter { + text-align: center; + background-color: darken($primary-dark, 30); + padding-top: 20px; + padding-bottom: 20px; + font-size: 1.2rem; + } + + .sidebar-problem-name { + text-align: left; + font-size: 1.2rem; + + padding-left: 5px; + padding-top: 20px; + padding-bottom: 20px; + + margin-left: 10px; + margin-right: 10px; + } +} diff --git a/codebox/utils/Tupfile b/codebox/utils/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/utils/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/utils/binding.moon b/codebox/utils/binding.moon new file mode 100644 index 0000000..2f673e0 --- /dev/null +++ b/codebox/utils/binding.moon @@ -0,0 +1,23 @@ +class Binding + new: => + @bindings = {} + @static_bindings = {} + @statics = {} + + bind: (name, service) => + @bindings[name] = service + + bind_static: (name, service) => + @static_bindings[name] = service + + make: (name) => + if @bindings[name] + return @bindings[name]() + elseif @statics[name] + return @statics[name] + elseif @static_bindings[name] + stat = @static_bindings[name]() + @statics[name] = stat + return stat + +return Binding() diff --git a/codebox/views/Tupfile b/codebox/views/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/views/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/views/account/Tupfile b/codebox/views/account/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/views/account/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/views/account/login.moon b/codebox/views/account/login.moon new file mode 100644 index 0000000..0dc3213 --- /dev/null +++ b/codebox/views/account/login.moon @@ -0,0 +1,11 @@ +html = require "lapis.html" + +class Login extends html.Widget + content: => + h1 style: "background-color:red", "Login!" + + form method: 'POST', -> + input type: 'hidden', name: 'csrf_token', value: @csrf_token + input type: 'text', placeholder: 'Username', name: 'username', '' + input type: 'password', placeholder: 'Password', name: 'password', '' + input type: 'submit', value: 'Submit', '' diff --git a/codebox/views/account/register.moon b/codebox/views/account/register.moon new file mode 100644 index 0000000..c0cc4ce --- /dev/null +++ b/codebox/views/account/register.moon @@ -0,0 +1,18 @@ +html = require 'lapis.html' +import to_json from require 'lapis.util' + +class Register extends html.Widget + content: => + h1 style: "background-color:red", "Register" + + p -> + text (to_json @errors) + + form method: 'POST', -> + p -> input type: 'hidden', name: 'csrf_token', value: @csrf_token + p -> input type: 'text', placeholder: 'Username', name: 'username', required: true, '' + p -> input type: 'password', placeholder: 'Password', name: 'password', required: true, '' + p -> input type: 'password', placeholder: 'Confirm Password', name: 'password_confirmation', required: true, '' + p -> input type: 'text', placeholder: 'Email', name: 'email', required: true, '' + p -> input type: 'text', placeholder: 'Display Name', name: 'nickname', required: true, '' + input type: 'submit', value: 'Submit', '' diff --git a/codebox/views/index.moon b/codebox/views/index.moon new file mode 100644 index 0000000..be44bc7 --- /dev/null +++ b/codebox/views/index.moon @@ -0,0 +1,19 @@ +html = require "lapis.html" + +class Index extends html.Widget + content: => + h1 style: "background-color:red", "Hello World!!!" + p "Hello #{@user.nickname}, #{@user.username}, #{@user.email}!" + p "The value is #{@val}" + p "API: #{@api_test}" + + ul -> + for job in *@jobs + li "#{job.lang} - #{job.problem_id} - #{job\get_problem!.name}" + + ul -> + for user in *@users + if user.username == @user.username + li style: "border: 2px solid yellow", "#{user.username} - #{user.email}" + else + li "#{user.username} - #{user.email}" diff --git a/codebox/views/partials/Tupfile b/codebox/views/partials/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/views/partials/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/views/partials/layout.moon b/codebox/views/partials/layout.moon new file mode 100644 index 0000000..79d5a08 --- /dev/null +++ b/codebox/views/partials/layout.moon @@ -0,0 +1,14 @@ +html = require "lapis.html" +Navbar = require 'views.partials.navbar' + +class DefaultLayout extends html.Widget + content: => + html_5 -> + head -> + link rel: "stylesheet", href: "static/css/core.css" + + script type: "text/javascript", src: "static/js/main.js" + + body -> + widget Navbar + @content_for "inner" diff --git a/codebox/views/partials/navbar.moon b/codebox/views/partials/navbar.moon new file mode 100644 index 0000000..b55b4d6 --- /dev/null +++ b/codebox/views/partials/navbar.moon @@ -0,0 +1,12 @@ +html = require 'lapis.html' + +class Navigation extends html.Widget + content: => + div class: 'navbar', -> + div class: 'navbar-logo', -> + img src: '/static/imgs/logo.png' + + ul -> + a -> li class: { 'selected': @navbar.selected == 0 }, 'Leaderboard' + a -> li class: { 'selected': @navbar.selected == 1 }, 'Problems' + a -> li class: { 'selected': @navbar.selected == 2 }, 'Submissions' diff --git a/config.env.example b/config.env.example new file mode 100644 index 0000000..6e4578d --- /dev/null +++ b/config.env.example @@ -0,0 +1,6 @@ +APP_SECRET= +REQ_SECRET= + +POSTGRES_DB=codebox +POSTGRES_USER=username +POSTGRES_PASSWORD=bigsecretpassword diff --git a/docker-compose.yaml b/docker-compose.yaml new file mode 100644 index 0000000..195f128 --- /dev/null +++ b/docker-compose.yaml @@ -0,0 +1,71 @@ +version: '3' + +services: + codebox: + env_file: + - config.env + build: + context: . + dockerfile: ./docker/codebox/Dockerfile + ports: + - 8888:8888 + volumes: + - ./codebox/app:/app/app + - ./codebox/views:/app/views + - ./codebox/flows:/app/flows + - ./codebox/middleware:/app/middleware + - ./codebox/models:/app/models + - ./codebox/controllers:/app/controllers + - ./codebox/utils:/app/utils + - ./codebox/services:/app/services + - ./codebox/facades:/app/facades + - ./codebox/static:/app/static + command: lapis server development + networks: + appnet: + ipv4_address: 192.168.0.3 + + executer: + env_file: + - config.env + build: + context: . + dockerfile: ./docker/executer/Dockerfile + volumes: + - ./executer/app:/app/app + command: node main.js + networks: + appnet: + ipv4_address: 192.168.0.4 + + postgres: + env_file: + - config.env + image: "postgres:12-alpine" + restart: always + networks: + appnet: + ipv4_address: 192.168.0.2 + logging: + driver: none + +networks: + appnet: + driver: bridge + ipam: + config: + - subnet: 192.168.0.0/16 + +# mysql: +# build: +# context: . +# dockerfile: ./docker/mysql/Dockerfile +# environment: +# MYSQL_ROOT_PASSWORD: secret +# MYSQL_DATABASE: codebox +# MYSQL_USER: mysql +# MYSQL_PASSWORD: secret +# ports: +# - 3306:3306 +# logging: +# driver: none diff --git a/docker/codebox/Dockerfile b/docker/codebox/Dockerfile new file mode 100644 index 0000000..30a1925 --- /dev/null +++ b/docker/codebox/Dockerfile @@ -0,0 +1,29 @@ +FROM openresty/openresty:xenial + +RUN apt-get update \ + && apt-get -y install openssl libssl-dev git \ + && luarocks install lapis \ + && luarocks install lapis-console \ + && luarocks install moonscript \ + # && luarocks install openssl \ + # && luarocks install pgmoon \ + # && luarocks install ansicolors \ + # && luarocks install date \ + # && luarocks install etlua \ + # && luarocks install loadkit \ + # && luarocks install lpeg \ + # && luarocks install lua-cjson \ + # && luarocks install luaossl \ + # && luarocks install luafilesystem \ + # && luarocks install luasocket \ + # && luarocks install mimetypes \ + && luarocks install luacrypto \ + && luarocks install bcrypt + +COPY codebox/ /app + +ENV LAPIS_OPENRESTY "/opt/openresty/nginx/sbin/nginx" + +EXPOSE 8888 80 + +WORKDIR /app diff --git a/docker/executer/Dockerfile b/docker/executer/Dockerfile new file mode 100644 index 0000000..efd1e54 --- /dev/null +++ b/docker/executer/Dockerfile @@ -0,0 +1,16 @@ +FROM node:12.9.1 + +RUN yarn global add coffeescript \ + && apt-get update \ + && apt-get install -y libseccomp-dev python3 + +COPY ./executer/package.json /app/package.json +WORKDIR /app +RUN yarn + +COPY ./executer/Tupfile /app/Tupfile +COPY ./executer/Tuprules.tup /app/Tuprules.tup +COPY ./executer/main.js /app/main.js +COPY ./executer/app /app/app + +ENV PATH $(yarn global bin):$PATH diff --git a/executer/.gitignore b/executer/.gitignore new file mode 100644 index 0000000..c2f7987 --- /dev/null +++ b/executer/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +.tup/ +yarn.lock +*.js diff --git a/executer/Tupfile b/executer/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/executer/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/executer/Tuprules.tup b/executer/Tuprules.tup new file mode 100644 index 0000000..9591588 --- /dev/null +++ b/executer/Tuprules.tup @@ -0,0 +1 @@ +: *.coffee |> coffee -c -o %B.js %f |> %B.js diff --git a/executer/app/Tupfile b/executer/app/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/executer/app/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/executer/app/routes.coffee b/executer/app/routes.coffee new file mode 100644 index 0000000..75ea4a5 --- /dev/null +++ b/executer/app/routes.coffee @@ -0,0 +1,22 @@ +request = require 'request' + +module.exports = (app) -> + app.get '/', (req, res) -> + res.json { + test: 'This is test data' + } + + app.post '/submit', (req, res) -> + console.log req.body.lang, req.body.code + + request.post 'http://192.168.0.3:8888/executer/status_update', + { json: true, form: { request_token: process.env.REQ_SECRET } }, + (err, res, body) -> + if err + return console.log err + + console.log body.status + + res.json { + id: 'test' + } diff --git a/executer/main.coffee b/executer/main.coffee new file mode 100644 index 0000000..6216e2d --- /dev/null +++ b/executer/main.coffee @@ -0,0 +1,15 @@ +http = require 'http' +express = require 'express' +morgan = require 'morgan' +bodyParser = require 'body-parser' + +app = express() +app.use (morgan 'dev') +app.use bodyParser.urlencoded { extended: true } + +routes = require './app/routes' +routes(app) + +server = http.createServer(app) +server.listen 8080, -> + console.log 'Started http server on port 8080' diff --git a/executer/package.json b/executer/package.json new file mode 100644 index 0000000..a7fa920 --- /dev/null +++ b/executer/package.json @@ -0,0 +1,14 @@ +{ + "name": "executer", + "version": "1.0.0", + "description": "Executes files", + "main": "main.js", + "author": "Brendan Hansen", + "license": "MIT", + "private": true, + "dependencies": { + "express": "^4.17.1", + "morgan": "^1.9.1", + "request": "^2.88.0" + } +}