Description:
merge with java
Commit status:
[Not Reviewed]
References:
merge algo
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r416:3378c5a77746 - - 24 files changed: 294 inserted, 86 deleted

@@ -0,0 +1,6
1 + //= require jquery
2 + //= require jquery_ujs
3 + //= require jquery.ui.all
4 + //= require jquery.ui.datepicker
5 + //= require jquery.ui.slider
6 + //= require jquery-ui-timepicker-addon
@@ -0,0 +1,3
1 + # Place all the behaviors and hooks related to the matching controller here.
2 + # All this logic will automatically be available in application.js.
3 + # You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/
@@ -0,0 +1,3
1 + // Place all the styles related to the report controller here.
2 + // They will automatically be included in application.css.
3 + // You can use Sass (SCSS) here: http://sass-lang.com/
@@ -0,0 +1,2
1 + module ReportHelper
2 + end
@@ -0,0 +1,3
1 + class Login < ActiveRecord::Base
2 + attr_accessible :ip_address, :logged_in_at, :user_id
3 + end
@@ -0,0 +1,23
1 +
2 + = form_tag({session: :url }) do
3 + .submitbox
4 + %table
5 + %tr
6 + %td{colspan: 6, style: 'font-weight: bold'}= title
7 + %tr
8 + %td{style: 'width: 120px; font-weight: bold'}= param_text
9 + %td{align: 'right'} since:
10 + %td= text_field_tag 'since_datetime'
11 + %tr
12 + %td
13 + %td{align: 'right'} until:
14 + %td= text_field_tag 'until_datetime'
15 + %tr
16 + %td
17 + %td
18 + %td Blank mean no condition
19 + %tr
20 + %td
21 + %td
22 + %td= submit_tag 'query'
23 +
@@ -0,0 +1,33
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 +
4 + %script{:type=>"text/javascript"}
5 + $(function () {
6 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + });
9 +
10 +
11 + %h1 Login status
12 +
13 +
14 + =render partial: 'report_menu'
15 + =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
16 +
17 + %table.info
18 + %thead
19 + %tr.info-head
20 + %th login
21 + %th full name
22 + %th login count
23 + %th earliest
24 + %th latest
25 + %tbody
26 + - @logins.each do |l|
27 + %tr{class: cycle('info-even','info-odd')}
28 + %td= l[:login]
29 + %td= l[:full_name]
30 + %td= l[:count]
31 + %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
32 + %td= l[:max] ? l[:max].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
33 +
@@ -0,0 +1,41
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 +
4 + %script{:type=>"text/javascript"}
5 + $(function () {
6 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + });
9 +
10 +
11 + %h1 Login status
12 +
13 +
14 +
15 +
16 + =render partial: 'report_menu'
17 + =render partial: 'date_range', locals: {param_text: 'Submission date range:', title: 'Query submission stat in the range' }
18 +
19 + %table.info
20 + %thead
21 + %tr.info-head
22 + %th login
23 + %th full name
24 + %th total submissions
25 + %th submissions
26 + %tbody
27 + - @submissions.each do |user_id,data|
28 + %tr{class: cycle('info-even','info-odd')}
29 + %td= data[:login]
30 + %td= data[:full_name]
31 + %td= data[:count]
32 + %td
33 + - data[:sub].each do |prob_id,sub_data|
34 + = "#{sub_data[:prob_name]}: ["
35 + - st = []
36 + - sub_data[:sub_ids].each do |id|
37 + - st << link_to(id, controller: 'graders' , action: 'submission', id: id)
38 + = raw st.join ', '
39 + = ']'
40 + %br/
41 +
@@ -0,0 +1,10
1 + class CreateLogins < ActiveRecord::Migration
2 + def change
3 + create_table :logins do |t|
4 + t.string :user_id
5 + t.string :ip_address
6 +
7 + t.timestamps
8 + end
9 + end
10 + end
@@ -0,0 +1,5
1 + require 'spec_helper'
2 +
3 + describe Login do
4 + pending "add some examples to (or delete) #{__FILE__}"
5 + end
@@ -1,50 +1,56
1 source 'https://rubygems.org'
1 source 'https://rubygems.org'
2
2
3 - gem 'rails', '3.2.8'
3 + gem 'rails', '3.2.19'
4
4
5 # Bundle edge Rails instead:
5 # Bundle edge Rails instead:
6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
7
8 gem 'mysql2'
8 gem 'mysql2'
9
9
10 # Gems used only for assets and not required
10 # Gems used only for assets and not required
11 # in production environments by default.
11 # in production environments by default.
12 group :assets do
12 group :assets do
13 gem 'sass-rails', '~> 3.2.3'
13 gem 'sass-rails', '~> 3.2.3'
14 gem 'coffee-rails', '~> 3.2.1'
14 gem 'coffee-rails', '~> 3.2.1'
15
15
16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
17 # gem 'therubyracer', :platforms => :ruby
17 # gem 'therubyracer', :platforms => :ruby
18
18
19 gem 'uglifier', '>= 1.0.3'
19 gem 'uglifier', '>= 1.0.3'
20 end
20 end
21
21
22 gem 'prototype-rails'
22 gem 'prototype-rails'
23
23
24 # To use ActiveModel has_secure_password
24 # To use ActiveModel has_secure_password
25 # gem 'bcrypt-ruby', '~> 3.0.0'
25 # gem 'bcrypt-ruby', '~> 3.0.0'
26
26
27 # To use Jbuilder templates for JSON
27 # To use Jbuilder templates for JSON
28 # gem 'jbuilder'
28 # gem 'jbuilder'
29
29
30 # Use unicorn as the app server
30 # Use unicorn as the app server
31 # gem 'unicorn'
31 # gem 'unicorn'
32
32
33 # Deploy with Capistrano
33 # Deploy with Capistrano
34 # gem 'capistrano'
34 # gem 'capistrano'
35
35
36 # To use debugger
36 # To use debugger
37 # gem 'debugger'
37 # gem 'debugger'
38 + #
39 +
40 + gem 'jquery-rails'
41 + gem 'jquery-ui-sass-rails'
42 + gem 'jquery-timepicker-addon-rails'
43 +
38
44
39 gem "haml"
45 gem "haml"
40 gem "mail"
46 gem "mail"
41 gem "rdiscount"
47 gem "rdiscount"
42 gem "test-unit"
48 gem "test-unit"
43 gem 'will_paginate', '~> 3.0.0'
49 gem 'will_paginate', '~> 3.0.0'
44 gem 'dynamic_form'
50 gem 'dynamic_form'
45 gem 'in_place_editing'
51 gem 'in_place_editing'
46 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
52 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
47
53
48 group :test, :development do
54 group :test, :development do
49 gem "rspec-rails", "~> 2.0"
55 gem "rspec-rails", "~> 2.0"
50 end
56 end
@@ -1,147 +1,166
1 GIT
1 GIT
2 remote: git://github.com/sikachu/verification.git
2 remote: git://github.com/sikachu/verification.git
3 - revision: 344ad2535da3dc9671872628ff9c79d6f59af9da
3 + revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
4 specs:
4 specs:
5 verification (1.0.3)
5 verification (1.0.3)
6 - actionpack (>= 3.0.0, < 3.3.0)
6 + actionpack (>= 3.0.0, < 5.0)
7 - activesupport (>= 3.0.0, < 3.3.0)
7 + activesupport (>= 3.0.0, < 5.0)
8
8
9 GEM
9 GEM
10 remote: https://rubygems.org/
10 remote: https://rubygems.org/
11 specs:
11 specs:
12 - actionmailer (3.2.8)
12 + actionmailer (3.2.19)
13 - actionpack (= 3.2.8)
13 + actionpack (= 3.2.19)
14 - mail (~> 2.4.4)
14 + mail (~> 2.5.4)
15 - actionpack (3.2.8)
15 + actionpack (3.2.19)
16 - activemodel (= 3.2.8)
16 + activemodel (= 3.2.19)
17 - activesupport (= 3.2.8)
17 + activesupport (= 3.2.19)
18 builder (~> 3.0.0)
18 builder (~> 3.0.0)
19 erubis (~> 2.7.0)
19 erubis (~> 2.7.0)
20 journey (~> 1.0.4)
20 journey (~> 1.0.4)
21 - rack (~> 1.4.0)
21 + rack (~> 1.4.5)
22 rack-cache (~> 1.2)
22 rack-cache (~> 1.2)
23 rack-test (~> 0.6.1)
23 rack-test (~> 0.6.1)
24 - sprockets (~> 2.1.3)
24 + sprockets (~> 2.2.1)
25 - activemodel (3.2.8)
25 + activemodel (3.2.19)
26 - activesupport (= 3.2.8)
26 + activesupport (= 3.2.19)
27 builder (~> 3.0.0)
27 builder (~> 3.0.0)
28 - activerecord (3.2.8)
28 + activerecord (3.2.19)
29 - activemodel (= 3.2.8)
29 + activemodel (= 3.2.19)
30 - activesupport (= 3.2.8)
30 + activesupport (= 3.2.19)
31 arel (~> 3.0.2)
31 arel (~> 3.0.2)
32 tzinfo (~> 0.3.29)
32 tzinfo (~> 0.3.29)
33 - activeresource (3.2.8)
33 + activeresource (3.2.19)
34 - activemodel (= 3.2.8)
34 + activemodel (= 3.2.19)
35 - activesupport (= 3.2.8)
35 + activesupport (= 3.2.19)
36 - activesupport (3.2.8)
36 + activesupport (3.2.19)
37 - i18n (~> 0.6)
37 + i18n (~> 0.6, >= 0.6.4)
38 multi_json (~> 1.0)
38 multi_json (~> 1.0)
39 - arel (3.0.2)
39 + arel (3.0.3)
40 - builder (3.0.3)
40 + builder (3.0.4)
41 coffee-rails (3.2.2)
41 coffee-rails (3.2.2)
42 coffee-script (>= 2.2.0)
42 coffee-script (>= 2.2.0)
43 railties (~> 3.2.0)
43 railties (~> 3.2.0)
44 - coffee-script (2.2.0)
44 + coffee-script (2.3.0)
45 coffee-script-source
45 coffee-script-source
46 execjs
46 execjs
47 - coffee-script-source (1.3.3)
47 + coffee-script-source (1.7.1)
48 - diff-lcs (1.1.3)
48 + diff-lcs (1.2.5)
49 dynamic_form (1.1.4)
49 dynamic_form (1.1.4)
50 erubis (2.7.0)
50 erubis (2.7.0)
51 - execjs (1.4.0)
51 + execjs (2.2.1)
52 - multi_json (~> 1.0)
52 + haml (4.0.5)
53 - haml (3.1.7)
53 + tilt
54 - hike (1.2.1)
54 + hike (1.2.3)
55 - i18n (0.6.1)
55 + i18n (0.6.11)
56 in_place_editing (1.2.0)
56 in_place_editing (1.2.0)
57 journey (1.0.4)
57 journey (1.0.4)
58 - json (1.7.5)
58 + jquery-rails (3.1.1)
59 - mail (2.4.4)
59 + railties (>= 3.0, < 5.0)
60 - i18n (>= 0.4.0)
60 + thor (>= 0.14, < 2.0)
61 + jquery-timepicker-addon-rails (1.4.1)
62 + railties (>= 3.1)
63 + jquery-ui-rails (4.0.3)
64 + jquery-rails
65 + railties (>= 3.1.0)
66 + jquery-ui-sass-rails (4.0.3.0)
67 + jquery-rails
68 + jquery-ui-rails (= 4.0.3)
69 + railties (>= 3.1.0)
70 + json (1.8.1)
71 + mail (2.5.4)
61 mime-types (~> 1.16)
72 mime-types (~> 1.16)
62 treetop (~> 1.4.8)
73 treetop (~> 1.4.8)
63 - mime-types (1.19)
74 + mime-types (1.25.1)
64 - multi_json (1.3.6)
75 + multi_json (1.10.1)
65 - mysql2 (0.3.11)
76 + mysql2 (0.3.16)
66 - polyglot (0.3.3)
77 + polyglot (0.3.5)
78 + power_assert (0.1.3)
67 prototype-rails (3.2.1)
79 prototype-rails (3.2.1)
68 rails (~> 3.2)
80 rails (~> 3.2)
69 - rack (1.4.1)
81 + rack (1.4.5)
70 rack-cache (1.2)
82 rack-cache (1.2)
71 rack (>= 0.4)
83 rack (>= 0.4)
72 - rack-ssl (1.3.2)
84 + rack-ssl (1.3.4)
73 rack
85 rack
74 rack-test (0.6.2)
86 rack-test (0.6.2)
75 rack (>= 1.0)
87 rack (>= 1.0)
76 - rails (3.2.8)
88 + rails (3.2.19)
77 - actionmailer (= 3.2.8)
89 + actionmailer (= 3.2.19)
78 - actionpack (= 3.2.8)
90 + actionpack (= 3.2.19)
79 - activerecord (= 3.2.8)
91 + activerecord (= 3.2.19)
80 - activeresource (= 3.2.8)
92 + activeresource (= 3.2.19)
81 - activesupport (= 3.2.8)
93 + activesupport (= 3.2.19)
82 bundler (~> 1.0)
94 bundler (~> 1.0)
83 - railties (= 3.2.8)
95 + railties (= 3.2.19)
84 - railties (3.2.8)
96 + railties (3.2.19)
85 - actionpack (= 3.2.8)
97 + actionpack (= 3.2.19)
86 - activesupport (= 3.2.8)
98 + activesupport (= 3.2.19)
87 rack-ssl (~> 1.3.2)
99 rack-ssl (~> 1.3.2)
88 rake (>= 0.8.7)
100 rake (>= 0.8.7)
89 rdoc (~> 3.4)
101 rdoc (~> 3.4)
90 thor (>= 0.14.6, < 2.0)
102 thor (>= 0.14.6, < 2.0)
91 - rake (0.9.2.2)
103 + rake (10.3.2)
92 - rdiscount (1.6.8)
104 + rdiscount (2.1.7.1)
93 - rdoc (3.12)
105 + rdoc (3.12.2)
94 json (~> 1.4)
106 json (~> 1.4)
95 - rspec (2.11.0)
107 + rspec-collection_matchers (1.0.0)
96 - rspec-core (~> 2.11.0)
108 + rspec-expectations (>= 2.99.0.beta1)
97 - rspec-expectations (~> 2.11.0)
109 + rspec-core (2.99.2)
98 - rspec-mocks (~> 2.11.0)
110 + rspec-expectations (2.99.2)
99 - rspec-core (2.11.1)
111 + diff-lcs (>= 1.1.3, < 2.0)
100 - rspec-expectations (2.11.3)
112 + rspec-mocks (2.99.2)
101 - diff-lcs (~> 1.1.3)
113 + rspec-rails (2.99.0)
102 - rspec-mocks (2.11.3)
103 - rspec-rails (2.11.0)
104 actionpack (>= 3.0)
114 actionpack (>= 3.0)
115 + activemodel (>= 3.0)
105 activesupport (>= 3.0)
116 activesupport (>= 3.0)
106 railties (>= 3.0)
117 railties (>= 3.0)
107 - rspec (~> 2.11.0)
118 + rspec-collection_matchers
108 - sass (3.2.1)
119 + rspec-core (~> 2.99.0)
109 - sass-rails (3.2.5)
120 + rspec-expectations (~> 2.99.0)
121 + rspec-mocks (~> 2.99.0)
122 + sass (3.4.1)
123 + sass-rails (3.2.6)
110 railties (~> 3.2.0)
124 railties (~> 3.2.0)
111 sass (>= 3.1.10)
125 sass (>= 3.1.10)
112 tilt (~> 1.3)
126 tilt (~> 1.3)
113 - sprockets (2.1.3)
127 + sprockets (2.2.2)
114 hike (~> 1.2)
128 hike (~> 1.2)
129 + multi_json (~> 1.0)
115 rack (~> 1.0)
130 rack (~> 1.0)
116 tilt (~> 1.1, != 1.3.0)
131 tilt (~> 1.1, != 1.3.0)
117 - test-unit (2.5.2)
132 + test-unit (3.0.1)
118 - thor (0.16.0)
133 + power_assert
119 - tilt (1.3.3)
134 + thor (0.19.1)
120 - treetop (1.4.10)
135 + tilt (1.4.1)
136 + treetop (1.4.15)
121 polyglot
137 polyglot
122 polyglot (>= 0.3.1)
138 polyglot (>= 0.3.1)
123 - tzinfo (0.3.33)
139 + tzinfo (0.3.41)
124 - uglifier (1.3.0)
140 + uglifier (2.5.3)
125 execjs (>= 0.3.0)
141 execjs (>= 0.3.0)
126 - multi_json (~> 1.0, >= 1.0.2)
142 + json (>= 1.8.0)
127 - will_paginate (3.0.3)
143 + will_paginate (3.0.7)
128
144
129 PLATFORMS
145 PLATFORMS
130 ruby
146 ruby
131
147
132 DEPENDENCIES
148 DEPENDENCIES
133 coffee-rails (~> 3.2.1)
149 coffee-rails (~> 3.2.1)
134 dynamic_form
150 dynamic_form
135 haml
151 haml
136 in_place_editing
152 in_place_editing
153 + jquery-rails
154 + jquery-timepicker-addon-rails
155 + jquery-ui-sass-rails
137 mail
156 mail
138 mysql2
157 mysql2
139 prototype-rails
158 prototype-rails
140 - rails (= 3.2.8)
159 + rails (= 3.2.19)
141 rdiscount
160 rdiscount
142 rspec-rails (~> 2.0)
161 rspec-rails (~> 2.0)
143 sass-rails (~> 3.2.3)
162 sass-rails (~> 3.2.3)
144 test-unit
163 test-unit
145 uglifier (>= 1.0.3)
164 uglifier (>= 1.0.3)
146 verification!
165 verification!
147 will_paginate (~> 3.0.0)
166 will_paginate (~> 3.0.0)
@@ -1,24 +1,32
1 +
2 + @import jquery.ui.core
3 + @import jquery.ui.theme
4 + @import jquery.ui.datepicker
5 + @import jquery.ui.slider
6 + @import jquery-ui-timepicker-addon
7 +
8 +
1 body
9 body
2 background: white image-url("topbg.jpg") repeat-x top center
10 background: white image-url("topbg.jpg") repeat-x top center
3 font-size: 13px
11 font-size: 13px
4 font-family: Tahoma, "sans-serif"
12 font-family: Tahoma, "sans-serif"
5 margin: 10px
13 margin: 10px
6 padding: 10px
14 padding: 10px
7
15
8
16
9 input
17 input
10 font-family: Tahoma, "sans-serif"
18 font-family: Tahoma, "sans-serif"
11
19
12
20
13 h1
21 h1
14 font-size: 24px
22 font-size: 24px
15 color: #334488
23 color: #334488
16 line-height: 2em
24 line-height: 2em
17
25
18
26
19 h2
27 h2
20 font-size: 18px
28 font-size: 18px
21 color: #5566bb
29 color: #5566bb
22 line-height: 1.5em
30 line-height: 1.5em
23
31
24
32
@@ -269,25 +277,25
269
277
270 &.message div.stat
278 &.message div.stat
271 font-size: 10px
279 font-size: 10px
272 line-height: 1.75em
280 line-height: 1.75em
273 padding: 0 5px
281 padding: 0 5px
274 color: #444444
282 color: #444444
275 background: #bbbbbb
283 background: #bbbbbb
276 font-weight: bold
284 font-weight: bold
277
285
278 &.contest-title
286 &.contest-title
279 color: white
287 color: white
280 text-align: center
288 text-align: center
281 line-height: 2em
289 line-height: 2em
282
290
283 &.registration-desc, &.test-desc
291 &.registration-desc, &.test-desc
284 border: 1px dotted gray
292 border: 1px dotted gray
285 background: #f5f5f5
293 background: #f5f5f5
286 padding: 5px
294 padding: 5px
287 margin: 10px 0
295 margin: 10px 0
288 font-size: 12px
296 font-size: 12px
289 line-height: 1.5em
297 line-height: 1.5em
290
298
291 h2.contest-title
299 h2.contest-title
292 margin-top: 5px
300 margin-top: 5px
293 - margin-bottom: 5px No newline at end of file
301 + margin-bottom: 5px
@@ -1,48 +1,51
1 class LoginController < ApplicationController
1 class LoginController < ApplicationController
2
2
3 def index
3 def index
4 # show login screen
4 # show login screen
5 reset_session
5 reset_session
6 redirect_to :controller => 'main', :action => 'login'
6 redirect_to :controller => 'main', :action => 'login'
7 end
7 end
8
8
9 def login
9 def login
10 if user = User.authenticate(params[:login], params[:password])
10 if user = User.authenticate(params[:login], params[:password])
11 session[:user_id] = user.id
11 session[:user_id] = user.id
12 session[:admin] = user.admin?
12 session[:admin] = user.admin?
13
13
14 # clear forced logout flag for multicontests contest change
14 # clear forced logout flag for multicontests contest change
15 if GraderConfiguration.multicontests?
15 if GraderConfiguration.multicontests?
16 contest_stat = user.contest_stat
16 contest_stat = user.contest_stat
17 if contest_stat.respond_to? :forced_logout
17 if contest_stat.respond_to? :forced_logout
18 if contest_stat.forced_logout
18 if contest_stat.forced_logout
19 contest_stat.forced_logout = false
19 contest_stat.forced_logout = false
20 contest_stat.save
20 contest_stat.save
21 end
21 end
22 end
22 end
23 end
23 end
24
24
25 + #save login information
26 + Login.create(user_id: user.id, ip_address: request.remote_ip)
27 +
25 redirect_to :controller => 'main', :action => 'list'
28 redirect_to :controller => 'main', :action => 'list'
26 else
29 else
27 flash[:notice] = 'Wrong password'
30 flash[:notice] = 'Wrong password'
28 redirect_to :controller => 'main', :action => 'login'
31 redirect_to :controller => 'main', :action => 'login'
29 end
32 end
30 end
33 end
31
34
32 def site_login
35 def site_login
33 begin
36 begin
34 site = Site.find(params[:login][:site_id])
37 site = Site.find(params[:login][:site_id])
35 rescue ActiveRecord::RecordNotFound
38 rescue ActiveRecord::RecordNotFound
36 site = nil
39 site = nil
37 end
40 end
38 if site==nil
41 if site==nil
39 flash[:notice] = 'Wrong site'
42 flash[:notice] = 'Wrong site'
40 redirect_to :controller => 'main', :action => 'login' and return
43 redirect_to :controller => 'main', :action => 'login' and return
41 end
44 end
42 if (site.password) and (site.password == params[:login][:password])
45 if (site.password) and (site.password == params[:login][:password])
43 session[:site_id] = site.id
46 session[:site_id] = site.id
44 redirect_to :controller => 'site', :action => 'index'
47 redirect_to :controller => 'site', :action => 'index'
45 else
48 else
46 flash[:notice] = 'Wrong site password'
49 flash[:notice] = 'Wrong site password'
47 redirect_to :controller => 'site', :action => 'login'
50 redirect_to :controller => 'site', :action => 'login'
48 end
51 end
@@ -1,39 +1,40
1 # Methods added to this helper will be available to all templates in the application.
1 # Methods added to this helper will be available to all templates in the application.
2 module ApplicationHelper
2 module ApplicationHelper
3
3
4 def user_header
4 def user_header
5 menu_items = ''
5 menu_items = ''
6 user = User.find(session[:user_id])
6 user = User.find(session[:user_id])
7
7
8 if (user!=nil) and (session[:admin])
8 if (user!=nil) and (session[:admin])
9 # admin menu
9 # admin menu
10 menu_items << "<b>Administrative task:</b> "
10 menu_items << "<b>Administrative task:</b> "
11 append_to menu_items, '[Announcements]', 'announcements', 'index'
11 append_to menu_items, '[Announcements]', 'announcements', 'index'
12 append_to menu_items, '[Msg console]', 'messages', 'console'
12 append_to menu_items, '[Msg console]', 'messages', 'console'
13 append_to menu_items, '[Problems]', 'problems', 'index'
13 append_to menu_items, '[Problems]', 'problems', 'index'
14 append_to menu_items, '[Users]', 'user_admin', 'index'
14 append_to menu_items, '[Users]', 'user_admin', 'index'
15 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
15 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
16 + append_to menu_items, '[Report]', 'report', 'login_stat'
16 append_to menu_items, '[Graders]', 'graders', 'list'
17 append_to menu_items, '[Graders]', 'graders', 'list'
17 append_to menu_items, '[Contests]', 'contest_management', 'index'
18 append_to menu_items, '[Contests]', 'contest_management', 'index'
18 append_to menu_items, '[Sites]', 'sites', 'index'
19 append_to menu_items, '[Sites]', 'sites', 'index'
19 append_to menu_items, '[System config]', 'configurations', 'index'
20 append_to menu_items, '[System config]', 'configurations', 'index'
20 menu_items << "<br/>"
21 menu_items << "<br/>"
21 end
22 end
22
23
23 # main page
24 # main page
24 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
25 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
25 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
26 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
26
27
27 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
28 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
28 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
29 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
29 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
30 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
30 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
31 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
31 end
32 end
32 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
33 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
33
34
34 if GraderConfiguration['system.user_setting_enabled']
35 if GraderConfiguration['system.user_setting_enabled']
35 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
36 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
36 end
37 end
37 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
38 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
38
39
39 menu_items.html_safe
40 menu_items.html_safe
@@ -1,114 +1,121
1 class Problem < ActiveRecord::Base
1 class Problem < ActiveRecord::Base
2
2
3 belongs_to :description
3 belongs_to :description
4 has_and_belongs_to_many :contests, :uniq => true
4 has_and_belongs_to_many :contests, :uniq => true
5 has_many :test_pairs, :dependent => :delete_all
5 has_many :test_pairs, :dependent => :delete_all
6
6
7 validates_presence_of :name
7 validates_presence_of :name
8 validates_format_of :name, :with => /^\w+$/
8 validates_format_of :name, :with => /^\w+$/
9 validates_presence_of :full_name
9 validates_presence_of :full_name
10
10
11 scope :available, :conditions => {:available => true}
11 scope :available, :conditions => {:available => true}
12
12
13 DEFAULT_TIME_LIMIT = 1
13 DEFAULT_TIME_LIMIT = 1
14 DEFAULT_MEMORY_LIMIT = 32
14 DEFAULT_MEMORY_LIMIT = 32
15
15
16 def self.find_available_problems
16 def self.find_available_problems
17 - Problem.available.all(:order => "date_added DESC")
17 + Problem.available.all(:order => "date_added DESC, name ASC")
18 end
18 end
19
19
20 def self.create_from_import_form_params(params, old_problem=nil)
20 def self.create_from_import_form_params(params, old_problem=nil)
21 org_problem = old_problem || Problem.new
21 org_problem = old_problem || Problem.new
22 import_params, problem = Problem.extract_params_and_check(params,
22 import_params, problem = Problem.extract_params_and_check(params,
23 org_problem)
23 org_problem)
24
24
25 if !problem.errors.empty?
25 if !problem.errors.empty?
26 return problem, 'Error importing'
26 return problem, 'Error importing'
27 end
27 end
28
28
29 problem.full_score = 100
29 problem.full_score = 100
30 problem.date_added = Time.new
30 problem.date_added = Time.new
31 problem.test_allowed = true
31 problem.test_allowed = true
32 problem.output_only = false
32 problem.output_only = false
33 problem.available = false
33 problem.available = false
34
34
35 if not problem.save
35 if not problem.save
36 return problem, 'Error importing'
36 return problem, 'Error importing'
37 end
37 end
38
38
39 import_to_db = params.has_key? :import_to_db
39 import_to_db = params.has_key? :import_to_db
40
40
41 importer = TestdataImporter.new(problem)
41 importer = TestdataImporter.new(problem)
42
42
43 if not importer.import_from_file(import_params[:file],
43 if not importer.import_from_file(import_params[:file],
44 import_params[:time_limit],
44 import_params[:time_limit],
45 import_params[:memory_limit],
45 import_params[:memory_limit],
46 + import_params[:checker_name],
46 import_to_db)
47 import_to_db)
47 problem.errors.add_to_base('Import error.')
48 problem.errors.add_to_base('Import error.')
48 end
49 end
49
50
50 return problem, importer.log_msg
51 return problem, importer.log_msg
51 end
52 end
52
53
53 def self.download_file_basedir
54 def self.download_file_basedir
54 return "#{Rails.root}/data/tasks"
55 return "#{Rails.root}/data/tasks"
55 end
56 end
56
57
57 protected
58 protected
58
59
59 def self.to_i_or_default(st, default)
60 def self.to_i_or_default(st, default)
60 if st!=''
61 if st!=''
61 result = st.to_i
62 result = st.to_i
62 end
63 end
63 result ||= default
64 result ||= default
64 end
65 end
65
66
66 def self.to_f_or_default(st, default)
67 def self.to_f_or_default(st, default)
67 if st!=''
68 if st!=''
68 result = st.to_f
69 result = st.to_f
69 end
70 end
70 result ||= default
71 result ||= default
71 end
72 end
72
73
73 def self.extract_params_and_check(params, problem)
74 def self.extract_params_and_check(params, problem)
74 time_limit = Problem.to_f_or_default(params[:time_limit],
75 time_limit = Problem.to_f_or_default(params[:time_limit],
75 DEFAULT_TIME_LIMIT)
76 DEFAULT_TIME_LIMIT)
76 memory_limit = Problem.to_i_or_default(params[:memory_limit],
77 memory_limit = Problem.to_i_or_default(params[:memory_limit],
77 DEFAULT_MEMORY_LIMIT)
78 DEFAULT_MEMORY_LIMIT)
78
79
79 if time_limit<=0 or time_limit >60
80 if time_limit<=0 or time_limit >60
80 problem.errors.add_to_base('Time limit out of range.')
81 problem.errors.add_to_base('Time limit out of range.')
81 end
82 end
82
83
83 if memory_limit==0 and params[:memory_limit]!='0'
84 if memory_limit==0 and params[:memory_limit]!='0'
84 problem.errors.add_to_base('Memory limit format errors.')
85 problem.errors.add_to_base('Memory limit format errors.')
85 elsif memory_limit<=0 or memory_limit >512
86 elsif memory_limit<=0 or memory_limit >512
86 problem.errors.add_to_base('Memory limit out of range.')
87 problem.errors.add_to_base('Memory limit out of range.')
87 end
88 end
88
89
89 if params[:file]==nil or params[:file]==''
90 if params[:file]==nil or params[:file]==''
90 problem.errors.add_to_base('No testdata file.')
91 problem.errors.add_to_base('No testdata file.')
91 end
92 end
92
93
94 + checker_name = 'text'
95 + if ['text','float'].include? params[:checker]
96 + checker_name = params[:checker]
97 + end
98 +
93 file = params[:file]
99 file = params[:file]
94
100
95 if !problem.errors.empty?
101 if !problem.errors.empty?
96 return nil, problem
102 return nil, problem
97 end
103 end
98
104
99 problem.name = params[:name]
105 problem.name = params[:name]
100 if params[:full_name]!=''
106 if params[:full_name]!=''
101 problem.full_name = params[:full_name]
107 problem.full_name = params[:full_name]
102 else
108 else
103 problem.full_name = params[:name]
109 problem.full_name = params[:name]
104 end
110 end
105
111
106 return [{
112 return [{
107 :time_limit => time_limit,
113 :time_limit => time_limit,
108 :memory_limit => memory_limit,
114 :memory_limit => memory_limit,
109 - :file => file
115 + :file => file,
116 + :checker_name => checker_name
110 },
117 },
111 problem]
118 problem]
112 end
119 end
113
120
114 end
121 end
@@ -1,26 +1,28
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 + require 'net/https'
4 + require 'net/http'
3 require 'json'
5 require 'json'
4
6
5 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
6
8
7 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
8
10
9 has_many :test_requests, :order => "submitted_at DESC"
11 has_many :test_requests, :order => "submitted_at DESC"
10
12
11 has_many :messages,
13 has_many :messages,
12 :class_name => "Message",
14 :class_name => "Message",
13 :foreign_key => "sender_id",
15 :foreign_key => "sender_id",
14 :order => 'created_at DESC'
16 :order => 'created_at DESC'
15
17
16 has_many :replied_messages,
18 has_many :replied_messages,
17 :class_name => "Message",
19 :class_name => "Message",
18 :foreign_key => "receiver_id",
20 :foreign_key => "receiver_id",
19 :order => 'created_at DESC'
21 :order => 'created_at DESC'
20
22
21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
22
24
23 belongs_to :site
25 belongs_to :site
24 belongs_to :country
26 belongs_to :country
25
27
26 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
@@ -60,76 +62,83
60 # this is for will_paginate
62 # this is for will_paginate
61 cattr_reader :per_page
63 cattr_reader :per_page
62 @@per_page = 50
64 @@per_page = 50
63
65
64 def self.authenticate(login, password)
66 def self.authenticate(login, password)
65 user = find_by_login(login)
67 user = find_by_login(login)
66 if user
68 if user
67 return user if user.authenticated?(password)
69 return user if user.authenticated?(password)
68 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
70 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
69 user.password = password
71 user.password = password
70 user.save
72 user.save
71 return user
73 return user
72 end
74 end
73 end
75 end
74 end
76 end
75
77
76 def authenticated?(password)
78 def authenticated?(password)
77 if self.activated
79 if self.activated
78 hashed_password == User.encrypt(password,self.salt)
80 hashed_password == User.encrypt(password,self.salt)
79 else
81 else
80 false
82 false
81 end
83 end
82 end
84 end
83
85
84 - def authenticated_by_pop3?(password)
86 + def authenticated_by_pop3?(password)
85 Net::POP3.enable_ssl
87 Net::POP3.enable_ssl
86 pop = Net::POP3.new('pops.it.chula.ac.th')
88 pop = Net::POP3.new('pops.it.chula.ac.th')
87 authen = true
89 authen = true
88 begin
90 begin
89 pop.start(login, password)
91 pop.start(login, password)
90 pop.finish
92 pop.finish
91 return true
93 return true
92 rescue
94 rescue
93 return false
95 return false
94 end
96 end
95 end
97 end
96
98
97 def authenticated_by_cucas?(password)
99 def authenticated_by_cucas?(password)
98 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
99 appid = '41508763e340d5858c00f8c1a0f5a2bb'
101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
100 appsecret ='d9cbb5863091dbe186fded85722a1e31'
102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
101 post_args = {
103 post_args = {
102 'appid' => appid,
104 'appid' => appid,
103 'appsecret' => appsecret,
105 'appsecret' => appsecret,
104 'username' => login,
106 'username' => login,
105 'password' => password
107 'password' => password
106 }
108 }
107
109
108 #simple call
110 #simple call
109 begin
111 begin
110 - resp = Net::HTTP.post_form(url, post_args)
112 + http = Net::HTTP.new('www.cas.chula.ac.th', 443)
111 - result = JSON.parse resp.body
113 + http.use_ssl = true
114 + result = [ ]
115 + http.start do |http|
116 + req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
117 + param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
118 + resp = http.request(req,param)
119 + result = JSON.parse resp.body
120 + end
112 return true if result["type"] == "beanStudent"
121 return true if result["type"] == "beanStudent"
113 rescue
122 rescue
114 return false
123 return false
115 end
124 end
116 return false
125 return false
117 end
126 end
118
127
119 def admin?
128 def admin?
120 self.roles.detect {|r| r.name == 'admin' }
129 self.roles.detect {|r| r.name == 'admin' }
121 end
130 end
122
131
123 def email_for_editing
132 def email_for_editing
124 if self.email==nil
133 if self.email==nil
125 "(unknown)"
134 "(unknown)"
126 elsif self.email==''
135 elsif self.email==''
127 "(blank)"
136 "(blank)"
128 else
137 else
129 self.email
138 self.email
130 end
139 end
131 end
140 end
132
141
133 def email_for_editing=(e)
142 def email_for_editing=(e)
134 self.email=e
143 self.email=e
135 end
144 end
@@ -1,21 +1,23
1 <!DOCTYPE html>
1 <!DOCTYPE html>
2 <html>
2 <html>
3 <head>
3 <head>
4 <title><%= GraderConfiguration['contest.name'] %></title>
4 <title><%= GraderConfiguration['contest.name'] %></title>
5 <%= stylesheet_link_tag "application", :media => "all" %>
5 <%= stylesheet_link_tag "application", :media => "all" %>
6 <%= javascript_include_tag "application" %>
6 <%= javascript_include_tag "application" %>
7 <%= csrf_meta_tags %>
7 <%= csrf_meta_tags %>
8 + <%= content_for :header %>
8 <%= yield :head %>
9 <%= yield :head %>
10 +
9 </head>
11 </head>
10 <body>
12 <body>
11
13
12 <div class="userbar">
14 <div class="userbar">
13 <%= user_header %>
15 <%= user_header %>
14 </div>
16 </div>
15
17
16 <%= content_tag(:p,flash[:notice],:style => "color:green") if flash[:notice]!=nil %>
18 <%= content_tag(:p,flash[:notice],:style => "color:green") if flash[:notice]!=nil %>
17
19
18 <%= yield %>
20 <%= yield %>
19
21
20 </body>
22 </body>
21 </html>
23 </html>
@@ -1,18 +1,18
1 <tr class="info-<%= (problem_counter%2==0) ? "even" : "odd" %>">
1 <tr class="info-<%= (problem_counter%2==0) ? "even" : "odd" %>">
2 <td>
2 <td>
3 <%= "#{problem_counter+1}" %>
3 <%= "#{problem_counter+1}" %>
4 </td>
4 </td>
5 <td>
5 <td>
6 - <%= "#{problem.full_name} (#{problem.name})" %>
6 + <%= "(#{problem.name}) #{problem.full_name}" %>
7 <%= link_to_description_if_any "[#{t 'main.problem_desc'}]", problem %>
7 <%= link_to_description_if_any "[#{t 'main.problem_desc'}]", problem %>
8 </td>
8 </td>
9 <td align="center">
9 <td align="center">
10 <%= @prob_submissions[problem.id][:count] %>
10 <%= @prob_submissions[problem.id][:count] %>
11 </td>
11 </td>
12 <td>
12 <td>
13 <%= render :partial => 'submission_short',
13 <%= render :partial => 'submission_short',
14 :locals => {
14 :locals => {
15 :submission => @prob_submissions[problem.id][:submission],
15 :submission => @prob_submissions[problem.id][:submission],
16 :problem_name => problem.name }%>
16 :problem_name => problem.name }%>
17 </td>
17 </td>
18 </tr>
18 </tr>
@@ -11,48 +11,61
11 = form_tag({:action => 'do_import'}, :multipart => true) do
11 = form_tag({:action => 'do_import'}, :multipart => true) do
12 .submitbox
12 .submitbox
13 %table
13 %table
14 %tr
14 %tr
15 %td Name:
15 %td Name:
16 %td= text_field_tag 'name'
16 %td= text_field_tag 'name'
17 %tr
17 %tr
18 %td Full name:
18 %td Full name:
19 %td
19 %td
20 = text_field_tag 'full_name'
20 = text_field_tag 'full_name'
21 %span{:class => 'help'} Leave blank to use the same value as the name above.
21 %span{:class => 'help'} Leave blank to use the same value as the name above.
22 %tr
22 %tr
23 %td Testdata file:
23 %td Testdata file:
24 %td= file_field_tag 'file'
24 %td= file_field_tag 'file'
25 %tr
25 %tr
26 %td
26 %td
27 %td
27 %td
28 %span{:class => 'help'}
28 %span{:class => 'help'}
29 In .zip, .tgz, tar.gz, .tar format.
29 In .zip, .tgz, tar.gz, .tar format.
30 It should includes inputs (e.g., 1.in, 2a.in, 2b.in)
30 It should includes inputs (e.g., 1.in, 2a.in, 2b.in)
31 and solutions (e.g., 1.sol, 2a.sol, 2b.sol).
31 and solutions (e.g., 1.sol, 2a.sol, 2b.sol).
32 %br/
32 %br/
33 You may put task description in *.html for raw html
33 You may put task description in *.html for raw html
34 and *.md or *.markdown for markdown.
34 and *.md or *.markdown for markdown.
35 + %br/
36 + You may also put a pdf file for the task description
37 + %tr
38 + %td Checker:
39 + %td= select_tag 'checker', options_for_select([['Text checker','text'],['Float checker','float']], 'text')
40 + %tr
41 + %td
42 + %td
43 + %span{:class => 'help'}
44 + "Text" checker checks if the text (including numbers) is the same, ignoring any whitespace
45 + %br/
46 + "Float" checker checks if all numbers is within EPSILON error using formula |a-b| < EPSILON * max(|a|,|b|)
47 +
35 - if @allow_test_pair_import
48 - if @allow_test_pair_import
36 %tr
49 %tr
37 %td
50 %td
38 %td
51 %td
39 = check_box_tag 'import_to_db'
52 = check_box_tag 'import_to_db'
40 Import test data to database (for a test-pair task)
53 Import test data to database (for a test-pair task)
41 %tr
54 %tr
42 %td Time limit:
55 %td Time limit:
43 %td
56 %td
44 = text_field_tag 'time_limit'
57 = text_field_tag 'time_limit'
45 %span{:class => 'help'} In seconds. Leave blank to use 1 sec.
58 %span{:class => 'help'} In seconds. Leave blank to use 1 sec.
46 %tr
59 %tr
47 %td Memory limit:
60 %td Memory limit:
48 %td
61 %td
49 = text_field_tag 'memory_limit'
62 = text_field_tag 'memory_limit'
50 %span{:class => 'help'} In MB. Leave blank to use 32MB.
63 %span{:class => 'help'} In MB. Leave blank to use 32MB.
51 %tr
64 %tr
52 %td
65 %td
53 %td= submit_tag 'Import problem'
66 %td= submit_tag 'Import problem'
54
67
55 - if @log
68 - if @log
56 %h3 Import log
69 %h3 Import log
57 %pre.import-log
70 %pre.import-log
58 = @log
71 = @log
@@ -1,25 +1,27
1 CafeGrader::Application.routes.draw do
1 CafeGrader::Application.routes.draw do
2 + get "report/login"
3 +
2 resources :contests
4 resources :contests
3
5
4 resources :announcements
6 resources :announcements
5 resources :sites
7 resources :sites
6
8
7 # The priority is based upon order of creation:
9 # The priority is based upon order of creation:
8 # first created -> highest priority.
10 # first created -> highest priority.
9
11
10 # Sample of regular route:
12 # Sample of regular route:
11 # match 'products/:id' => 'catalog#view'
13 # match 'products/:id' => 'catalog#view'
12 # Keep in mind you can assign values other than :controller and :action
14 # Keep in mind you can assign values other than :controller and :action
13
15
14 # Sample of named route:
16 # Sample of named route:
15 # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
17 # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
16 # This route can be invoked with purchase_url(:id => product.id)
18 # This route can be invoked with purchase_url(:id => product.id)
17
19
18 # Sample resource route (maps HTTP verbs to controller actions automatically):
20 # Sample resource route (maps HTTP verbs to controller actions automatically):
19 # resources :products
21 # resources :products
20
22
21 # Sample resource route with options:
23 # Sample resource route with options:
22 # resources :products do
24 # resources :products do
23 # member do
25 # member do
24 # get 'short'
26 # get 'short'
25 # post 'toggle'
27 # post 'toggle'
@@ -1,38 +1,38
1 # encoding: UTF-8
1 # encoding: UTF-8
2 # This file is auto-generated from the current state of the database. Instead
2 # This file is auto-generated from the current state of the database. Instead
3 # of editing this file, please use the migrations feature of Active Record to
3 # of editing this file, please use the migrations feature of Active Record to
4 # incrementally modify your database, and then regenerate this schema definition.
4 # incrementally modify your database, and then regenerate this schema definition.
5 #
5 #
6 # Note that this schema.rb definition is the authoritative source for your
6 # Note that this schema.rb definition is the authoritative source for your
7 # database schema. If you need to create the application database on another
7 # database schema. If you need to create the application database on another
8 # system, you should be using db:schema:load, not running all the migrations
8 # system, you should be using db:schema:load, not running all the migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 #
11 #
12 # It's strongly recommended to check this file into your version control system.
12 # It's strongly recommended to check this file into your version control system.
13
13
14 - ActiveRecord::Schema.define(:version => 20140823031747) do
14 + ActiveRecord::Schema.define(:version => 20140826095949) do
15
15
16 create_table "announcements", :force => true do |t|
16 create_table "announcements", :force => true do |t|
17 t.string "author"
17 t.string "author"
18 t.text "body"
18 t.text "body"
19 t.boolean "published"
19 t.boolean "published"
20 t.datetime "created_at", :null => false
20 t.datetime "created_at", :null => false
21 t.datetime "updated_at", :null => false
21 t.datetime "updated_at", :null => false
22 t.boolean "frontpage", :default => false
22 t.boolean "frontpage", :default => false
23 t.boolean "contest_only", :default => false
23 t.boolean "contest_only", :default => false
24 t.string "title"
24 t.string "title"
25 t.string "notes"
25 t.string "notes"
26 end
26 end
27
27
28 create_table "contests", :force => true do |t|
28 create_table "contests", :force => true do |t|
29 t.string "title"
29 t.string "title"
30 t.boolean "enabled"
30 t.boolean "enabled"
31 t.datetime "created_at", :null => false
31 t.datetime "created_at", :null => false
32 t.datetime "updated_at", :null => false
32 t.datetime "updated_at", :null => false
33 t.string "name"
33 t.string "name"
34 end
34 end
35
35
36 create_table "contests_problems", :id => false, :force => true do |t|
36 create_table "contests_problems", :id => false, :force => true do |t|
37 t.integer "contest_id"
37 t.integer "contest_id"
38 t.integer "problem_id"
38 t.integer "problem_id"
@@ -65,48 +65,55
65 t.text "description"
65 t.text "description"
66 end
66 end
67
67
68 create_table "grader_processes", :force => true do |t|
68 create_table "grader_processes", :force => true do |t|
69 t.string "host", :limit => 20
69 t.string "host", :limit => 20
70 t.integer "pid"
70 t.integer "pid"
71 t.string "mode"
71 t.string "mode"
72 t.boolean "active"
72 t.boolean "active"
73 t.datetime "created_at", :null => false
73 t.datetime "created_at", :null => false
74 t.datetime "updated_at", :null => false
74 t.datetime "updated_at", :null => false
75 t.integer "task_id"
75 t.integer "task_id"
76 t.string "task_type"
76 t.string "task_type"
77 t.boolean "terminated"
77 t.boolean "terminated"
78 end
78 end
79
79
80 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
80 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
81
81
82 create_table "languages", :force => true do |t|
82 create_table "languages", :force => true do |t|
83 t.string "name", :limit => 10
83 t.string "name", :limit => 10
84 t.string "pretty_name"
84 t.string "pretty_name"
85 t.string "ext", :limit => 10
85 t.string "ext", :limit => 10
86 t.string "common_ext"
86 t.string "common_ext"
87 end
87 end
88
88
89 + create_table "logins", :force => true do |t|
90 + t.string "user_id"
91 + t.string "ip_address"
92 + t.datetime "created_at", :null => false
93 + t.datetime "updated_at", :null => false
94 + end
95 +
89 create_table "messages", :force => true do |t|
96 create_table "messages", :force => true do |t|
90 t.integer "sender_id"
97 t.integer "sender_id"
91 t.integer "receiver_id"
98 t.integer "receiver_id"
92 t.integer "replying_message_id"
99 t.integer "replying_message_id"
93 t.text "body"
100 t.text "body"
94 t.boolean "replied"
101 t.boolean "replied"
95 t.datetime "created_at", :null => false
102 t.datetime "created_at", :null => false
96 t.datetime "updated_at", :null => false
103 t.datetime "updated_at", :null => false
97 end
104 end
98
105
99 create_table "problems", :force => true do |t|
106 create_table "problems", :force => true do |t|
100 t.string "name", :limit => 30
107 t.string "name", :limit => 30
101 t.string "full_name"
108 t.string "full_name"
102 t.integer "full_score"
109 t.integer "full_score"
103 t.date "date_added"
110 t.date "date_added"
104 t.boolean "available"
111 t.boolean "available"
105 t.string "url"
112 t.string "url"
106 t.integer "description_id"
113 t.integer "description_id"
107 t.boolean "test_allowed"
114 t.boolean "test_allowed"
108 t.boolean "output_only"
115 t.boolean "output_only"
109 t.string "description_filename"
116 t.string "description_filename"
110 end
117 end
111
118
112 create_table "rights", :force => true do |t|
119 create_table "rights", :force => true do |t|
@@ -29,30 +29,30
29 end
29 end
30
30
31 def self.start_grader(env)
31 def self.start_grader(env)
32 GraderScript.call_grader "#{env} queue &"
32 GraderScript.call_grader "#{env} queue &"
33 GraderScript.call_grader "#{env} test_request &"
33 GraderScript.call_grader "#{env} test_request &"
34 end
34 end
35
35
36 def self.call_import_problem(problem_name,
36 def self.call_import_problem(problem_name,
37 problem_dir,
37 problem_dir,
38 time_limit=1,
38 time_limit=1,
39 memory_limit=32,
39 memory_limit=32,
40 checker_name='text')
40 checker_name='text')
41 if GraderScript.grader_control_enabled?
41 if GraderScript.grader_control_enabled?
42 cur_dir = `pwd`.chomp
42 cur_dir = `pwd`.chomp
43 Dir.chdir(GRADER_ROOT_DIR)
43 Dir.chdir(GRADER_ROOT_DIR)
44
44
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 " -t #{time_limit} -m #{memory_limit}"
47 " -t #{time_limit} -m #{memory_limit}"
48
48
49 output = `#{cmd}`
49 output = `#{cmd}`
50
50
51 Dir.chdir(cur_dir)
51 Dir.chdir(cur_dir)
52
52
53 - return output
53 + return "import CMD: #{cmd}\n" + output
54 end
54 end
55 return ''
55 return ''
56 end
56 end
57
57
58 end
58 end
@@ -1,46 +1,48
1 require 'tmpdir'
1 require 'tmpdir'
2
2
3 class TestdataImporter
3 class TestdataImporter
4
4
5 attr :log_msg
5 attr :log_msg
6
6
7 def initialize(problem)
7 def initialize(problem)
8 @problem = problem
8 @problem = problem
9 end
9 end
10
10
11 def import_from_file(tempfile,
11 def import_from_file(tempfile,
12 time_limit,
12 time_limit,
13 memory_limit,
13 memory_limit,
14 + checker_name='text',
14 import_to_db=false)
15 import_to_db=false)
15
16
16 dirname = extract(tempfile)
17 dirname = extract(tempfile)
17 return false if not dirname
18 return false if not dirname
18 if not import_to_db
19 if not import_to_db
19 @log_msg = GraderScript.call_import_problem(@problem.name,
20 @log_msg = GraderScript.call_import_problem(@problem.name,
20 dirname,
21 dirname,
21 time_limit,
22 time_limit,
22 - memory_limit)
23 + memory_limit,
24 + checker_name)
23 else
25 else
24 # Import test data to test pairs.
26 # Import test data to test pairs.
25
27
26 @problem.test_pairs.clear
28 @problem.test_pairs.clear
27 if import_test_pairs(dirname)
29 if import_test_pairs(dirname)
28 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
30 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
29 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
31 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
30 else
32 else
31 @log_msg = "Importing test pair failed. (0 test pairs imported)"
33 @log_msg = "Importing test pair failed. (0 test pairs imported)"
32 end
34 end
33 end
35 end
34
36
35 @log_msg << import_problem_description(dirname)
37 @log_msg << import_problem_description(dirname)
36 @log_msg << import_problem_pdf(dirname)
38 @log_msg << import_problem_pdf(dirname)
37 @log_msg << import_full_score(dirname)
39 @log_msg << import_full_score(dirname)
38
40
39 return true
41 return true
40 end
42 end
41
43
42 protected
44 protected
43
45
44 def self.long_ext(filename)
46 def self.long_ext(filename)
45 i = filename.index('.')
47 i = filename.index('.')
46 len = filename.length
48 len = filename.length
You need to be logged in to leave comments. Login now