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,293 +1,301
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
25 hr
33 hr
26 border-top: 1px solid #dddddd
34 border-top: 1px solid #dddddd
27 border-bottom: 1px solid #eeeeee
35 border-bottom: 1px solid #eeeeee
28
36
29
37
30 a
38 a
31 color: #6666cc
39 color: #6666cc
32 text-decoration: none
40 text-decoration: none
33
41
34 &:link, &:visited
42 &:link, &:visited
35 color: #6666cc
43 color: #6666cc
36 text-decoration: none
44 text-decoration: none
37
45
38 &:hover, &:focus
46 &:hover, &:focus
39 color: #111166
47 color: #111166
40 text-decoration: none
48 text-decoration: none
41
49
42
50
43 div
51 div
44 &.userbar
52 &.userbar
45 line-height: 1.5em
53 line-height: 1.5em
46 text-align: right
54 text-align: right
47 font-size: 12px
55 font-size: 12px
48
56
49 &.title
57 &.title
50 padding: 10px 0px
58 padding: 10px 0px
51 line-height: 1.5em
59 line-height: 1.5em
52 font-size: 13px
60 font-size: 13px
53
61
54 span.contest-over-msg
62 span.contest-over-msg
55 font-size: 15px
63 font-size: 15px
56 color: red
64 color: red
57
65
58 table
66 table
59 width: 100%
67 width: 100%
60 font-weight: bold
68 font-weight: bold
61
69
62 td
70 td
63 &.left-col
71 &.left-col
64 text-align: left
72 text-align: left
65 vertical-align: top
73 vertical-align: top
66 color: #444444
74 color: #444444
67
75
68 &.right-col
76 &.right-col
69 text-align: right
77 text-align: right
70 vertical-align: top
78 vertical-align: top
71 font-size: 18px
79 font-size: 18px
72 color: #116699
80 color: #116699
73
81
74
82
75 table.info
83 table.info
76 margin: 10px 0
84 margin: 10px 0
77 border: 1px solid #666666
85 border: 1px solid #666666
78 border-collapse: collapse
86 border-collapse: collapse
79 font-size: 12px
87 font-size: 12px
80
88
81 th
89 th
82 border: 1px solid #666666
90 border: 1px solid #666666
83 line-height: 1.5em
91 line-height: 1.5em
84 padding: 0 0.5em
92 padding: 0 0.5em
85
93
86 td
94 td
87 border-left: 1px solid #666666
95 border-left: 1px solid #666666
88 border-right: 1px solid #666666
96 border-right: 1px solid #666666
89 line-height: 1.5em
97 line-height: 1.5em
90 padding: 0 0.5em
98 padding: 0 0.5em
91
99
92
100
93 tr
101 tr
94 &.info-head
102 &.info-head
95 background: #777777
103 background: #777777
96 color: white
104 color: white
97
105
98 &.info-odd
106 &.info-odd
99 background: #eeeeee
107 background: #eeeeee
100
108
101 &.info-even
109 &.info-even
102 background: #fcfcfc
110 background: #fcfcfc
103
111
104 =basicbox
112 =basicbox
105 background: #eeeeff
113 background: #eeeeff
106 border: 1px dotted #99aaee
114 border: 1px dotted #99aaee
107 padding: 5px
115 padding: 5px
108 margin: 10px 0px
116 margin: 10px 0px
109 color: black
117 color: black
110 font-size: 13px
118 font-size: 13px
111
119
112 .infobox
120 .infobox
113 +basicbox
121 +basicbox
114
122
115 .submitbox
123 .submitbox
116 +basicbox
124 +basicbox
117
125
118 .errorExplanation
126 .errorExplanation
119 border: 1px dotted gray
127 border: 1px dotted gray
120 color: #bb2222
128 color: #bb2222
121 padding: 5px 15px 5px 15px
129 padding: 5px 15px 5px 15px
122 margin-bottom: 5px
130 margin-bottom: 5px
123 background-color: white
131 background-color: white
124 font-weight: normal
132 font-weight: normal
125
133
126 h2
134 h2
127 color: #cc1111
135 color: #cc1111
128 font-weight: bold
136 font-weight: bold
129
137
130
138
131 table.uinfo
139 table.uinfo
132 border-collapse: collapse
140 border-collapse: collapse
133 border: 1px solid black
141 border: 1px solid black
134 font-size: 13px
142 font-size: 13px
135
143
136
144
137 td.uinfo
145 td.uinfo
138 vertical-align: top
146 vertical-align: top
139 border: 1px solid black
147 border: 1px solid black
140 padding: 5px
148 padding: 5px
141
149
142
150
143 th.uinfo
151 th.uinfo
144 background: lightgreen
152 background: lightgreen
145 vertical-align: top
153 vertical-align: top
146 text-align: right
154 text-align: right
147 border: 1px solid black
155 border: 1px solid black
148 padding: 5px
156 padding: 5px
149
157
150
158
151 div
159 div
152 &.compilermsgbody
160 &.compilermsgbody
153 font-family: monospace
161 font-family: monospace
154
162
155 &.task-menu
163 &.task-menu
156 text-align: center
164 text-align: center
157 font-size: 13px
165 font-size: 13px
158 line-height: 1.75em
166 line-height: 1.75em
159 font-weight: bold
167 font-weight: bold
160 border-top: 1px dashed gray
168 border-top: 1px dashed gray
161 border-bottom: 1px dashed gray
169 border-bottom: 1px dashed gray
162 margin-top: 2px
170 margin-top: 2px
163 margin-bottom: 4px
171 margin-bottom: 4px
164
172
165
173
166 table.taskdesc
174 table.taskdesc
167 border: 2px solid #dddddd
175 border: 2px solid #dddddd
168 border-collapse: collapse
176 border-collapse: collapse
169 margin: 10px auto
177 margin: 10px auto
170 width: 90%
178 width: 90%
171 font-size: 13px
179 font-size: 13px
172
180
173 p
181 p
174 font-size: 13px
182 font-size: 13px
175
183
176 tr.name
184 tr.name
177 border: 2px solid #dddddd
185 border: 2px solid #dddddd
178 background: #dddddd
186 background: #dddddd
179 color: #333333
187 color: #333333
180 font-weight: bold
188 font-weight: bold
181 font-size: 14px
189 font-size: 14px
182 line-height: 1.5em
190 line-height: 1.5em
183 text-align: center
191 text-align: center
184
192
185 td
193 td
186 &.desc-odd
194 &.desc-odd
187 padding: 5px
195 padding: 5px
188 padding-left: 20px
196 padding-left: 20px
189 background: #fefeee
197 background: #fefeee
190
198
191 &.desc-even
199 &.desc-even
192 padding: 5px
200 padding: 5px
193 padding-left: 20px
201 padding-left: 20px
194 background: #feeefe
202 background: #feeefe
195
203
196
204
197 .announcementbox
205 .announcementbox
198 margin: 10px 0px
206 margin: 10px 0px
199 background: #bbddee
207 background: #bbddee
200 padding: 1px
208 padding: 1px
201
209
202 span.title
210 span.title
203 font-weight: bold
211 font-weight: bold
204 color: #224455
212 color: #224455
205 padding-left: 10px
213 padding-left: 10px
206 line-height: 1.6em
214 line-height: 1.6em
207
215
208 .announcement
216 .announcement
209 margin: 2px
217 margin: 2px
210 background: white
218 background: white
211 padding: 1px
219 padding: 1px
212 padding-left: 10px
220 padding-left: 10px
213 padding-right: 10px
221 padding-right: 10px
214 padding-top: 5px
222 padding-top: 5px
215 padding-bottom: 5px
223 padding-bottom: 5px
216
224
217
225
218 .announcement p
226 .announcement p
219 font-size: 12px
227 font-size: 12px
220 margin: 2px
228 margin: 2px
221
229
222
230
223 .pub-info
231 .pub-info
224 text-align: right
232 text-align: right
225 font-style: italic
233 font-style: italic
226 font-size: 9px
234 font-size: 9px
227
235
228 p
236 p
229 text-align: right
237 text-align: right
230 font-style: italic
238 font-style: italic
231 font-size: 9px
239 font-size: 9px
232
240
233
241
234 .announcement
242 .announcement
235 .toggles
243 .toggles
236 font-weight: normal
244 font-weight: normal
237 float: right
245 float: right
238 font-size: 80%
246 font-size: 80%
239
247
240 .announcement-title
248 .announcement-title
241 font-weight: bold
249 font-weight: bold
242
250
243
251
244 div
252 div
245 &.message
253 &.message
246 margin: 10px 0 0
254 margin: 10px 0 0
247
255
248 div
256 div
249 &.message
257 &.message
250 margin: 0 0 0 30px
258 margin: 0 0 0 30px
251
259
252 &.body
260 &.body
253 border: 2px solid #dddddd
261 border: 2px solid #dddddd
254 background: #fff8f8
262 background: #fff8f8
255 padding-left: 5px
263 padding-left: 5px
256
264
257 &.reply-body
265 &.reply-body
258 border: 2px solid #bbbbbb
266 border: 2px solid #bbbbbb
259 background: #fffff8
267 background: #fffff8
260 padding-left: 5px
268 padding-left: 5px
261
269
262 &.stat
270 &.stat
263 font-size: 10px
271 font-size: 10px
264 line-height: 1.75em
272 line-height: 1.75em
265 padding: 0 5px
273 padding: 0 5px
266 color: #333333
274 color: #333333
267 background: #dddddd
275 background: #dddddd
268 font-weight: bold
276 font-weight: bold
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,51 +1,54
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
49 end
52 end
50
53
51 end
54 end
@@ -1,133 +1,134
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
40 end
41 end
41
42
42 def append_to(option,label, controller, action)
43 def append_to(option,label, controller, action)
43 option << ' ' if option!=''
44 option << ' ' if option!=''
44 option << link_to_unless_current(label,
45 option << link_to_unless_current(label,
45 :controller => controller,
46 :controller => controller,
46 :action => action)
47 :action => action)
47 end
48 end
48
49
49 def format_short_time(time)
50 def format_short_time(time)
50 now = Time.now.gmtime
51 now = Time.now.gmtime
51 st = ''
52 st = ''
52 if (time.yday != now.yday) or
53 if (time.yday != now.yday) or
53 (time.year != now.year)
54 (time.year != now.year)
54 st = time.strftime("%x ")
55 st = time.strftime("%x ")
55 end
56 end
56 st + time.strftime("%X")
57 st + time.strftime("%X")
57 end
58 end
58
59
59 def format_short_duration(duration)
60 def format_short_duration(duration)
60 return '' if duration==nil
61 return '' if duration==nil
61 d = duration.to_f
62 d = duration.to_f
62 return Time.at(d).gmtime.strftime("%X")
63 return Time.at(d).gmtime.strftime("%X")
63 end
64 end
64
65
65 def read_textfile(fname,max_size=2048)
66 def read_textfile(fname,max_size=2048)
66 begin
67 begin
67 File.open(fname).read(max_size)
68 File.open(fname).read(max_size)
68 rescue
69 rescue
69 nil
70 nil
70 end
71 end
71 end
72 end
72
73
73 def user_title_bar(user)
74 def user_title_bar(user)
74 header = ''
75 header = ''
75 time_left = ''
76 time_left = ''
76
77
77 #
78 #
78 # if the contest is over
79 # if the contest is over
79 if GraderConfiguration.time_limit_mode?
80 if GraderConfiguration.time_limit_mode?
80 if user.contest_finished?
81 if user.contest_finished?
81 header = <<CONTEST_OVER
82 header = <<CONTEST_OVER
82 <tr><td colspan="2" align="center">
83 <tr><td colspan="2" align="center">
83 <span class="contest-over-msg">THE CONTEST IS OVER</span>
84 <span class="contest-over-msg">THE CONTEST IS OVER</span>
84 </td></tr>
85 </td></tr>
85 CONTEST_OVER
86 CONTEST_OVER
86 end
87 end
87 if !user.contest_started?
88 if !user.contest_started?
88 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
89 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
89 else
90 else
90 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
91 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
91 " #{format_short_duration(user.contest_time_left)}"
92 " #{format_short_duration(user.contest_time_left)}"
92 end
93 end
93 end
94 end
94
95
95 #
96 #
96 # if the contest is in the anaysis mode
97 # if the contest is in the anaysis mode
97 if GraderConfiguration.analysis_mode?
98 if GraderConfiguration.analysis_mode?
98 header = <<ANALYSISMODE
99 header = <<ANALYSISMODE
99 <tr><td colspan="2" align="center">
100 <tr><td colspan="2" align="center">
100 <span class="contest-over-msg">ANALYSIS MODE</span>
101 <span class="contest-over-msg">ANALYSIS MODE</span>
101 </td></tr>
102 </td></tr>
102 ANALYSISMODE
103 ANALYSISMODE
103 end
104 end
104
105
105 contest_name = GraderConfiguration['contest.name']
106 contest_name = GraderConfiguration['contest.name']
106
107
107 #
108 #
108 # build real title bar
109 # build real title bar
109 result = <<TITLEBAR
110 result = <<TITLEBAR
110 <div class="title">
111 <div class="title">
111 <table>
112 <table>
112 #{header}
113 #{header}
113 <tr>
114 <tr>
114 <td class="left-col">
115 <td class="left-col">
115 #{user.full_name}<br/>
116 #{user.full_name}<br/>
116 #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
117 #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
117 #{time_left}
118 #{time_left}
118 <br/>
119 <br/>
119 </td>
120 </td>
120 <td class="right-col">#{contest_name}</td>
121 <td class="right-col">#{contest_name}</td>
121 </tr>
122 </tr>
122 </table>
123 </table>
123 </div>
124 </div>
124 TITLEBAR
125 TITLEBAR
125 result.html_safe
126 result.html_safe
126 end
127 end
127
128
128 def markdown(text)
129 def markdown(text)
129 markdown = RDiscount.new(text)
130 markdown = RDiscount.new(text)
130 markdown.to_html.html_safe
131 markdown.to_html.html_safe
131 end
132 end
132
133
133 end
134 end
@@ -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,303 +1,312
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'
27
29
28 scope :activated_users, :conditions => {:activated => true}
30 scope :activated_users, :conditions => {:activated => true}
29
31
30 validates_presence_of :login
32 validates_presence_of :login
31 validates_uniqueness_of :login
33 validates_uniqueness_of :login
32 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
33 validates_length_of :login, :within => 3..30
35 validates_length_of :login, :within => 3..30
34
36
35 validates_presence_of :full_name
37 validates_presence_of :full_name
36 validates_length_of :full_name, :minimum => 1
38 validates_length_of :full_name, :minimum => 1
37
39
38 validates_presence_of :password, :if => :password_required?
40 validates_presence_of :password, :if => :password_required?
39 validates_length_of :password, :within => 4..20, :if => :password_required?
41 validates_length_of :password, :within => 4..20, :if => :password_required?
40 validates_confirmation_of :password, :if => :password_required?
42 validates_confirmation_of :password, :if => :password_required?
41
43
42 validates_format_of :email,
44 validates_format_of :email,
43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
44 :if => :email_validation?
46 :if => :email_validation?
45 validate :uniqueness_of_email_from_activated_users,
47 validate :uniqueness_of_email_from_activated_users,
46 :if => :email_validation?
48 :if => :email_validation?
47 validate :enough_time_interval_between_same_email_registrations,
49 validate :enough_time_interval_between_same_email_registrations,
48 :if => :email_validation?
50 :if => :email_validation?
49
51
50 # these are for ytopc
52 # these are for ytopc
51 # disable for now
53 # disable for now
52 #validates_presence_of :province
54 #validates_presence_of :province
53
55
54 attr_accessor :password
56 attr_accessor :password
55
57
56 before_save :encrypt_new_password
58 before_save :encrypt_new_password
57 before_save :assign_default_site
59 before_save :assign_default_site
58 before_save :assign_default_contest
60 before_save :assign_default_contest
59
61
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
136
145
137 def alias_for_editing
146 def alias_for_editing
138 if self.alias==nil
147 if self.alias==nil
139 "(unknown)"
148 "(unknown)"
140 elsif self.alias==''
149 elsif self.alias==''
141 "(blank)"
150 "(blank)"
142 else
151 else
143 self.alias
152 self.alias
144 end
153 end
145 end
154 end
146
155
147 def alias_for_editing=(e)
156 def alias_for_editing=(e)
148 self.alias=e
157 self.alias=e
149 end
158 end
150
159
151 def activation_key
160 def activation_key
152 if self.hashed_password==nil
161 if self.hashed_password==nil
153 encrypt_new_password
162 encrypt_new_password
154 end
163 end
155 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
164 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
156 end
165 end
157
166
158 def verify_activation_key(key)
167 def verify_activation_key(key)
159 key == activation_key
168 key == activation_key
160 end
169 end
161
170
162 def self.random_password(length=5)
171 def self.random_password(length=5)
163 chars = 'abcdefghjkmnopqrstuvwxyz'
172 chars = 'abcdefghjkmnopqrstuvwxyz'
164 password = ''
173 password = ''
165 length.times { password << chars[rand(chars.length - 1)] }
174 length.times { password << chars[rand(chars.length - 1)] }
166 password
175 password
167 end
176 end
168
177
169 def self.find_non_admin_with_prefix(prefix='')
178 def self.find_non_admin_with_prefix(prefix='')
170 users = User.find(:all)
179 users = User.find(:all)
171 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
180 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
172 end
181 end
173
182
174 # Contest information
183 # Contest information
175
184
176 def self.find_users_with_no_contest()
185 def self.find_users_with_no_contest()
177 users = User.find(:all)
186 users = User.find(:all)
178 return users.find_all { |u| u.contests.length == 0 }
187 return users.find_all { |u| u.contests.length == 0 }
179 end
188 end
180
189
181
190
182 def contest_time_left
191 def contest_time_left
183 if GraderConfiguration.contest_mode?
192 if GraderConfiguration.contest_mode?
184 return nil if site==nil
193 return nil if site==nil
185 return site.time_left
194 return site.time_left
186 elsif GraderConfiguration.indv_contest_mode?
195 elsif GraderConfiguration.indv_contest_mode?
187 time_limit = GraderConfiguration.contest_time_limit
196 time_limit = GraderConfiguration.contest_time_limit
188 if time_limit == nil
197 if time_limit == nil
189 return nil
198 return nil
190 end
199 end
191 if contest_stat==nil or contest_stat.started_at==nil
200 if contest_stat==nil or contest_stat.started_at==nil
192 return (Time.now.gmtime + time_limit) - Time.now.gmtime
201 return (Time.now.gmtime + time_limit) - Time.now.gmtime
193 else
202 else
194 finish_time = contest_stat.started_at + time_limit
203 finish_time = contest_stat.started_at + time_limit
195 current_time = Time.now.gmtime
204 current_time = Time.now.gmtime
196 if current_time > finish_time
205 if current_time > finish_time
197 return 0
206 return 0
198 else
207 else
199 return finish_time - current_time
208 return finish_time - current_time
200 end
209 end
201 end
210 end
202 else
211 else
203 return nil
212 return nil
204 end
213 end
205 end
214 end
206
215
207 def contest_finished?
216 def contest_finished?
208 if GraderConfiguration.contest_mode?
217 if GraderConfiguration.contest_mode?
209 return false if site==nil
218 return false if site==nil
210 return site.finished?
219 return site.finished?
211 elsif GraderConfiguration.indv_contest_mode?
220 elsif GraderConfiguration.indv_contest_mode?
212 return false if self.contest_stat(true)==nil
221 return false if self.contest_stat(true)==nil
213 return contest_time_left == 0
222 return contest_time_left == 0
214 else
223 else
215 return false
224 return false
216 end
225 end
217 end
226 end
218
227
219 def contest_started?
228 def contest_started?
220 if GraderConfiguration.indv_contest_mode?
229 if GraderConfiguration.indv_contest_mode?
221 stat = self.contest_stat
230 stat = self.contest_stat
222 return ((stat != nil) and (stat.started_at != nil))
231 return ((stat != nil) and (stat.started_at != nil))
223 elsif GraderConfiguration.contest_mode?
232 elsif GraderConfiguration.contest_mode?
224 return true if site==nil
233 return true if site==nil
225 return site.started
234 return site.started
226 else
235 else
227 return true
236 return true
228 end
237 end
229 end
238 end
230
239
231 def update_start_time
240 def update_start_time
232 stat = self.contest_stat
241 stat = self.contest_stat
233 if stat == nil or stat.started_at == nil
242 if stat == nil or stat.started_at == nil
234 stat ||= UserContestStat.new(:user => self)
243 stat ||= UserContestStat.new(:user => self)
235 stat.started_at = Time.now.gmtime
244 stat.started_at = Time.now.gmtime
236 stat.save
245 stat.save
237 end
246 end
238 end
247 end
239
248
240 def problem_in_user_contests?(problem)
249 def problem_in_user_contests?(problem)
241 problem_contests = problem.contests.all
250 problem_contests = problem.contests.all
242
251
243 if problem_contests.length == 0 # this is public contest
252 if problem_contests.length == 0 # this is public contest
244 return true
253 return true
245 end
254 end
246
255
247 contests.each do |contest|
256 contests.each do |contest|
248 if problem_contests.find {|c| c.id == contest.id }
257 if problem_contests.find {|c| c.id == contest.id }
249 return true
258 return true
250 end
259 end
251 end
260 end
252 return false
261 return false
253 end
262 end
254
263
255 def available_problems_group_by_contests
264 def available_problems_group_by_contests
256 contest_problems = []
265 contest_problems = []
257 pin = {}
266 pin = {}
258 contests.enabled.each do |contest|
267 contests.enabled.each do |contest|
259 available_problems = contest.problems.available
268 available_problems = contest.problems.available
260 contest_problems << {
269 contest_problems << {
261 :contest => contest,
270 :contest => contest,
262 :problems => available_problems
271 :problems => available_problems
263 }
272 }
264 available_problems.each {|p| pin[p.id] = true}
273 available_problems.each {|p| pin[p.id] = true}
265 end
274 end
266 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
275 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
267 contest_problems << {
276 contest_problems << {
268 :contest => nil,
277 :contest => nil,
269 :problems => other_avaiable_problems
278 :problems => other_avaiable_problems
270 }
279 }
271 return contest_problems
280 return contest_problems
272 end
281 end
273
282
274 def available_problems
283 def available_problems
275 if not GraderConfiguration.multicontests?
284 if not GraderConfiguration.multicontests?
276 return Problem.find_available_problems
285 return Problem.find_available_problems
277 else
286 else
278 contest_problems = []
287 contest_problems = []
279 pin = {}
288 pin = {}
280 contests.enabled.each do |contest|
289 contests.enabled.each do |contest|
281 contest.problems.available.each do |problem|
290 contest.problems.available.each do |problem|
282 if not pin.has_key? problem.id
291 if not pin.has_key? problem.id
283 contest_problems << problem
292 contest_problems << problem
284 end
293 end
285 pin[problem.id] = true
294 pin[problem.id] = true
286 end
295 end
287 end
296 end
288 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
297 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
289 return contest_problems + other_avaiable_problems
298 return contest_problems + other_avaiable_problems
290 end
299 end
291 end
300 end
292
301
293 def can_view_problem?(problem)
302 def can_view_problem?(problem)
294 if not GraderConfiguration.multicontests?
303 if not GraderConfiguration.multicontests?
295 return problem.available
304 return problem.available
296 else
305 else
297 return problem_in_user_contests? problem
306 return problem_in_user_contests? problem
298 end
307 end
299 end
308 end
300
309
301 protected
310 protected
302 def encrypt_new_password
311 def encrypt_new_password
303 return if password.blank?
312 return if password.blank?
@@ -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>
@@ -1,58 +1,71
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3
3
4 %h1 Import problems
4 %h1 Import problems
5
5
6 %p= link_to '[Back to problem list]', :action => 'list'
6 %p= link_to '[Back to problem list]', :action => 'list'
7
7
8 - if @problem and @problem.errors
8 - if @problem and @problem.errors
9 =error_messages_for 'problem'
9 =error_messages_for 'problem'
10
10
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,68 +1,70
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'
26 # end
28 # end
27 #
29 #
28 # collection do
30 # collection do
29 # get 'sold'
31 # get 'sold'
30 # end
32 # end
31 # end
33 # end
32
34
33 # Sample resource route with sub-resources:
35 # Sample resource route with sub-resources:
34 # resources :products do
36 # resources :products do
35 # resources :comments, :sales
37 # resources :comments, :sales
36 # resource :seller
38 # resource :seller
37 # end
39 # end
38
40
39 # Sample resource route with more complex sub-resources
41 # Sample resource route with more complex sub-resources
40 # resources :products do
42 # resources :products do
41 # resources :comments
43 # resources :comments
42 # resources :sales do
44 # resources :sales do
43 # get 'recent', :on => :collection
45 # get 'recent', :on => :collection
44 # end
46 # end
45 # end
47 # end
46
48
47 # Sample resource route within a namespace:
49 # Sample resource route within a namespace:
48 # namespace :admin do
50 # namespace :admin do
49 # # Directs /admin/products/* to Admin::ProductsController
51 # # Directs /admin/products/* to Admin::ProductsController
50 # # (app/controllers/admin/products_controller.rb)
52 # # (app/controllers/admin/products_controller.rb)
51 # resources :products
53 # resources :products
52 # end
54 # end
53
55
54 # You can have the root of your site routed with "root"
56 # You can have the root of your site routed with "root"
55 # just remember to delete public/index.html.
57 # just remember to delete public/index.html.
56 # root :to => 'welcome#index'
58 # root :to => 'welcome#index'
57
59
58 root :to => 'main#login'
60 root :to => 'main#login'
59
61
60 match 'tasks/view/:file.:ext' => 'tasks#view'
62 match 'tasks/view/:file.:ext' => 'tasks#view'
61 match 'tasks/download/:id/:file.:ext' => 'tasks#download'
63 match 'tasks/download/:id/:file.:ext' => 'tasks#download'
62
64
63 # See how all your routes lay out with "rake routes"
65 # See how all your routes lay out with "rake routes"
64
66
65 # This is a legacy wild controller route that's not recommended for RESTful applications.
67 # This is a legacy wild controller route that's not recommended for RESTful applications.
66 # Note: This route will make all actions in every controller accessible via GET requests.
68 # Note: This route will make all actions in every controller accessible via GET requests.
67 match ':controller(/:action(/:id))(.:format)'
69 match ':controller(/:action(/:id))(.:format)'
68 end
70 end
@@ -1,238 +1,245
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"
39 end
39 end
40
40
41 create_table "contests_users", :id => false, :force => true do |t|
41 create_table "contests_users", :id => false, :force => true do |t|
42 t.integer "contest_id"
42 t.integer "contest_id"
43 t.integer "user_id"
43 t.integer "user_id"
44 end
44 end
45
45
46 create_table "countries", :force => true do |t|
46 create_table "countries", :force => true do |t|
47 t.string "name"
47 t.string "name"
48 t.datetime "created_at", :null => false
48 t.datetime "created_at", :null => false
49 t.datetime "updated_at", :null => false
49 t.datetime "updated_at", :null => false
50 end
50 end
51
51
52 create_table "descriptions", :force => true do |t|
52 create_table "descriptions", :force => true do |t|
53 t.text "body"
53 t.text "body"
54 t.boolean "markdowned"
54 t.boolean "markdowned"
55 t.datetime "created_at", :null => false
55 t.datetime "created_at", :null => false
56 t.datetime "updated_at", :null => false
56 t.datetime "updated_at", :null => false
57 end
57 end
58
58
59 create_table "grader_configurations", :force => true do |t|
59 create_table "grader_configurations", :force => true do |t|
60 t.string "key"
60 t.string "key"
61 t.string "value_type"
61 t.string "value_type"
62 t.string "value"
62 t.string "value"
63 t.datetime "created_at", :null => false
63 t.datetime "created_at", :null => false
64 t.datetime "updated_at", :null => false
64 t.datetime "updated_at", :null => false
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|
113 t.string "name"
120 t.string "name"
114 t.string "controller"
121 t.string "controller"
115 t.string "action"
122 t.string "action"
116 end
123 end
117
124
118 create_table "rights_roles", :id => false, :force => true do |t|
125 create_table "rights_roles", :id => false, :force => true do |t|
119 t.integer "right_id"
126 t.integer "right_id"
120 t.integer "role_id"
127 t.integer "role_id"
121 end
128 end
122
129
123 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
130 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
124
131
125 create_table "roles", :force => true do |t|
132 create_table "roles", :force => true do |t|
126 t.string "name"
133 t.string "name"
127 end
134 end
128
135
129 create_table "roles_users", :id => false, :force => true do |t|
136 create_table "roles_users", :id => false, :force => true do |t|
130 t.integer "role_id"
137 t.integer "role_id"
131 t.integer "user_id"
138 t.integer "user_id"
132 end
139 end
133
140
134 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
141 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
135
142
136 create_table "sessions", :force => true do |t|
143 create_table "sessions", :force => true do |t|
137 t.string "session_id"
144 t.string "session_id"
138 t.text "data"
145 t.text "data"
139 t.datetime "updated_at"
146 t.datetime "updated_at"
140 end
147 end
141
148
142 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
149 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
143 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
150 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
144
151
145 create_table "sites", :force => true do |t|
152 create_table "sites", :force => true do |t|
146 t.string "name"
153 t.string "name"
147 t.boolean "started"
154 t.boolean "started"
148 t.datetime "start_time"
155 t.datetime "start_time"
149 t.datetime "created_at", :null => false
156 t.datetime "created_at", :null => false
150 t.datetime "updated_at", :null => false
157 t.datetime "updated_at", :null => false
151 t.integer "country_id"
158 t.integer "country_id"
152 t.string "password"
159 t.string "password"
153 end
160 end
154
161
155 create_table "submissions", :force => true do |t|
162 create_table "submissions", :force => true do |t|
156 t.integer "user_id"
163 t.integer "user_id"
157 t.integer "problem_id"
164 t.integer "problem_id"
158 t.integer "language_id"
165 t.integer "language_id"
159 t.text "source"
166 t.text "source"
160 t.binary "binary"
167 t.binary "binary"
161 t.datetime "submitted_at"
168 t.datetime "submitted_at"
162 t.datetime "compiled_at"
169 t.datetime "compiled_at"
163 t.text "compiler_message"
170 t.text "compiler_message"
164 t.datetime "graded_at"
171 t.datetime "graded_at"
165 t.integer "points"
172 t.integer "points"
166 t.text "grader_comment"
173 t.text "grader_comment"
167 t.integer "number"
174 t.integer "number"
168 t.string "source_filename"
175 t.string "source_filename"
169 t.float "max_runtime"
176 t.float "max_runtime"
170 t.integer "peak_memory"
177 t.integer "peak_memory"
171 t.integer "effective_code_length"
178 t.integer "effective_code_length"
172 end
179 end
173
180
174 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
181 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
175 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
182 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
176
183
177 create_table "tasks", :force => true do |t|
184 create_table "tasks", :force => true do |t|
178 t.integer "submission_id"
185 t.integer "submission_id"
179 t.datetime "created_at"
186 t.datetime "created_at"
180 t.integer "status"
187 t.integer "status"
181 t.datetime "updated_at"
188 t.datetime "updated_at"
182 end
189 end
183
190
184 create_table "test_pairs", :force => true do |t|
191 create_table "test_pairs", :force => true do |t|
185 t.integer "problem_id"
192 t.integer "problem_id"
186 t.text "input", :limit => 16777215
193 t.text "input", :limit => 16777215
187 t.text "solution", :limit => 16777215
194 t.text "solution", :limit => 16777215
188 t.datetime "created_at", :null => false
195 t.datetime "created_at", :null => false
189 t.datetime "updated_at", :null => false
196 t.datetime "updated_at", :null => false
190 end
197 end
191
198
192 create_table "test_requests", :force => true do |t|
199 create_table "test_requests", :force => true do |t|
193 t.integer "user_id"
200 t.integer "user_id"
194 t.integer "problem_id"
201 t.integer "problem_id"
195 t.integer "submission_id"
202 t.integer "submission_id"
196 t.string "input_file_name"
203 t.string "input_file_name"
197 t.string "output_file_name"
204 t.string "output_file_name"
198 t.string "running_stat"
205 t.string "running_stat"
199 t.integer "status"
206 t.integer "status"
200 t.datetime "updated_at", :null => false
207 t.datetime "updated_at", :null => false
201 t.datetime "submitted_at"
208 t.datetime "submitted_at"
202 t.datetime "compiled_at"
209 t.datetime "compiled_at"
203 t.text "compiler_message"
210 t.text "compiler_message"
204 t.datetime "graded_at"
211 t.datetime "graded_at"
205 t.string "grader_comment"
212 t.string "grader_comment"
206 t.datetime "created_at", :null => false
213 t.datetime "created_at", :null => false
207 t.float "running_time"
214 t.float "running_time"
208 t.string "exit_status"
215 t.string "exit_status"
209 t.integer "memory_usage"
216 t.integer "memory_usage"
210 end
217 end
211
218
212 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
219 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
213
220
214 create_table "user_contest_stats", :force => true do |t|
221 create_table "user_contest_stats", :force => true do |t|
215 t.integer "user_id"
222 t.integer "user_id"
216 t.datetime "started_at"
223 t.datetime "started_at"
217 t.datetime "created_at", :null => false
224 t.datetime "created_at", :null => false
218 t.datetime "updated_at", :null => false
225 t.datetime "updated_at", :null => false
219 t.boolean "forced_logout"
226 t.boolean "forced_logout"
220 end
227 end
221
228
222 create_table "users", :force => true do |t|
229 create_table "users", :force => true do |t|
223 t.string "login", :limit => 50
230 t.string "login", :limit => 50
224 t.string "full_name"
231 t.string "full_name"
225 t.string "hashed_password"
232 t.string "hashed_password"
226 t.string "salt", :limit => 5
233 t.string "salt", :limit => 5
227 t.string "alias"
234 t.string "alias"
228 t.string "email"
235 t.string "email"
229 t.integer "site_id"
236 t.integer "site_id"
230 t.integer "country_id"
237 t.integer "country_id"
231 t.boolean "activated", :default => false
238 t.boolean "activated", :default => false
232 t.datetime "created_at"
239 t.datetime "created_at"
233 t.datetime "updated_at"
240 t.datetime "updated_at"
234 end
241 end
235
242
236 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
243 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
237
244
238 end
245 end
@@ -1,58 +1,58
1 module GraderScript
1 module GraderScript
2
2
3 def self.grader_control_enabled?
3 def self.grader_control_enabled?
4 if defined? GRADER_ROOT_DIR
4 if defined? GRADER_ROOT_DIR
5 GRADER_ROOT_DIR != ''
5 GRADER_ROOT_DIR != ''
6 else
6 else
7 false
7 false
8 end
8 end
9 end
9 end
10
10
11 def self.raw_dir
11 def self.raw_dir
12 File.join GRADER_ROOT_DIR, "raw"
12 File.join GRADER_ROOT_DIR, "raw"
13 end
13 end
14
14
15 def self.call_grader(params)
15 def self.call_grader(params)
16 if GraderScript.grader_control_enabled?
16 if GraderScript.grader_control_enabled?
17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
18 system(cmd)
18 system(cmd)
19 end
19 end
20 end
20 end
21
21
22 def self.stop_grader(pid)
22 def self.stop_grader(pid)
23 GraderScript.call_grader "stop #{pid}"
23 GraderScript.call_grader "stop #{pid}"
24 end
24 end
25
25
26 def self.stop_graders(pids)
26 def self.stop_graders(pids)
27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
28 GraderScript.call_grader "stop #{pid_str}"
28 GraderScript.call_grader "stop #{pid_str}"
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,188 +1,190
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
47 return filename.slice(i..len)
49 return filename.slice(i..len)
48 end
50 end
49
51
50 def extract(tempfile)
52 def extract(tempfile)
51 testdata_filename = save_testdata_file(tempfile)
53 testdata_filename = save_testdata_file(tempfile)
52 ext = TestdataImporter.long_ext(tempfile.original_filename)
54 ext = TestdataImporter.long_ext(tempfile.original_filename)
53
55
54 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
56 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
55 if File.exists? extract_dir
57 if File.exists? extract_dir
56 backup_count = 0
58 backup_count = 0
57 begin
59 begin
58 backup_count += 1
60 backup_count += 1
59 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
61 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
60 end while File.exists? backup_dirname
62 end while File.exists? backup_dirname
61 File.rename(extract_dir, backup_dirname)
63 File.rename(extract_dir, backup_dirname)
62 end
64 end
63 Dir.mkdir extract_dir
65 Dir.mkdir extract_dir
64
66
65 if ext=='.tar.gz' or ext=='.tgz'
67 if ext=='.tar.gz' or ext=='.tgz'
66 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
68 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
67 elsif ext=='.tar'
69 elsif ext=='.tar'
68 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
70 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
69 elsif ext=='.zip'
71 elsif ext=='.zip'
70 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
72 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
71 else
73 else
72 return nil
74 return nil
73 end
75 end
74
76
75 system(cmd)
77 system(cmd)
76
78
77 files = Dir["#{extract_dir}/**/*1*.in"]
79 files = Dir["#{extract_dir}/**/*1*.in"]
78 return nil if files.length==0
80 return nil if files.length==0
79
81
80 File.delete(testdata_filename)
82 File.delete(testdata_filename)
81
83
82 return File.dirname(files[0])
84 return File.dirname(files[0])
83 end
85 end
84
86
85 def save_testdata_file(tempfile)
87 def save_testdata_file(tempfile)
86 ext = TestdataImporter.long_ext(tempfile.original_filename)
88 ext = TestdataImporter.long_ext(tempfile.original_filename)
87 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
89 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
88
90
89 return nil if tempfile==""
91 return nil if tempfile==""
90
92
91 if tempfile.instance_of?(Tempfile)
93 if tempfile.instance_of?(Tempfile)
92 tempfile.close
94 tempfile.close
93 FileUtils.move(tempfile.path,testdata_filename)
95 FileUtils.move(tempfile.path,testdata_filename)
94 else
96 else
95 File.open(testdata_filename, "wb") do |f|
97 File.open(testdata_filename, "wb") do |f|
96 f.write(tempfile.read)
98 f.write(tempfile.read)
97 end
99 end
98 end
100 end
99
101
100 return testdata_filename
102 return testdata_filename
101 end
103 end
102
104
103 def import_test_pairs(dirname)
105 def import_test_pairs(dirname)
104 test_num = 1
106 test_num = 1
105 while FileTest.exists? "#{dirname}/#{test_num}.in"
107 while FileTest.exists? "#{dirname}/#{test_num}.in"
106 in_filename = "#{dirname}/#{test_num}.in"
108 in_filename = "#{dirname}/#{test_num}.in"
107 sol_filename = "#{dirname}/#{test_num}.sol"
109 sol_filename = "#{dirname}/#{test_num}.sol"
108
110
109 break if not FileTest.exists? sol_filename
111 break if not FileTest.exists? sol_filename
110
112
111 test_pair = TestPair.new(:input => open(in_filename).read,
113 test_pair = TestPair.new(:input => open(in_filename).read,
112 :solution => open(sol_filename).read,
114 :solution => open(sol_filename).read,
113 :problem => @problem)
115 :problem => @problem)
114 break if not test_pair.save
116 break if not test_pair.save
115
117
116 test_num += 1
118 test_num += 1
117 end
119 end
118 return test_num > 1
120 return test_num > 1
119 end
121 end
120
122
121 def import_problem_description(dirname)
123 def import_problem_description(dirname)
122 html_files = Dir["#{dirname}/*.html"]
124 html_files = Dir["#{dirname}/*.html"]
123 markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"]
125 markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"]
124 if (html_files.length != 0) or (markdown_files.length != 0)
126 if (html_files.length != 0) or (markdown_files.length != 0)
125 description = @problem.description || Description.new
127 description = @problem.description || Description.new
126
128
127 if html_files.length != 0
129 if html_files.length != 0
128 filename = html_files[0]
130 filename = html_files[0]
129 description.markdowned = false
131 description.markdowned = false
130 else
132 else
131 filename = markdown_files[0]
133 filename = markdown_files[0]
132 description.markdowned = true
134 description.markdowned = true
133 end
135 end
134
136
135 description.body = open(filename).read
137 description.body = open(filename).read
136 description.save
138 description.save
137 @problem.description = description
139 @problem.description = description
138 @problem.save
140 @problem.save
139 return "\nProblem description imported from #{filename}."
141 return "\nProblem description imported from #{filename}."
140 else
142 else
141 return ''
143 return ''
142 end
144 end
143 end
145 end
144
146
145 def import_problem_pdf(dirname)
147 def import_problem_pdf(dirname)
146 pdf_files = Dir["#{dirname}/*.pdf"]
148 pdf_files = Dir["#{dirname}/*.pdf"]
147 puts "CHECKING... #{dirname}"
149 puts "CHECKING... #{dirname}"
148 if pdf_files.length != 0
150 if pdf_files.length != 0
149 puts "HAS PDF FILE"
151 puts "HAS PDF FILE"
150 filename = pdf_files[0]
152 filename = pdf_files[0]
151
153
152 @problem.save if not @problem.id
154 @problem.save if not @problem.id
153 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
155 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
154 if not FileTest.exists? out_dirname
156 if not FileTest.exists? out_dirname
155 Dir.mkdir out_dirname
157 Dir.mkdir out_dirname
156 end
158 end
157
159
158 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
160 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
159
161
160 if FileTest.exists? out_filename
162 if FileTest.exists? out_filename
161 File.delete out_filename
163 File.delete out_filename
162 end
164 end
163
165
164 File.rename(filename, out_filename)
166 File.rename(filename, out_filename)
165 @problem.description_filename = "#{@problem.name}.pdf"
167 @problem.description_filename = "#{@problem.name}.pdf"
166 @problem.save
168 @problem.save
167 return "\nProblem pdf imported from #{filename}."
169 return "\nProblem pdf imported from #{filename}."
168 else
170 else
169 return ""
171 return ""
170 end
172 end
171 end
173 end
172
174
173 #just set the full score to the total number of test case
175 #just set the full score to the total number of test case
174 #it is not perfect but works on most normal use case
176 #it is not perfect but works on most normal use case
175 def import_full_score(dirname)
177 def import_full_score(dirname)
176 num = 0
178 num = 0
177 loop do
179 loop do
178 num += 1
180 num += 1
179 in_file = Dir["#{dirname}/#{num}*.in"]
181 in_file = Dir["#{dirname}/#{num}*.in"]
180 break if in_file.length == 0
182 break if in_file.length == 0
181 end
183 end
182 full_score = (num - 1) * 10
184 full_score = (num - 1) * 10
183 @problem.full_score = full_score
185 @problem.full_score = full_score
184 @problem.save
186 @problem.save
185 return "\nFull score is set to #{full_score}."
187 return "\nFull score is set to #{full_score}."
186 end
188 end
187
189
188 end
190 end
You need to be logged in to leave comments. Login now