Description:
- start adding testcases into database - fix download button for score report
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r607:350b2d080045 - - 7 files changed: 77 inserted, 6 deleted

@@ -0,0 +1,4
1 + class Testcase < ActiveRecord::Base
2 + belongs_to :problem
3 + attr_accessible :group, :input, :num, :score, :sol
4 + end
@@ -0,0 +1,15
1 + class CreateTestcases < ActiveRecord::Migration
2 + def change
3 + create_table :testcases do |t|
4 + t.references :problem
5 + t.integer :num
6 + t.integer :group
7 + t.integer :score
8 + t.text :input
9 + t.text :sol
10 +
11 + t.timestamps
12 + end
13 + add_index :testcases, :problem_id
14 + end
15 + end
@@ -0,0 +1,5
1 + require 'spec_helper'
2 +
3 + describe Testcases do
4 + pending "add some examples to (or delete) #{__FILE__}"
5 + end
@@ -1,108 +1,110
1 + require 'csv'
2 +
1 3 class ReportController < ApplicationController
2 4
3 5 before_filter :authenticate
4 6
5 7 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score]
6 8
7 9 before_filter(only: [:problem_hof]) { |c|
8 10 return false unless authenticate
9 11
10 12 if GraderConfiguration["right.user_view_submission"]
11 13 return true;
12 14 end
13 15
14 16 admin_authorization
15 17 }
16 18
17 19 def max_score
18 20 end
19 21
20 22 def current_score
21 23 @problems = Problem.find_available_problems
22 24 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
23 25 @scorearray = calculate_max_score(@problems, @users,0,0,true)
24 26
25 27 #rencer accordingly
26 - if params[:commit] == 'download csv' then
28 + if params[:button] == 'download' then
27 29 csv = gen_csv_from_scorearray(@scorearray,@problems)
28 30 send_data csv, filename: 'max_score.csv'
29 31 else
30 32 #render template: 'user_admin/user_stat'
31 33 render 'current_score'
32 34 end
33 35 end
34 36
35 37 def show_max_score
36 38 #process parameters
37 39 #problems
38 40 @problems = []
39 41 params[:problem_id].each do |id|
40 42 next unless id.strip != ""
41 43 pid = Problem.find_by_id(id.to_i)
42 44 @problems << pid if pid
43 45 end
44 46
45 47 #users
46 48 @users = if params[:user] == "all" then
47 49 User.find(:all, :include => [:contests, :contest_stat])
48 50 else
49 51 User.includes(:contests).includes(:contest_stat).where(enabled: true)
50 52 end
51 53
52 54 #set up range from param
53 55 since_id = params.fetch(:min_id, 0).to_i
54 56 until_id = params.fetch(:max_id, 0).to_i
55 57
56 58 #calculate the routine
57 59 @scorearray = calculate_max_score(@problems, @users,since_id,until_id)
58 60
59 61 #rencer accordingly
60 - if params[:commit] == 'download csv' then
62 + if params[:button] == 'download' then
61 63 csv = gen_csv_from_scorearray(@scorearray,@problems)
62 64 send_data csv, filename: 'max_score.csv'
63 65 else
64 66 #render template: 'user_admin/user_stat'
65 67 render 'max_score'
66 68 end
67 69
68 70 end
69 71
70 72 def score
71 73 if params[:commit] == 'download csv'
72 74 @problems = Problem.all
73 75 else
74 76 @problems = Problem.find_available_problems
75 77 end
76 78 @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
77 79 @scorearray = Array.new
78 80 @users.each do |u|
79 81 ustat = Array.new
80 82 ustat[0] = u
81 83 @problems.each do |p|
82 84 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
83 85 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
84 86 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
85 87 else
86 88 ustat << [0,false]
87 89 end
88 90 end
89 91 @scorearray << ustat
90 92 end
91 93 if params[:commit] == 'download csv' then
92 94 csv = gen_csv_from_scorearray(@scorearray,@problems)
93 95 send_data csv, filename: 'last_score.csv'
94 96 else
95 97 render template: 'user_admin/user_stat'
96 98 end
97 99
98 100 end
99 101
100 102 def login_stat
101 103 @logins = Array.new
102 104
103 105 date_and_time = '%Y-%m-%d %H:%M'
104 106 begin
105 107 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
106 108 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
107 109 rescue
108 110 @since_time = DateTime.new(1000,1,1)
@@ -440,49 +442,80
440 442 FROM logins l INNER JOIN users u on l.user_id = u.id
441 443 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
442 444 UNION
443 445 SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
444 446 FROM submissions s INNER JOIN users u ON s.user_id = u.id
445 447 WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
446 448 ORDER BY submitted_at
447 449 SQL
448 450
449 451 p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
450 452 @logs = Submission.joins(:problem).find_by_sql(p)
451 453
452 454
453 455
454 456
455 457
456 458 end
457 459
458 460 protected
459 461
460 462 def calculate_max_score(problems, users,since_id,until_id, get_last_score = false)
461 463 scorearray = Array.new
462 464 users.each do |u|
463 465 ustat = Array.new
464 466 ustat[0] = u
465 467 problems.each do |p|
466 468 unless get_last_score
467 469 #get max score
468 470 max_points = 0
469 471 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
470 472 max_points = sub.points if sub and sub.points and (sub.points > max_points)
471 473 end
472 474 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
473 475 else
474 476 #get latest score
475 477 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
476 478 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
477 479 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
478 480 else
479 481 ustat << [0,false]
480 482 end
481 483 end
482 484 end
483 485 scorearray << ustat
484 486 end
485 487 return scorearray
486 488 end
487 489
490 + def gen_csv_from_scorearray(scorearray,problem)
491 + CSV.generate do |csv|
492 + #add header
493 + header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
494 + problem.each { |p| header << p.name }
495 + header += ['Total','Passed']
496 + csv << header
497 + #add data
498 + scorearray.each do |sc|
499 + total = num_passed = 0
500 + row = Array.new
501 + sc.each_index do |i|
502 + if i == 0
503 + row << sc[i].login
504 + row << sc[i].full_name
505 + row << sc[i].activated
506 + row << (sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no')
507 + row << sc[i].contests.collect {|c| c.name}.join(', ')
508 + else
509 + row << sc[i][0]
510 + total += sc[i][0]
511 + num_passed += 1 if sc[i][1]
488 512 end
513 + end
514 + row << total
515 + row << num_passed
516 + csv << row
517 + end
518 + end
519 + end
520 +
521 + end
@@ -1,53 +1,54
1 1 class Problem < ActiveRecord::Base
2 2
3 3 belongs_to :description
4 4 has_and_belongs_to_many :contests, :uniq => true
5 5 has_many :test_pairs, :dependent => :delete_all
6 + has_many :testcases, :dependent => :destroy
6 7
7 8 validates_presence_of :name
8 9 validates_format_of :name, :with => /^\w+$/
9 10 validates_presence_of :full_name
10 11
11 12 scope :available, :conditions => {:available => true}
12 13
13 14 DEFAULT_TIME_LIMIT = 1
14 15 DEFAULT_MEMORY_LIMIT = 32
15 16
16 17 def self.find_available_problems
17 18 Problem.available.all(:order => "date_added DESC, name ASC")
18 19 end
19 20
20 21 def self.create_from_import_form_params(params, old_problem=nil)
21 22 org_problem = old_problem || Problem.new
22 23 import_params, problem = Problem.extract_params_and_check(params,
23 24 org_problem)
24 25
25 26 if !problem.errors.empty?
26 27 return problem, 'Error importing'
27 28 end
28 29
29 30 problem.full_score = 100
30 31 problem.date_added = Time.new
31 32 problem.test_allowed = true
32 33 problem.output_only = false
33 34 problem.available = false
34 35
35 36 if not problem.save
36 37 return problem, 'Error importing'
37 38 end
38 39
39 40 import_to_db = params.has_key? :import_to_db
40 41
41 42 importer = TestdataImporter.new(problem)
42 43
43 44 if not importer.import_from_file(import_params[:file],
44 45 import_params[:time_limit],
45 46 import_params[:memory_limit],
46 47 import_params[:checker_name],
47 48 import_to_db)
48 49 problem.errors.add(:base,'Import error.')
49 50 end
50 51
51 52 return problem, importer.log_msg
52 53 end
53 54
@@ -1,49 +1,49
1 1 %h1 Maximum score
2 2
3 3 = form_tag report_show_max_score_path
4 4 .row
5 5 .col-md-4
6 6 .panel.panel-primary
7 7 .panel-heading
8 8 Problems
9 9 .panel-body
10 10 %p
11 11 Select problem(s) that we wish to know the score.
12 12 = label_tag :problem_id, "Problems"
13 13 = select_tag 'problem_id[]',
14 - options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]}),
14 + options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
15 15 { class: 'select2 form-control', multiple: "true" }
16 16 .col-md-4
17 17 .panel.panel-primary
18 18 .panel-heading
19 19 Submission range
20 20 .panel-body
21 21 %p
22 22 Input minimum and maximum range of submission ID that should be included. A blank value for min and max means -1 and infinity, respectively.
23 23 .form-group
24 24 = label_tag :from, "Min"
25 25 = text_field_tag 'from_id', nil, class: "form-control"
26 26 .form-group
27 27 = label_tag :from, "Max"
28 28 = text_field_tag 'to_id', nil, class: "form-control"
29 29 .col-md-4
30 30 .panel.panel-primary
31 31 .panel-heading
32 32 Users
33 33 .panel-body
34 34 .radio
35 35 %label
36 36 = radio_button_tag 'users', 'all', true
37 37 All users
38 38 .radio
39 39 %label
40 40 = radio_button_tag 'users', 'enabled'
41 41 Only enabled users
42 42 .row
43 43 .col-md-12
44 - = button_tag 'Show', class: "btn btn-primary btn-large"
45 - = button_tag 'Download CSV', class: "btn btn-primary btn-large"
44 + = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
45 + = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
46 46
47 47 - if @scorearray
48 48 %h2 Result
49 49 =render "score_table"
@@ -1,62 +1,62
1 1 # encoding: UTF-8
2 2 # This file is auto-generated from the current state of the database. Instead
3 3 # of editing this file, please use the migrations feature of Active Record to
4 4 # incrementally modify your database, and then regenerate this schema definition.
5 5 #
6 6 # Note that this schema.rb definition is the authoritative source for your
7 7 # database schema. If you need to create the application database on another
8 8 # system, you should be using db:schema:load, not running all the migrations
9 9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13
14 - ActiveRecord::Schema.define(:version => 20161008050135) do
14 + ActiveRecord::Schema.define(:version => 20161014091417) do
15 15
16 16 create_table "announcements", :force => true do |t|
17 17 t.string "author"
18 18 t.text "body"
19 19 t.boolean "published"
20 20 t.datetime "created_at", :null => false
21 21 t.datetime "updated_at", :null => false
22 22 t.boolean "frontpage", :default => false
23 23 t.boolean "contest_only", :default => false
24 24 t.string "title"
25 25 t.string "notes"
26 26 end
27 27
28 28 create_table "contests", :force => true do |t|
29 29 t.string "title"
30 30 t.boolean "enabled"
31 31 t.datetime "created_at", :null => false
32 32 t.datetime "updated_at", :null => false
33 33 t.string "name"
34 34 end
35 35
36 36 create_table "contests_problems", :id => false, :force => true do |t|
37 37 t.integer "contest_id"
38 38 t.integer "problem_id"
39 39 end
40 40
41 41 create_table "contests_users", :id => false, :force => true do |t|
42 42 t.integer "contest_id"
43 43 t.integer "user_id"
44 44 end
45 45
46 46 create_table "countries", :force => true do |t|
47 47 t.string "name"
48 48 t.datetime "created_at", :null => false
49 49 t.datetime "updated_at", :null => false
50 50 end
51 51
52 52 create_table "descriptions", :force => true do |t|
53 53 t.text "body"
54 54 t.boolean "markdowned"
55 55 t.datetime "created_at", :null => false
56 56 t.datetime "updated_at", :null => false
57 57 end
58 58
59 59 create_table "grader_configurations", :force => true do |t|
60 60 t.string "key"
61 61 t.string "value_type"
62 62 t.string "value"
@@ -191,77 +191,90
191 191 t.integer "number"
192 192 t.string "source_filename"
193 193 t.float "max_runtime"
194 194 t.integer "peak_memory"
195 195 t.integer "effective_code_length"
196 196 t.string "ip_address"
197 197 end
198 198
199 199 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
200 200 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
201 201
202 202 create_table "tasks", :force => true do |t|
203 203 t.integer "submission_id"
204 204 t.datetime "created_at"
205 205 t.integer "status"
206 206 t.datetime "updated_at"
207 207 end
208 208
209 209 create_table "test_pairs", :force => true do |t|
210 210 t.integer "problem_id"
211 211 t.text "input", :limit => 16777215
212 212 t.text "solution", :limit => 16777215
213 213 t.datetime "created_at", :null => false
214 214 t.datetime "updated_at", :null => false
215 215 end
216 216
217 217 create_table "test_requests", :force => true do |t|
218 218 t.integer "user_id"
219 219 t.integer "problem_id"
220 220 t.integer "submission_id"
221 221 t.string "input_file_name"
222 222 t.string "output_file_name"
223 223 t.string "running_stat"
224 224 t.integer "status"
225 225 t.datetime "updated_at", :null => false
226 226 t.datetime "submitted_at"
227 227 t.datetime "compiled_at"
228 228 t.text "compiler_message"
229 229 t.datetime "graded_at"
230 230 t.string "grader_comment"
231 231 t.datetime "created_at", :null => false
232 232 t.float "running_time"
233 233 t.string "exit_status"
234 234 t.integer "memory_usage"
235 235 end
236 236
237 237 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
238 238
239 + create_table "testcases", :force => true do |t|
240 + t.integer "problem_id"
241 + t.integer "num"
242 + t.integer "group"
243 + t.integer "score"
244 + t.text "input"
245 + t.text "sol"
246 + t.datetime "created_at", :null => false
247 + t.datetime "updated_at", :null => false
248 + end
249 +
250 + add_index "testcases", ["problem_id"], :name => "index_testcases_on_problem_id"
251 +
239 252 create_table "user_contest_stats", :force => true do |t|
240 253 t.integer "user_id"
241 254 t.datetime "started_at"
242 255 t.datetime "created_at", :null => false
243 256 t.datetime "updated_at", :null => false
244 257 t.boolean "forced_logout"
245 258 end
246 259
247 260 create_table "users", :force => true do |t|
248 261 t.string "login", :limit => 50
249 262 t.string "full_name"
250 263 t.string "hashed_password"
251 264 t.string "salt", :limit => 5
252 265 t.string "alias"
253 266 t.string "email"
254 267 t.integer "site_id"
255 268 t.integer "country_id"
256 269 t.boolean "activated", :default => false
257 270 t.datetime "created_at"
258 271 t.datetime "updated_at"
259 272 t.boolean "enabled", :default => true
260 273 t.string "remark"
261 274 t.string "last_ip"
262 275 t.string "section"
263 276 end
264 277
265 278 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
266 279
267 280 end
You need to be logged in to leave comments. Login now