Added submitting and viewing submissions
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 16 Sep 2019 13:35:07 +0000 (08:35 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 16 Sep 2019 13:35:07 +0000 (08:35 -0500)
29 files changed:
codebox/app/app.moon
codebox/controllers/controller.moon
codebox/controllers/executer/request.moon
codebox/controllers/problem/problem.moon
codebox/controllers/problem/submit.moon [new file with mode: 0644]
codebox/controllers/submission/Tupfile [new file with mode: 0644]
codebox/controllers/submission/list.moon [new file with mode: 0644]
codebox/controllers/submission/status.moon [new file with mode: 0644]
codebox/controllers/submission/view.moon [new file with mode: 0644]
codebox/facades/executer.moon
codebox/static/coffee/pie_chart.coffee
codebox/static/coffee/problem_submit.coffee [new file with mode: 0644]
codebox/static/coffee/submission_reloader.coffee [new file with mode: 0644]
codebox/static/js/pie_chart.js
codebox/static/js/pie_chart.js.map
codebox/static/js/problem_submit.js [new file with mode: 0644]
codebox/static/js/problem_submit.js.map [new file with mode: 0644]
codebox/static/js/submission_reloader.js [new file with mode: 0644]
codebox/static/js/submission_reloader.js.map [new file with mode: 0644]
codebox/views/admin/submission/edit.moon
codebox/views/partials/navbar.moon
codebox/views/partials/problem_sidebar.moon [new file with mode: 0644]
codebox/views/problem/problem.moon
codebox/views/problem/submit.moon [new file with mode: 0644]
codebox/views/ssr/job_result.moon
codebox/views/submission/Tupfile [new file with mode: 0644]
codebox/views/submission/list.moon [new file with mode: 0644]
codebox/views/submission/view.moon [new file with mode: 0644]
executer/app/executer.coffee

index b2138b2f7cbdaec434ab9843830775d4ee24d590..0bf96700c97732e7b31aacad814267d733ab563b 100644 (file)
@@ -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!
index b8786a2fbe2bebcfa39c946db68b438ad3cdd33a..16130d9c6168b27afb64d17a56dbb7d1420e08a4 100644 (file)
@@ -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
                }
 }
index ba86a2e92815d305855bc14cbf407d92a03ad24d..5c3f77ce4204d30c0832b153233dc1624371766f 100644 (file)
@@ -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
        ), =>
index 800385cd434f82681cb903537c37b1f77a82683c..2a6db9a97a79ff0f07ee4c7d75fe44b4a1f3fe2a 100644 (file)
@@ -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 (file)
index 0000000..7d740a4
--- /dev/null
@@ -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 (file)
index 0000000..f0fe651
--- /dev/null
@@ -0,0 +1 @@
+include_rules
diff --git a/codebox/controllers/submission/list.moon b/codebox/controllers/submission/list.moon
new file mode 100644 (file)
index 0000000..7465943
--- /dev/null
@@ -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 (file)
index 0000000..5d7afd0
--- /dev/null
@@ -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 (file)
index 0000000..f55f70a
--- /dev/null
@@ -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
index 6b7ad6d00666dcde0743a53c4b1cf1ad848c9d97..bae8f0c609f21899edd33087a48408ba92d6cd0e 100644 (file)
@@ -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
index 355289541afbdca10b3d50decd77c58973b6060f..369e1768ae7de561d6655f8efb0c598907f22fd2 100644 (file)
@@ -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 (file)
index 0000000..286bd4e
--- /dev/null
@@ -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 (file)
index 0000000..4515b2d
--- /dev/null
@@ -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
index b969980e3cd4c763d56e0b1f95c99ff610f5f738..3529949632196205f116673950226b4c5304b2d5 100644 (file)
@@ -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);
index 2c187917ff021034a2fd8354410c4f3e8b330d03..3b63c63c58a75db4241540b4fb2f4c49d1eee33a 100644 (file)
@@ -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 (file)
index 0000000..0133c1d
--- /dev/null
@@ -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 (file)
index 0000000..775402d
--- /dev/null
@@ -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 (file)
index 0000000..add5a3d
--- /dev/null
@@ -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 (file)
index 0000000..1157375
--- /dev/null
@@ -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
index 2915e98384cb247e02bae1aed89053e65dd25b34..5ac8b1b9dafffccb68f8d367b22a06db65c1961d 100644 (file)
@@ -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
 
index 6dd6da13377b785763cc27fd1f044778af38ea04..ae6062687333b04988bedc8b934ba9aba3c3b5c7 100644 (file)
@@ -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 (file)
index 0000000..4711479
--- /dev/null
@@ -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
index d4facbdecffcdacdc6cab29c2801bdea9b99148d..cbf18964f38e7b974d9935a1ab5bb1fcefc9adf9 100644 (file)
@@ -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 (file)
index 0000000..30360ca
--- /dev/null
@@ -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
index 4fa8a898b7766e4ce86a20ea5cbf08675ef61424..7dd9950f16015b77f24a04299386bf4a1196e83c 100644 (file)
@@ -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 (file)
index 0000000..f0fe651
--- /dev/null
@@ -0,0 +1 @@
+include_rules
diff --git a/codebox/views/submission/list.moon b/codebox/views/submission/list.moon
new file mode 100644 (file)
index 0000000..757fee6
--- /dev/null
@@ -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 (file)
index 0000000..c4c5ef1
--- /dev/null
@@ -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
index 585dddab85fc8ee267a312462c1c228a3fd89d73..6b01fc3d67e01034c0427810864ea04e2de84927 100644 (file)
@@ -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'