From 0535e4001d736b71b324dbeac821058a9d48591e Mon Sep 17 00:00:00 2001 From: Brendan Hansen Date: Mon, 16 Sep 2019 08:35:07 -0500 Subject: [PATCH] Added submitting and viewing submissions --- codebox/app/app.moon | 58 +++++++++---------- codebox/controllers/controller.moon | 9 ++- codebox/controllers/executer/request.moon | 2 +- codebox/controllers/problem/problem.moon | 11 ---- codebox/controllers/problem/submit.moon | 42 ++++++++++++++ codebox/controllers/submission/Tupfile | 1 + codebox/controllers/submission/list.moon | 16 +++++ codebox/controllers/submission/status.moon | 30 ++++++++++ codebox/controllers/submission/view.moon | 25 ++++++++ codebox/facades/executer.moon | 4 +- codebox/static/coffee/pie_chart.coffee | 4 +- codebox/static/coffee/problem_submit.coffee | 22 +++++++ .../static/coffee/submission_reloader.coffee | 11 ++++ codebox/static/js/pie_chart.js | 4 +- codebox/static/js/pie_chart.js.map | 4 +- codebox/static/js/problem_submit.js | 37 ++++++++++++ codebox/static/js/problem_submit.js.map | 13 +++++ codebox/static/js/submission_reloader.js | 24 ++++++++ codebox/static/js/submission_reloader.js.map | 13 +++++ codebox/views/admin/submission/edit.moon | 2 +- codebox/views/partials/navbar.moon | 2 +- codebox/views/partials/problem_sidebar.moon | 27 +++++++++ codebox/views/problem/problem.moon | 14 +---- codebox/views/problem/submit.moon | 25 ++++++++ codebox/views/ssr/job_result.moon | 14 +++-- codebox/views/submission/Tupfile | 1 + codebox/views/submission/list.moon | 5 ++ codebox/views/submission/view.moon | 12 ++++ executer/app/executer.coffee | 20 ++++--- 29 files changed, 374 insertions(+), 78 deletions(-) create mode 100644 codebox/controllers/problem/submit.moon create mode 100644 codebox/controllers/submission/Tupfile create mode 100644 codebox/controllers/submission/list.moon create mode 100644 codebox/controllers/submission/status.moon create mode 100644 codebox/controllers/submission/view.moon create mode 100644 codebox/static/coffee/problem_submit.coffee create mode 100644 codebox/static/coffee/submission_reloader.coffee create mode 100644 codebox/static/js/problem_submit.js create mode 100644 codebox/static/js/problem_submit.js.map create mode 100644 codebox/static/js/submission_reloader.js create mode 100644 codebox/static/js/submission_reloader.js.map create mode 100644 codebox/views/partials/problem_sidebar.moon create mode 100644 codebox/views/problem/submit.moon create mode 100644 codebox/views/submission/Tupfile create mode 100644 codebox/views/submission/list.moon create mode 100644 codebox/views/submission/view.moon diff --git a/codebox/app/app.moon b/codebox/app/app.moon index b2138b2..0bf9670 100644 --- a/codebox/app/app.moon +++ b/codebox/app/app.moon @@ -34,9 +34,13 @@ class extends lapis.Application ['account.logout': "/logout"]: controller "account.logout" ['account.register': "/register"]: controller "account.register" - ['problem': '/problem']: controller "problem.problem" - ['problem.description': '/problem/:problem_name']: controller "problem.problem" - ['problem.submit': '/problem/:problem_name/submit']: controller "problem.submit" + ['problem': '/problems']: controller "problem.problem" + ['problem.description': '/problems/:problem_name']: controller "problem.problem" + ['problem.submit': '/problems/:problem_name/submit']: controller "problem.submit" + + ['submission.list': '/submissions']: controller "submission.list" + ['submission.view': '/submissions/view']: controller "submission.view" + ['submission.status': '/submissions/status']: controller "submission.status" ['executer.status_update': "/executer/status_update"]: controller "executer.status_update" ['executer.request': '/executer/request']: controller "executer.request" @@ -47,33 +51,25 @@ class extends lapis.Application ['admin.user.reset_password': "/admin/user/reset_password"]: controller "admin.user.reset_password" ['admin.user.delete': "/admin/user/delete"]: controller "admin.user.delete" - ['admin.problem': "/admin/problem"]: controller "admin.problem" - ['admin.problem.new': "/admin/problem/new"]: controller "admin.problem.new" - ['admin.problem.edit': "/admin/problem/edit/:problem_name"]: controller "admin.problem.edit" - ['admin.problem.delete': "/admin/problem/delete"]: controller "admin.problem.delete" - - ['admin.testcase.new': "/admin/testcase/new"]: controller "admin.testcase.new" - ['admin.testcase.edit': "/admin/testcase/edit"]: controller "admin.testcase.edit" - ['admin.testcase.delete': "/admin/testcase/delete"]: controller "admin.testcase.delete" - - ['admin.submission': "/admin/submission"]: controller "admin.submission" - ['admin.submission.edit': "/admin/submission/edit"]: controller "admin.submission.edit" - ['admin.submission.delete': "/admin/submission/delete"]: controller "admin.submission.delete" - - ['admin.competition': "/admin/competition"]: controller "admin.competition" - ['admin.competition.new': "/admin/competition/new"]: controller "admin.competition.new" - ['admin.competition.edit': "/admin/competition/edit/:competition_id"]: controller "admin.competition.edit" - ['admin.competition.delete': "/admin/competition/delete/:competition_id"]: controller "admin.competition.delete" - ['admin.competition.add_problem': "/admin/competition/add_problem"]: controller "admin.competition.add_problem" - ['admin.competition.delete_problem': "/admin/competition/delete_problem"]: controller "admin.competition.delete_problem" - ['admin.competition.activate': "/admin/competition/activate/:competition_id"]: controller "admin.competition.activate" - - [test: '/test']: => - table.insert @scripts, "vendor/ace/ace" - @html -> - div style: 'position: relative; width: 100%; height: 15rem', id: 'editor', -> - text "function test() { - console.log('Hello World!'); - }" + ['admin.problem': "/admin/problems"]: controller "admin.problem" + ['admin.problem.new': "/admin/problems/new"]: controller "admin.problem.new" + ['admin.problem.edit': "/admin/problems/edit/:problem_name"]: controller "admin.problem.edit" + ['admin.problem.delete': "/admin/problems/delete"]: controller "admin.problem.delete" + + ['admin.testcase.new': "/admin/testcases/new"]: controller "admin.testcase.new" + ['admin.testcase.edit': "/admin/testcases/edit"]: controller "admin.testcase.edit" + ['admin.testcase.delete': "/admin/testcases/delete"]: controller "admin.testcase.delete" + + ['admin.submission': "/admin/submissions"]: controller "admin.submission" + ['admin.submission.edit': "/admin/submissions/edit"]: controller "admin.submission.edit" + ['admin.submission.delete': "/admin/submissions/delete"]: controller "admin.submission.delete" + + ['admin.competition': "/admin/competitions"]: controller "admin.competition" + ['admin.competition.new': "/admin/competitions/new"]: controller "admin.competition.new" + ['admin.competition.edit': "/admin/competitions/edit/:competition_id"]: controller "admin.competition.edit" + ['admin.competition.delete': "/admin/competitions/delete/:competition_id"]: controller "admin.competition.delete" + ['admin.competition.add_problem': "/admin/competitions/add_problem"]: controller "admin.competition.add_problem" + ['admin.competition.delete_problem': "/admin/competitions/delete_problem"]: controller "admin.competition.delete_problem" + ['admin.competition.activate': "/admin/competitions/activate/:competition_id"]: controller "admin.competition.activate" "/console": console.make! diff --git a/codebox/controllers/controller.moon b/codebox/controllers/controller.moon index b8786a2..16130d9 100644 --- a/codebox/controllers/controller.moon +++ b/codebox/controllers/controller.moon @@ -20,15 +20,18 @@ bind = require 'utils.binding' GET: => r = routes.get(@) - r.layout or= routes.layout + if type(r) == "table" + r.layout or= routes.layout return r POST: => r = routes.post(@) - r.layout or= routes.layout + if type(r) == "table" + r.layout or= routes.layout return r DELETE: => r = routes.delete(@) - r.layout or= routes.layout + if type(r) == "table" + r.layout or= routes.layout return r } } diff --git a/codebox/controllers/executer/request.moon b/codebox/controllers/executer/request.moon index ba86a2e..5c3f77c 100644 --- a/codebox/controllers/executer/request.moon +++ b/codebox/controllers/executer/request.moon @@ -22,7 +22,7 @@ make_controller test_cases = problem\get_test_cases! - id = @executer\request @params.lang, @params.code, @params.problem_id, test_cases, problem.time_limit + id = @executer\request @params.lang, @params.code, 1, @params.problem_id, test_cases, problem.time_limit json: id ), => diff --git a/codebox/controllers/problem/problem.moon b/codebox/controllers/problem/problem.moon index 800385c..2a6db9a 100644 --- a/codebox/controllers/problem/problem.moon +++ b/codebox/controllers/problem/problem.moon @@ -14,19 +14,8 @@ make_controller get: => @navbar.selected = 1 - @current_comp = Competitions\find active: true - @problems = @current_comp\get_problems! - if @params.problem_name @problem = Problems\find short_name: @params.problem_name - for prob in *@problems - if @queries.has_correct_submission @user.id, prob.short_name - print "FOUND CORRECT FOR ", prob.name - prob.tag = "correct" - elseif @queries.has_incorrect_submission @user.id, prob.short_name - print "FOUND INCORRECT FOR ", prob.name - prob.tab = "incorrect" - render: 'problem.problem' diff --git a/codebox/controllers/problem/submit.moon b/codebox/controllers/problem/submit.moon new file mode 100644 index 0000000..7d740a4 --- /dev/null +++ b/codebox/controllers/problem/submit.moon @@ -0,0 +1,42 @@ +import make_controller from require "controllers.controller" +import from_json, to_json from require 'lapis.util' +import assert_valid from require 'lapis.validate' +import capture_errors, capture_errors_json, yield_error from require 'lapis.application' +import Competitions, Problems from require 'models' + +make_controller + inject: + queries: 'queries' + executer: 'executer' + + middleware: { 'logged_in' } + scripts: { 'vendor/ace/ace', 'problem_submit' } + + get: capture_errors_json => + assert_valid @params, { + { "problem_name", exists: true } + } + + @navbar.selected = 1 + + @problem = Problems\find short_name: @params.problem_name + + render: 'problem.submit' + + post: capture_errors_json => + assert_valid @params, { + { "problem_name", exists: true } + { "lang", exists: true } + { "code", exists: true } + } + + problem = Problems\find short_name: @params.problem_name + unless problem + return json: { status: 'problem not found' } + + test_cases = problem\get_test_cases! + + id = @executer\request @params.lang, @params.code, @user.id, problem.id, test_cases, problem.time_limit + + json: id + diff --git a/codebox/controllers/submission/Tupfile b/codebox/controllers/submission/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/controllers/submission/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/controllers/submission/list.moon b/codebox/controllers/submission/list.moon new file mode 100644 index 0000000..7465943 --- /dev/null +++ b/codebox/controllers/submission/list.moon @@ -0,0 +1,16 @@ +import make_controller from require "controllers.controller" +import from_json, to_json from require 'lapis.util' +import assert_valid from require 'lapis.validate' +import capture_errors, yield_error from require 'lapis.application' +import Competitions, Jobs from require 'models' + +make_controller + inject: + queries: 'queries' + + middleware: { 'logged_in' } + + get: => + @navbar.selected = 2 + + render: 'submission.list' \ No newline at end of file diff --git a/codebox/controllers/submission/status.moon b/codebox/controllers/submission/status.moon new file mode 100644 index 0000000..5d7afd0 --- /dev/null +++ b/codebox/controllers/submission/status.moon @@ -0,0 +1,30 @@ +import make_controller from require "controllers.controller" +import from_json, to_json from require 'lapis.util' +import assert_valid from require 'lapis.validate' +import capture_errors, capture_errors_json, yield_error from require 'lapis.application' +import Competitions, Jobs from require 'models' +JobResult = require 'views.ssr.job_result' + +make_controller + layout: false + middleware: { 'logged_in' } + + get: capture_errors_json => + @navbar.selected = 2 + + assert_valid @params, { + { "submission_id", exists: true } + } + + @job = Jobs\find job_id: @params.submission_id + unless @job.user_id == @user.id + yield_error "You are not allowed to view this submission!" + + status_code = 201 + switch @job.status + when Jobs.statuses.queued then status_code = 200 + when Jobs.statuses.compiling then status_code = 200 + when Jobs.statuses.running then status_code = 200 + + status_widget = JobResult @job + return { layout: false, status: status_code, status_widget\render_to_string! } \ No newline at end of file diff --git a/codebox/controllers/submission/view.moon b/codebox/controllers/submission/view.moon new file mode 100644 index 0000000..f55f70a --- /dev/null +++ b/codebox/controllers/submission/view.moon @@ -0,0 +1,25 @@ +import make_controller from require "controllers.controller" +import from_json, to_json from require 'lapis.util' +import assert_valid from require 'lapis.validate' +import capture_errors, capture_errors_json, yield_error from require 'lapis.application' +import Competitions, Jobs from require 'models' + +make_controller + inject: + queries: 'queries' + + middleware: { 'logged_in' } + scripts: { 'vendor/ace/ace', 'submission_reloader' } + + get: capture_errors_json => + @navbar.selected = 2 + + assert_valid @params, { + { "submission_id", exists: true } + } + + @job = Jobs\find job_id: @params.submission_id + unless @job.user_id == @user.id + yield_error "You are not allowed to view this submission!" + + render: 'submission.view' \ No newline at end of file diff --git a/codebox/facades/executer.moon b/codebox/facades/executer.moon index 6b7ad6d..bae8f0c 100644 --- a/codebox/facades/executer.moon +++ b/codebox/facades/executer.moon @@ -6,7 +6,7 @@ import format_date from require 'lapis.db' import Jobs from require 'models' class ExecuterFacade - request: (lang, code, problem_id, test_cases, time_limit) => + request: (lang, code, user_id, problem_id, test_cases, time_limit) => body = http.simple "#{config.executer_addr}/request", { :lang :code @@ -20,7 +20,7 @@ class ExecuterFacade job = Jobs\create { job_id: job_id - user_id: 1 + user_id: user_id problem_id: problem_id status: Jobs.statuses\for_db 'queued' lang: lang diff --git a/codebox/static/coffee/pie_chart.coffee b/codebox/static/coffee/pie_chart.coffee index 3552895..369e176 100644 --- a/codebox/static/coffee/pie_chart.coffee +++ b/codebox/static/coffee/pie_chart.coffee @@ -13,7 +13,7 @@ $(document).ready -> for i in [1..segments] total += parseInt ($p.attr "data-segment-#{i}") - fill_perc = 0 + fill_perc = 0.01 anim = -> acc = 0 @@ -30,7 +30,7 @@ $(document).ready -> acc += ratio - fill_perc += 0.05 + fill_perc += fill_perc / 10 + 0.01 if fill_perc >= 1 fill_perc = 1 diff --git a/codebox/static/coffee/problem_submit.coffee b/codebox/static/coffee/problem_submit.coffee new file mode 100644 index 0000000..286bd4e --- /dev/null +++ b/codebox/static/coffee/problem_submit.coffee @@ -0,0 +1,22 @@ +$(document).ready -> + $("#language").change (ev) -> + $lang = $(ev.target).val() + + editor_lang = switch $lang + when 'c' then 'c_cpp' + when 'cpp' then 'c_cpp' + when 'py' then 'python' + when 'lua' then 'lua' + + editor = ace.edit 'code-editor' + editor.session.setMode "ace/mode/#{editor_lang}" + + $('#submit-btn').click -> + lang = $('#language').val() + code = (ace.edit 'code-editor').getValue() + + $.post window.location.pathname, { + lang: lang, + code: code + }, (data) -> + window.location.replace("/submissions/view?submission_id=#{data}"); diff --git a/codebox/static/coffee/submission_reloader.coffee b/codebox/static/coffee/submission_reloader.coffee new file mode 100644 index 0000000..4515b2d --- /dev/null +++ b/codebox/static/coffee/submission_reloader.coffee @@ -0,0 +1,11 @@ +submission_id = (new URLSearchParams window.location.search).get 'submission_id' + +updateStatus = -> + $.get '/submissions/status', { submission_id: submission_id }, (html, _, data) -> + $('#status-container').html html + + if data.status == 200 + setTimeout updateStatus, 100 + +$(document).ready -> + updateStatus() \ No newline at end of file diff --git a/codebox/static/js/pie_chart.js b/codebox/static/js/pie_chart.js index b969980..3529949 100644 --- a/codebox/static/js/pie_chart.js +++ b/codebox/static/js/pie_chart.js @@ -14,7 +14,7 @@ for (i = j = 1, ref = segments; (1 <= ref ? j <= ref : j >= ref); i = 1 <= ref ? ++j : --j) { total += parseInt($p.attr(`data-segment-${i}`)); } - fill_perc = 0; + fill_perc = 0.01; anim = function() { var acc, color, k, ratio, ref1; acc = 0; @@ -29,7 +29,7 @@ ctx.fill(); acc += ratio; } - fill_perc += 0.05; + fill_perc += fill_perc / 10 + 0.01; if (fill_perc >= 1) { fill_perc = 1; window.requestAnimationFrame(anim); diff --git a/codebox/static/js/pie_chart.js.map b/codebox/static/js/pie_chart.js.map index 2c18791..3b63c63 100644 --- a/codebox/static/js/pie_chart.js.map +++ b/codebox/static/js/pie_chart.js.map @@ -6,8 +6,8 @@ "coffee/pie_chart.coffee" ], "names": [], - "mappings": ";AAAA;EAAA,CAAA,CAAE,QAAF,CAAW,CAAC,KAAZ,CAAkB,QAAA,CAAA,CAAA;WACd,CAAA,CAAE,UAAF,CAAa,CAAC,IAAd,CAAmB,QAAA,CAAC,CAAD,EAAI,CAAJ,CAAA;AACf,UAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,GAAA,EAAA,SAAA,EAAA,CAAA,EAAA,CAAA,EAAA,GAAA,EAAA,QAAA,EAAA;MAAA,EAAA,GAAK,CAAA,CAAE,CAAF;MACL,QAAA,GAAW,EAAE,CAAC,IAAH,CAAQ,eAAR;MAEX,MAAA,GAAS,QAAQ,CAAC,aAAT,CAAuB,QAAvB;MACT,MAAM,CAAC,KAAP,GAAe;MACf,MAAM,CAAC,MAAP,GAAgB;MAChB,EAAE,CAAC,MAAH,CAAU,MAAV;MACA,GAAA,GAAM,MAAM,CAAC,UAAP,CAAkB,IAAlB;MAEN,KAAA,GAAQ;MACR,KAAS,qFAAT;QACI,KAAA,IAAS,QAAA,CAAU,EAAE,CAAC,IAAH,CAAQ,CAAA,aAAA,CAAA,CAAgB,CAAhB,CAAA,CAAR,CAAV;MADb;MAGA,SAAA,GAAY;MAEZ,IAAA,GAAO,QAAA,CAAA,CAAA;AACH,YAAA,GAAA,EAAA,KAAA,EAAA,CAAA,EAAA,KAAA,EAAA;QAAA,GAAA,GAAM;QACN,KAAS,0FAAT;UACI,KAAA,GAAQ,CAAC,QAAA,CAAU,EAAE,CAAC,IAAH,CAAQ,CAAA,aAAA,CAAA,CAAgB,CAAhB,CAAA,CAAR,CAAV,CAAD,CAAA,GAA2C;UACnD,KAAA,GAAQ,EAAE,CAAC,IAAH,CAAQ,CAAA,aAAA,CAAA,CAAgB,CAAhB,CAAkB,MAAlB,CAAR;UAER,GAAG,CAAC,SAAJ,CAAA;UACA,GAAG,CAAC,MAAJ,CAAW,GAAX,EAAgB,GAAhB;UACA,GAAG,CAAC,GAAJ,CAAQ,GAAR,EAAa,GAAb,EAAkB,GAAlB,EAAwB,CAAC,CAAD,GAAK,IAAI,CAAC,EAAV,GAAe,CAAC,KAAA,GAAQ,GAAT,CAAf,GAA+B,KAAvD,EAAgE,CAAC,CAAD,GAAK,IAAI,CAAC,EAAV,GAAe,GAAf,GAAqB,KAArF;UACA,GAAG,CAAC,SAAJ,CAAA;UACA,GAAG,CAAC,SAAJ,GAAgB;UAChB,GAAG,CAAC,IAAJ,CAAA;UAEA,GAAA,IAAO;QAXX;QAaA,SAAA,IAAa;QAEb,IAAG,SAAA,IAAa,CAAhB;UACI,SAAA,GAAY;UACZ,MAAM,CAAC,qBAAP,CAA6B,IAA7B,EAFJ;;QAIA,IAAG,SAAA,GAAY,CAAf;iBACI,MAAM,CAAC,qBAAP,CAA6B,IAA7B,EADJ;;MArBG;aAwBP,MAAM,CAAC,qBAAP,CAA6B,IAA7B;IAxCe,CAAnB;EADc,CAAlB;AAAA", + "mappings": ";AAAA;EAAA,CAAA,CAAE,QAAF,CAAW,CAAC,KAAZ,CAAkB,QAAA,CAAA,CAAA;WACd,CAAA,CAAE,UAAF,CAAa,CAAC,IAAd,CAAmB,QAAA,CAAC,CAAD,EAAI,CAAJ,CAAA;AACf,UAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,GAAA,EAAA,SAAA,EAAA,CAAA,EAAA,CAAA,EAAA,GAAA,EAAA,QAAA,EAAA;MAAA,EAAA,GAAK,CAAA,CAAE,CAAF;MACL,QAAA,GAAW,EAAE,CAAC,IAAH,CAAQ,eAAR;MAEX,MAAA,GAAS,QAAQ,CAAC,aAAT,CAAuB,QAAvB;MACT,MAAM,CAAC,KAAP,GAAe;MACf,MAAM,CAAC,MAAP,GAAgB;MAChB,EAAE,CAAC,MAAH,CAAU,MAAV;MACA,GAAA,GAAM,MAAM,CAAC,UAAP,CAAkB,IAAlB;MAEN,KAAA,GAAQ;MACR,KAAS,qFAAT;QACI,KAAA,IAAS,QAAA,CAAU,EAAE,CAAC,IAAH,CAAQ,CAAA,aAAA,CAAA,CAAgB,CAAhB,CAAA,CAAR,CAAV;MADb;MAGA,SAAA,GAAY;MAEZ,IAAA,GAAO,QAAA,CAAA,CAAA;AACH,YAAA,GAAA,EAAA,KAAA,EAAA,CAAA,EAAA,KAAA,EAAA;QAAA,GAAA,GAAM;QACN,KAAS,0FAAT;UACI,KAAA,GAAQ,CAAC,QAAA,CAAU,EAAE,CAAC,IAAH,CAAQ,CAAA,aAAA,CAAA,CAAgB,CAAhB,CAAA,CAAR,CAAV,CAAD,CAAA,GAA2C;UACnD,KAAA,GAAQ,EAAE,CAAC,IAAH,CAAQ,CAAA,aAAA,CAAA,CAAgB,CAAhB,CAAkB,MAAlB,CAAR;UAER,GAAG,CAAC,SAAJ,CAAA;UACA,GAAG,CAAC,MAAJ,CAAW,GAAX,EAAgB,GAAhB;UACA,GAAG,CAAC,GAAJ,CAAQ,GAAR,EAAa,GAAb,EAAkB,GAAlB,EAAwB,CAAC,CAAD,GAAK,IAAI,CAAC,EAAV,GAAe,CAAC,KAAA,GAAQ,GAAT,CAAf,GAA+B,KAAvD,EAAgE,CAAC,CAAD,GAAK,IAAI,CAAC,EAAV,GAAe,GAAf,GAAqB,KAArF;UACA,GAAG,CAAC,SAAJ,CAAA;UACA,GAAG,CAAC,SAAJ,GAAgB;UAChB,GAAG,CAAC,IAAJ,CAAA;UAEA,GAAA,IAAO;QAXX;QAaA,SAAA,IAAa,SAAA,GAAY,EAAZ,GAAiB;QAE9B,IAAG,SAAA,IAAa,CAAhB;UACI,SAAA,GAAY;UACZ,MAAM,CAAC,qBAAP,CAA6B,IAA7B,EAFJ;;QAIA,IAAG,SAAA,GAAY,CAAf;iBACI,MAAM,CAAC,qBAAP,CAA6B,IAA7B,EADJ;;MArBG;aAwBP,MAAM,CAAC,qBAAP,CAA6B,IAA7B;IAxCe,CAAnB;EADc,CAAlB;AAAA", "sourcesContent": [ - "$(document).ready ->\n $('piechart').each (_, p) ->\n $p = $ p\n segments = $p.attr 'data-segments'\n\n canvas = document.createElement \"canvas\"\n canvas.width = 256\n canvas.height = 256\n $p.append canvas\n ctx = canvas.getContext \"2d\"\n\n total = 0\n for i in [1..segments]\n total += parseInt ($p.attr \"data-segment-#{i}\")\n \n fill_perc = 0\n\n anim = ->\n acc = 0\n for i in [1..segments]\n ratio = (parseInt ($p.attr \"data-segment-#{i}\")) * fill_perc\n color = $p.attr \"data-segment-#{i}-color\"\n\n ctx.beginPath()\n ctx.moveTo 128, 128\n ctx.arc 128, 128, 128, (-2 * Math.PI * (ratio + acc) / total), (-2 * Math.PI * acc / total)\n ctx.closePath()\n ctx.fillStyle = color\n ctx.fill()\n\n acc += ratio\n\n fill_perc += 0.05\n\n if fill_perc >= 1\n fill_perc = 1\n window.requestAnimationFrame anim\n\n if fill_perc < 1\n window.requestAnimationFrame anim\n \n window.requestAnimationFrame anim\n\n" + "$(document).ready ->\n $('piechart').each (_, p) ->\n $p = $ p\n segments = $p.attr 'data-segments'\n\n canvas = document.createElement \"canvas\"\n canvas.width = 256\n canvas.height = 256\n $p.append canvas\n ctx = canvas.getContext \"2d\"\n\n total = 0\n for i in [1..segments]\n total += parseInt ($p.attr \"data-segment-#{i}\")\n \n fill_perc = 0.01\n\n anim = ->\n acc = 0\n for i in [1..segments]\n ratio = (parseInt ($p.attr \"data-segment-#{i}\")) * fill_perc\n color = $p.attr \"data-segment-#{i}-color\"\n\n ctx.beginPath()\n ctx.moveTo 128, 128\n ctx.arc 128, 128, 128, (-2 * Math.PI * (ratio + acc) / total), (-2 * Math.PI * acc / total)\n ctx.closePath()\n ctx.fillStyle = color\n ctx.fill()\n\n acc += ratio\n\n fill_perc += fill_perc / 10 + 0.01\n\n if fill_perc >= 1\n fill_perc = 1\n window.requestAnimationFrame anim\n\n if fill_perc < 1\n window.requestAnimationFrame anim\n \n window.requestAnimationFrame anim\n\n" ] } \ No newline at end of file diff --git a/codebox/static/js/problem_submit.js b/codebox/static/js/problem_submit.js new file mode 100644 index 0000000..0133c1d --- /dev/null +++ b/codebox/static/js/problem_submit.js @@ -0,0 +1,37 @@ +// Generated by CoffeeScript 2.4.1 +(function() { + $(document).ready(function() { + $("#language").change(function(ev) { + var $lang, editor, editor_lang; + $lang = $(ev.target).val(); + editor_lang = (function() { + switch ($lang) { + case 'c': + return 'c_cpp'; + case 'cpp': + return 'c_cpp'; + case 'py': + return 'python'; + case 'lua': + return 'lua'; + } + })(); + editor = ace.edit('code-editor'); + return editor.session.setMode(`ace/mode/${editor_lang}`); + }); + return $('#submit-btn').click(function() { + var code, lang; + lang = $('#language').val(); + code = (ace.edit('code-editor')).getValue(); + return $.post(window.location.pathname, { + lang: lang, + code: code + }, function(data) { + return window.location.replace(`/submissions/view?submission_id=${data}`); + }); + }); + }); + +}).call(this); + +//# sourceMappingURL=problem_submit.js.map diff --git a/codebox/static/js/problem_submit.js.map b/codebox/static/js/problem_submit.js.map new file mode 100644 index 0000000..775402d --- /dev/null +++ b/codebox/static/js/problem_submit.js.map @@ -0,0 +1,13 @@ +{ + "version": 3, + "file": "problem_submit.js", + "sourceRoot": "..", + "sources": [ + "coffee/problem_submit.coffee" + ], + "names": [], + "mappings": ";AAAA;EAAA,CAAA,CAAE,QAAF,CAAW,CAAC,KAAZ,CAAkB,QAAA,CAAA,CAAA;IACd,CAAA,CAAE,WAAF,CAAc,CAAC,MAAf,CAAsB,QAAA,CAAC,EAAD,CAAA;AAClB,UAAA,KAAA,EAAA,MAAA,EAAA;MAAA,KAAA,GAAQ,CAAA,CAAE,EAAE,CAAC,MAAL,CAAY,CAAC,GAAb,CAAA;MAER,WAAA;AAAc,gBAAO,KAAP;AAAA,eACL,GADK;mBACI;AADJ,eAEL,KAFK;mBAEM;AAFN,eAGL,IAHK;mBAGK;AAHL,eAIL,KAJK;mBAIM;AAJN;;MAMd,MAAA,GAAS,GAAG,CAAC,IAAJ,CAAS,aAAT;aACT,MAAM,CAAC,OAAO,CAAC,OAAf,CAAuB,CAAA,SAAA,CAAA,CAAY,WAAZ,CAAA,CAAvB;IAVkB,CAAtB;WAYA,CAAA,CAAE,aAAF,CAAgB,CAAC,KAAjB,CAAuB,QAAA,CAAA,CAAA;AACnB,UAAA,IAAA,EAAA;MAAA,IAAA,GAAO,CAAA,CAAE,WAAF,CAAc,CAAC,GAAf,CAAA;MACP,IAAA,GAAO,CAAC,GAAG,CAAC,IAAJ,CAAS,aAAT,CAAD,CAAwB,CAAC,QAAzB,CAAA;aAEP,CAAC,CAAC,IAAF,CAAO,MAAM,CAAC,QAAQ,CAAC,QAAvB,EAAiC;QAC7B,IAAA,EAAM,IADuB;QAE7B,IAAA,EAAM;MAFuB,CAAjC,EAGG,QAAA,CAAC,IAAD,CAAA;eACC,MAAM,CAAC,QAAQ,CAAC,OAAhB,CAAwB,CAAA,gCAAA,CAAA,CAAmC,IAAnC,CAAA,CAAxB;MADD,CAHH;IAJmB,CAAvB;EAbc,CAAlB;AAAA", + "sourcesContent": [ + "$(document).ready ->\n $(\"#language\").change (ev) ->\n $lang = $(ev.target).val()\n\n editor_lang = switch $lang\n when 'c' then 'c_cpp'\n when 'cpp' then 'c_cpp'\n when 'py' then 'python'\n when 'lua' then 'lua'\n \n editor = ace.edit 'code-editor'\n editor.session.setMode \"ace/mode/#{editor_lang}\"\n\n $('#submit-btn').click ->\n lang = $('#language').val()\n code = (ace.edit 'code-editor').getValue()\n\n $.post window.location.pathname, {\n lang: lang,\n code: code\n }, (data) ->\n window.location.replace(\"/submissions/view?submission_id=#{data}\");\n" + ] +} \ No newline at end of file diff --git a/codebox/static/js/submission_reloader.js b/codebox/static/js/submission_reloader.js new file mode 100644 index 0000000..add5a3d --- /dev/null +++ b/codebox/static/js/submission_reloader.js @@ -0,0 +1,24 @@ +// Generated by CoffeeScript 2.4.1 +(function() { + var submission_id, updateStatus; + + submission_id = (new URLSearchParams(window.location.search)).get('submission_id'); + + updateStatus = function() { + return $.get('/submissions/status', { + submission_id: submission_id + }, function(html, _, data) { + $('#status-container').html(html); + if (data.status === 200) { + return setTimeout(updateStatus, 100); + } + }); + }; + + $(document).ready(function() { + return updateStatus(); + }); + +}).call(this); + +//# sourceMappingURL=submission_reloader.js.map diff --git a/codebox/static/js/submission_reloader.js.map b/codebox/static/js/submission_reloader.js.map new file mode 100644 index 0000000..1157375 --- /dev/null +++ b/codebox/static/js/submission_reloader.js.map @@ -0,0 +1,13 @@ +{ + "version": 3, + "file": "submission_reloader.js", + "sourceRoot": "..", + "sources": [ + "coffee/submission_reloader.coffee" + ], + "names": [], + "mappings": ";AAAA;AAAA,MAAA,aAAA,EAAA;;EAAA,aAAA,GAAgB,CAAC,IAAI,eAAJ,CAAoB,MAAM,CAAC,QAAQ,CAAC,MAApC,CAAD,CAA4C,CAAC,GAA7C,CAAiD,eAAjD;;EAEhB,YAAA,GAAe,QAAA,CAAA,CAAA;WACX,CAAC,CAAC,GAAF,CAAM,qBAAN,EAA6B;MAAE,aAAA,EAAe;IAAjB,CAA7B,EAA+D,QAAA,CAAC,IAAD,EAAO,CAAP,EAAU,IAAV,CAAA;MAC3D,CAAA,CAAE,mBAAF,CAAsB,CAAC,IAAvB,CAA4B,IAA5B;MAEA,IAAG,IAAI,CAAC,MAAL,KAAe,GAAlB;eACI,UAAA,CAAW,YAAX,EAAyB,GAAzB,EADJ;;IAH2D,CAA/D;EADW;;EAOf,CAAA,CAAE,QAAF,CAAW,CAAC,KAAZ,CAAkB,QAAA,CAAA,CAAA;WACd,YAAA,CAAA;EADc,CAAlB;AATA", + "sourcesContent": [ + "submission_id = (new URLSearchParams window.location.search).get 'submission_id'\n\nupdateStatus = ->\n $.get '/submissions/status', { submission_id: submission_id }, (html, _, data) ->\n $('#status-container').html html\n\n if data.status == 200\n setTimeout updateStatus, 100\n\n$(document).ready ->\n updateStatus()" + ] +} \ No newline at end of file diff --git a/codebox/views/admin/submission/edit.moon b/codebox/views/admin/submission/edit.moon index 2915e98..5ac8b1b 100644 --- a/codebox/views/admin/submission/edit.moon +++ b/codebox/views/admin/submission/edit.moon @@ -9,7 +9,7 @@ class AdminSubmissionEdit extends html.Widget widget (require('views.ssr.job_result')(@job)) div class: 'header-line', -> - div -> text "#{@job.lang} code" + div -> text "#{@job.lang\upper!} code" pre { id: 'code-editor', 'data-lang': 'c_cpp', 'data-readonly': 'true' }, -> text @job.code diff --git a/codebox/views/partials/navbar.moon b/codebox/views/partials/navbar.moon index 6dd6da1..ae60626 100644 --- a/codebox/views/partials/navbar.moon +++ b/codebox/views/partials/navbar.moon @@ -9,4 +9,4 @@ class Navigation extends html.Widget ul -> a -> li class: { 'selected': @navbar.selected == 0 }, 'Leaderboard' a href: (@url_for 'problem'), -> li class: { 'selected': @navbar.selected == 1 }, 'Problems' - a -> li class: { 'selected': @navbar.selected == 2 }, 'Submissions' + a href: (@url_for 'submission.list'), -> li class: { 'selected': @navbar.selected == 2 }, 'Submissions' diff --git a/codebox/views/partials/problem_sidebar.moon b/codebox/views/partials/problem_sidebar.moon new file mode 100644 index 0000000..4711479 --- /dev/null +++ b/codebox/views/partials/problem_sidebar.moon @@ -0,0 +1,27 @@ +html = require 'lapis.html' +import Competitions from require 'models' + +class ProblemSidebar extends html.Widget + load_problems: => + @current_comp = Competitions\find active: true + @problems = @current_comp\get_problems! + + for prob in *@problems + if @queries.has_correct_submission @user.id, prob.short_name + prob.tag = "correct" + elseif @queries.has_incorrect_submission @user.id, prob.short_name + prob.tab = "incorrect" + + content: => + @load_problems! + + for prob in *@problems + a href: (@url_for 'problem.description', problem_name: prob.short_name), -> + div { + selected: prob.short_name == @params.problem_name + correct: prob.tag == "correct" + wrong: prob.tab == "incorrect" + class: 'sidebar-problem' + }, -> + div class: 'sidebar-problem-letter', -> text prob.letter + div class: 'sidebar-problem-name', -> text prob.name \ No newline at end of file diff --git a/codebox/views/problem/problem.moon b/codebox/views/problem/problem.moon index d4facbd..cbf1896 100644 --- a/codebox/views/problem/problem.moon +++ b/codebox/views/problem/problem.moon @@ -5,16 +5,7 @@ class Problems extends html.Widget content: => div class: 'sidebar-page-container', -> div class: 'sidebar-problem-list', -> - for prob in *@problems - a href: (@url_for 'problem.description', problem_name: prob.short_name), -> - div { - selected: prob.short_name == @params.problem_name - correct: prob.tag == "correct" - wrong: prob.tab == "incorrect" - class: 'sidebar-problem' - }, -> - div class: 'sidebar-problem-letter', -> text prob.letter - div class: 'sidebar-problem-name', -> text prob.name + widget (require 'views.partials.problem_sidebar') div class: 'content', -> unless @problem @@ -22,7 +13,8 @@ class Problems extends html.Widget else h1 @problem.name div class: 'problem-info', -> - a style: "width: 100%; text-align: center", class: 'button', -> text "Make a submission" + a style: "width: 100%; text-align: center", class: 'button', href: (@url_for 'problem.submit', { problem_name: @problem.short_name }), -> + text "Make a submission" div style: 'font-size: 1.3rem; margin-top: 0', class: 'header-line', -> text "Stats for #{@problem.name}" diff --git a/codebox/views/problem/submit.moon b/codebox/views/problem/submit.moon new file mode 100644 index 0000000..30360ca --- /dev/null +++ b/codebox/views/problem/submit.moon @@ -0,0 +1,25 @@ +html = require 'lapis.html' + +class ProblemSubmit extends html.Widget + content: => + div class: 'sidebar-page-container', -> + div class: 'sidebar-problem-list', -> + widget (require 'views.partials.problem_sidebar') + + div class: 'content', -> + h1 "Submit to '#{@problem.name}'" + + div class: 'header-line', -> text "Code Editor" + div class: 'box', -> + div class: 'split-lr', -> + div class: 'mar-l-12', -> + span -> text "Language: " + element 'select', id: 'language', -> + option value: 'c', -> text 'C' + option value: 'cpp', -> text 'C++' + option value: 'py', -> text 'Python' + option value: 'lua', -> text 'Lua' + div class: 'button-list', -> + button id: 'submit-btn', -> text "Submit" + + pre { style: 'height: 40rem', id: 'code-editor', 'data-lang': 'c_cpp' }, "" \ No newline at end of file diff --git a/codebox/views/ssr/job_result.moon b/codebox/views/ssr/job_result.moon index 4fa8a89..7dd9950 100644 --- a/codebox/views/ssr/job_result.moon +++ b/codebox/views/ssr/job_result.moon @@ -12,8 +12,11 @@ class JobResultView extends html.Widget @username = @job\get_user!.username @problem = @job\get_problem!.name - @json_data = from_json @job.data @time_started = @job.time_initiated + if @job.data + @json_data = from_json @job.data + else + @json_data = nil @ring_color = '' switch @job.status @@ -31,14 +34,14 @@ class JobResultView extends html.Widget when Jobs.statuses.bad_language then @show_slash = false when Jobs.statuses.bad_problem then @show_slash = false - if @show_slash + if @show_slash and type(@json_data) == "table" @completed_percentage = math.floor(100 * (@json_data.completed / @json_data.total)) content: => div class: 'fixed-half-split', -> div -> span class: "mar-t-12 mar-l-12 c100 p#{@completed_percentage} big dark #{@ring_color}", -> - if @show_slash + if @show_slash and type(@json_data) == "table" span -> text "#{@json_data.completed} / #{@json_data.total}" else span -> text "Error" @@ -70,6 +73,8 @@ class JobResultView extends html.Widget div 'Test cases' div class: 'box', -> + return unless type(@json_data) == "table" + for i = 1, @json_data.total tc_status = 'secondary' if i <= @json_data.completed @@ -94,10 +99,11 @@ class JobResultView extends html.Widget p "---------" if type(@json_data.run_times[i]) == 'number' - p "Run time: #{@json_data.run_times[i]}s" + p "Run time: #{@json_data.run_times[i] / 1000000}s" else div class: 'header-line', -> div 'Errors' div class: 'box', -> + return unless @job.data pre (process_str @job.data) diff --git a/codebox/views/submission/Tupfile b/codebox/views/submission/Tupfile new file mode 100644 index 0000000..f0fe651 --- /dev/null +++ b/codebox/views/submission/Tupfile @@ -0,0 +1 @@ +include_rules diff --git a/codebox/views/submission/list.moon b/codebox/views/submission/list.moon new file mode 100644 index 0000000..757fee6 --- /dev/null +++ b/codebox/views/submission/list.moon @@ -0,0 +1,5 @@ +html = require 'lapis.html' + +class SubmissionList extends html.Widget + content: => + h1 "Submission" \ No newline at end of file diff --git a/codebox/views/submission/view.moon b/codebox/views/submission/view.moon new file mode 100644 index 0000000..c4c5ef1 --- /dev/null +++ b/codebox/views/submission/view.moon @@ -0,0 +1,12 @@ +html = require 'lapis.html' + +class SubmissionView extends html.Widget + content: => + div class: 'content', -> + div id: 'status-container', -> + widget (require('views.ssr.job_result')(@job)) + + div class: 'header-line', -> + div -> text "#{@job.lang\upper!} code" + + pre { id: 'code-editor', 'data-lang': 'c_cpp', 'data-readonly': 'true' }, -> text @job.code \ No newline at end of file diff --git a/executer/app/executer.coffee b/executer/app/executer.coffee index 585ddda..6b01fc3 100644 --- a/executer/app/executer.coffee +++ b/executer/app/executer.coffee @@ -15,13 +15,13 @@ create_matchers = (otpt) -> class Executer compilers: { - 'C': new CCompiler(), - 'CPP': new CPPCompiler() + 'c': new CCompiler(), + 'cpp': new CPPCompiler() } executers: { - 'C': new CExecuter(), - 'CPP': new CExecuter() + 'c': new CExecuter(), + 'cpp': new CExecuter() } process: (lang, code, test_cases, time_limit) -> @@ -33,9 +33,9 @@ class Executer await return process_code: (lang, code, test_cases, time_limit) -> - compiler = @compilers[lang] + compiler = @compilers[lang.toLowerCase()] unless compiler? - yield { status: 8 } + yield { status: 7 } return yield { status: 2 } @@ -51,17 +51,23 @@ class Executer unless executer? exec_file.delete_file() - yield { status: 8 } + yield { status: 7 } return total_cases = test_cases.length run_times = new Array total_cases completed = 0 + # Wait a second so the submission page looks cooler + await new Promise (res) -> + setTimeout res, 500 + yield { status: 3, data: { completed: completed, total: total_cases, run_times: run_times } } for test_case in test_cases res = await executer.execute exec_file.file_path, test_case.input, time_limit + await new Promise (res) -> + setTimeout res, 200 switch (res.status) when 'SUCCESS' -- 2.25.1