lapis = require "lapis"
console = require "lapis.console"
-import Users, Competitions from require "models"
bind = require "utils.binding"
-
bind\bind_static 'executer', require 'facades.executer'
bind\bind_static 'crypto', require 'services.crypto'
bind\bind_static 'uuidv4', require 'services.uuid'
bind\bind_static 'queries', require 'services.queries'
+bind\bind_static 'scoring', require 'services.scoring'
+bind\bind_static 'time', require 'utils.time'
--- Helper function that sppeds up requests by
+-- Helper function that speeds up requests by
-- delaying the requiring of the controllers
controller = (cont) ->
return =>
['account.login': "/login"]: controller "account.login"
['account.logout': "/logout"]: controller "account.logout"
['account.register': "/register"]: controller "account.register"
- ['account.account': "/account"]: controller "account.account"
+ ['account.account': "/account"]: controller "account.account"
['problem': '/problems']: controller "problem.problem"
['problem.description': '/problems/:problem_name']: controller "problem.problem"
import make_controller from require "controllers.controller"
-import Users from require 'models'
import assert_valid from require "lapis.validate"
import capture_errors, yield_error from require 'lapis.application'
if @user.username ~=@params.username
yield_error 'You cannot change your username!'
-
+
@user\update
nickname: @params.nickname
email: @params.email
import assert_valid from require "lapis.validate"
import capture_errors, yield_error from require "lapis.application"
-utils = require "lapis.util"
-
make_controller
inject:
crypto: 'crypto'
import make_controller from require "controllers.controller"
-import Jobs from require 'models'
+import Jobs, Problems from require 'models'
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'
make_controller
+ inject:
+ scoring: 'scoring'
+
middleware: { 'internal_request' }
post: capture_errors (=>
status: status.status
data: to_json status.data
}
-
- print "Updated job: #{job.id}"
+
+ if status.status != Jobs.statuses.running
+ problem = Problems\find job.problem_id
+ @scoring\score_problem_for_user job.user_id, problem.short_name
+ @scoring\place!
+
json: { status: 'success' }
), =>
json: { status: 'error', errors: @errors }
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'
+import capture_errors_json, yield_error from require 'lapis.application'
+import Problems from require 'models'
make_controller
inject:
http = require 'lapis.nginx.http'
import from_json, to_json from require 'lapis.util'
-import format_date from require 'lapis.db'
import Jobs from require 'models'
class ExecuterFacade
job_id = from_json(body).id
- job = Jobs\create {
+ Jobs\create {
job_id: job_id
user_id: user_id
problem_id: problem_id
}
job_id
-
class LeaderboardProblems extends Model
@statuses: enum {
not_attempted: 1
- correct: 2
- wrong: 3
+ attempted: 2
+ correct: 3
+ wrong: 4
}
@relations: {
{ "leaderboard_placement", belongs_to: 'LeaderboardPlacements' }
{ "user", belongs_to: 'Users' }
{ "problem", belongs_to: 'Problems' }
- }
\ No newline at end of file
+ }
import Jobs from require 'models'
has_correct_submission = (user_id, problem_name) ->
- count = db.select "count(problems.id) from problems
- inner join jobs on problems.id = jobs.problem_id
+ count = db.select "count(jobs.id) from jobs
+ inner join problems on problems.id = jobs.problem_id
inner join competitions on jobs.competition_id=competitions.id
where competitions.active=TRUE and jobs.status=? and jobs.user_id=? and problems.short_name=?
", (Jobs.statuses\for_db 'correct'), user_id, problem_name
-
+
return count[1].count > 0
count_incorrect_submission = (user_id, problem_name) ->
- count = db.select "count(problems.id) from problems
- inner join jobs on problems.id = jobs.problem_id
+ count = db.select "count(jobs.id) from jobs
+ inner join problems on problems.id = jobs.problem_id
inner join competitions on jobs.competition_id=competitions.id
where competitions.active=TRUE and jobs.status in ? and jobs.user_id=? and problems.short_name=?
",
Jobs.statuses\for_db 'error'
Jobs.statuses\for_db 'compile_err'
}), user_id, problem_name
-
+
return count[1].count
has_incorrect_submission = (user_id, problem_name) ->
get_jobs_by_user_and_problem_and_competition = (user_id, problem_id, competition_id) ->
db.select "* from jobs where user_id=? and problem_id=? and competition_id=? order by time_initiated desc", user_id, problem_id, competition_id
+get_first_correct_submission = (user_id, problem_id, competition_id) ->
+ jobs = db.select "* from jobs where user_id=? and problem_id=? and competition_id=? order by time_initiated asc limit 1", user_id, problem_id, competition_id
+ jobs[1]
+
+delete_leaderboard_for_competition = (competition_id) ->
+ db.query "delete from leaderboard_problems
+ where leaderboard_placement_id in
+ (select id from leaderboard_placements where competition_id=?)", competition_id
+
+ db.delete "leaderboard_placements", competition_id: competition_id
+
+get_user_score = (user_id, competition_id) ->
+ res = db.select "sum(points)
+ from leaderboard_problems
+ inner join leaderboard_placements on leaderboard_placements.id=leaderboard_problems.leaderboard_placement_id
+ where leaderboard_placements.user_id=? and competition_id=?", user_id, competition_id
+
+ return 0 if #res == 0
+ res[1].sum
+
+
-> {
- :has_correct_submission,
- :count_incorrect_submission,
+ :has_correct_submission
+ :count_incorrect_submission
:has_incorrect_submission
:get_jobs_by_user_and_problem_and_competition
-}
\ No newline at end of file
+ :get_first_correct_submission
+ :delete_leaderboard_for_competition
+ :get_user_score
+}
--- /dev/null
+import Injectable from require 'utils.inject'
+import Users, Problems, Competitions, LeaderboardProblems, LeaderboardPlacements from require 'models'
+
+class Scoring extends Injectable
+ new: =>
+ @queries = @make 'queries'
+ @time = @make 'time'
+ @competition = Competitions\find active: true
+
+ @competition_start = @time.time_to_number @competition.start
+ @competition_end = @time.time_to_number @competition.end
+
+ setup_scoring_tables: =>
+ @queries.delete_leaderboard_for_competition @competition.id
+
+ users = Users\select!
+ problems = @competition\get_competition_problems!
+
+ for user in *users
+ placement = LeaderboardPlacements\create
+ competition_id: @competition.id
+ user_id: user.id
+
+ for problem in *problems
+ LeaderboardProblems\create
+ leaderboard_placement_id: placement.id
+ user_id: user.id
+ problem_id: problem.problem_id
+
+ get_problem_worth: (time_submitted) =>
+ start = @competition_start + 30 * 60
+ return 1 if time_submitted < start
+ duration = @competition_end - start
+ percent = (time_submitted - start) / duration
+ 1 - 0.5 * percent
+
+ score_problem_for_user: (user_id, problem_shortname) =>
+ placement = LeaderboardPlacements\find user_id: user_id, competition_id: @competition.id
+ status = LeaderboardProblems.statuses.not_attempted
+ points = 0
+ attempts = 0
+
+ problem = Problems\find short_name: problem_shortname
+
+ -- THIS SHOULD SWITCH ON PROBLEM KIND
+
+ attempts += @queries.count_incorrect_submission user_id, problem_shortname
+ if attempts > 0
+ status = LeaderboardProblems.statuses.wrong
+
+ if @queries.has_correct_submission user_id, problem_shortname
+ job = @queries.get_first_correct_submission user_id, problem.id, @competition.id
+
+ points += math.ceil (1000 * @get_problem_worth job.time_initiated)
+ points -= 50 * attempts
+ status = LeaderboardProblems.statuses.correct
+ attempts += 1
+
+ lp = LeaderboardProblems\find problem_id: problem.id, leaderboard_placement_id: placement.id
+ lp\update
+ status: status
+ points: points
+ attempts: attempts
+
+ score_user: (user_id) =>
+ problems = @competition\get_competition_problems!
+ for p in *problems
+ problem = p\get_problem!
+ @score_problem_for_user user_id, problem.short_name
+
+ score_problem: (problem_name) =>
+ users = Users\select!
+ for u in *users
+ @score_problem_for_user u.id, problem_name
+
+ score_all: =>
+ problems = @competition\get_competition_problems!
+ for p in *problems
+ problem = p\get_problem!
+ @score_problem problem.short_name
+
+ place: =>
+ users = Users\select!
+
+ for u in *users
+ u.score = @queries.get_user_score u.id, @competition.id
+
+ table.sort users, (a, b) ->
+ a.score - b.score
+
+ last_score = 1e308
+ num, act_num = 0, 0
+ for u in *users
+ act_num += 1
+ if last_score > u.score
+ num = act_num
+ last_score = u.score
+ lp = LeaderboardPlacements\find user_id: u.id, competition_id: @competition.id
+ lp\update
+ place: num
+ score: u.score
--- /dev/null
+bind = require 'utils.binding'
+
+class Injectable
+ make: (thing) =>
+ bind\make thing
+
+{ :Injectable }
else
a href: (@url_for 'account.login'), "Log in"
div class: 'navbar-username-dropdown', ->
- div class: 'navbar-username-dropdown-option', ->
+ div class: 'navbar-username-dropdown-option', ->
a href: (@url_for 'account.register'), "Register"
switch (res.status)
when 'SUCCESS'
- console.log test_case.output, res.output
output = clean_output res.output
expected = create_matchers (clean_output test_case.output)
worked = true
i = 0
for matcher in expected
- console.log matcher.line, output[i]
unless matcher.test output[i]
worked = false
break