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