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

r522:dd2e569af6cb - - 40 files changed: 205 inserted, 316 deleted

@@ -0,0 +1,11
1 + %h1 Editing user
2 +
3 + = form_tag :action => 'update', :id => @user do
4 + = error_messages_for 'user'
5 + = render partial: "form"
6 + = submit_tag "Edit"
7 +
8 +
9 + = link_to 'Show', :action => 'show', :id => @user
10 + |
11 + = link_to 'Back', :action => 'list'
@@ -0,0 +1,6
1 + class AddMoreToUsers < ActiveRecord::Migration
2 + def change
3 + add_column :users, :enabled, :boolean, default: 1
4 + add_column :users, :remark, :string
5 + end
6 + end
@@ -1,60 +1,63
1 1 source 'https://rubygems.org'
2 2
3 - gem 'rails', '3.2.19'
3 + gem 'rails', '3.2.21'
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 - gem 'sass-rails', '~> 3.2.3'
14 - gem 'coffee-rails', '~> 3.2.1'
13 + gem 'sass-rails', '~> 3.2.6'
14 + gem 'coffee-rails', '~> 3.2.2'
15 15
16 16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
17 17 # gem 'therubyracer', :platforms => :ruby
18 18
19 - gem 'uglifier', '>= 1.0.3'
19 + gem 'uglifier'
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 38 #
39 39
40 + #in-place editor
41 + gem 'best_in_place', '~> 3.0.1'
42 +
40 43 # jquery addition
41 44 gem 'jquery-rails'
42 45 gem 'jquery-ui-sass-rails'
43 46 gem 'jquery-timepicker-addon-rails'
44 47 gem 'jquery-tablesorter'
45 48
46 49 #syntax highlighter
47 50 gem 'rouge'
48 51
49 - gem "haml"
50 - gem "mail"
51 - gem "rdiscount"
52 - gem "test-unit"
53 - gem 'will_paginate', '~> 3.0.0'
52 + gem 'haml'
53 + gem 'mail'
54 + gem 'rdiscount'
55 + gem 'test-unit'
56 + gem 'will_paginate', '~> 3.0.7'
54 57 gem 'dynamic_form'
55 58 gem 'in_place_editing'
56 - gem 'verification', :git => 'git://github.com/sikachu/verification.git'
59 + gem 'verification', :git => 'https://github.com/sikachu/verification.git'
57 60
58 61 group :test, :development do
59 - gem "rspec-rails", "~> 2.0"
62 + gem 'rspec-rails', '~> 2.99.0'
60 63 end
@@ -1,171 +1,175
1 1 GIT
2 - remote: git://github.com/sikachu/verification.git
2 + remote: https://github.com/sikachu/verification.git
3 3 revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
4 4 specs:
5 5 verification (1.0.3)
6 6 actionpack (>= 3.0.0, < 5.0)
7 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.19)
13 - actionpack (= 3.2.19)
12 + actionmailer (3.2.21)
13 + actionpack (= 3.2.21)
14 14 mail (~> 2.5.4)
15 - actionpack (3.2.19)
16 - activemodel (= 3.2.19)
17 - activesupport (= 3.2.19)
15 + actionpack (3.2.21)
16 + activemodel (= 3.2.21)
17 + activesupport (= 3.2.21)
18 18 builder (~> 3.0.0)
19 19 erubis (~> 2.7.0)
20 20 journey (~> 1.0.4)
21 21 rack (~> 1.4.5)
22 22 rack-cache (~> 1.2)
23 23 rack-test (~> 0.6.1)
24 24 sprockets (~> 2.2.1)
25 - activemodel (3.2.19)
26 - activesupport (= 3.2.19)
25 + activemodel (3.2.21)
26 + activesupport (= 3.2.21)
27 27 builder (~> 3.0.0)
28 - activerecord (3.2.19)
29 - activemodel (= 3.2.19)
30 - activesupport (= 3.2.19)
28 + activerecord (3.2.21)
29 + activemodel (= 3.2.21)
30 + activesupport (= 3.2.21)
31 31 arel (~> 3.0.2)
32 32 tzinfo (~> 0.3.29)
33 - activeresource (3.2.19)
34 - activemodel (= 3.2.19)
35 - activesupport (= 3.2.19)
36 - activesupport (3.2.19)
33 + activeresource (3.2.21)
34 + activemodel (= 3.2.21)
35 + activesupport (= 3.2.21)
36 + activesupport (3.2.21)
37 37 i18n (~> 0.6, >= 0.6.4)
38 38 multi_json (~> 1.0)
39 39 arel (3.0.3)
40 + best_in_place (3.0.3)
41 + actionpack (>= 3.2)
42 + railties (>= 3.2)
40 43 builder (3.0.4)
41 44 coffee-rails (3.2.2)
42 45 coffee-script (>= 2.2.0)
43 46 railties (~> 3.2.0)
44 47 coffee-script (2.3.0)
45 48 coffee-script-source
46 49 execjs
47 - coffee-script-source (1.7.1)
50 + coffee-script-source (1.9.0)
48 51 diff-lcs (1.2.5)
49 52 dynamic_form (1.1.4)
50 53 erubis (2.7.0)
51 - execjs (2.2.1)
52 - haml (4.0.5)
54 + execjs (2.3.0)
55 + haml (4.0.6)
53 56 tilt
54 57 hike (1.2.3)
55 - i18n (0.6.11)
58 + i18n (0.7.0)
56 59 in_place_editing (1.2.0)
57 60 journey (1.0.4)
58 - jquery-rails (3.1.1)
61 + jquery-rails (3.1.2)
59 62 railties (>= 3.0, < 5.0)
60 63 thor (>= 0.14, < 2.0)
61 - jquery-tablesorter (1.12.7)
64 + jquery-tablesorter (1.13.4)
62 65 railties (>= 3.1, < 5)
63 66 jquery-timepicker-addon-rails (1.4.1)
64 67 railties (>= 3.1)
65 68 jquery-ui-rails (4.0.3)
66 69 jquery-rails
67 70 railties (>= 3.1.0)
68 71 jquery-ui-sass-rails (4.0.3.0)
69 72 jquery-rails
70 73 jquery-ui-rails (= 4.0.3)
71 74 railties (>= 3.1.0)
72 - json (1.8.1)
75 + json (1.8.2)
73 76 mail (2.5.4)
74 77 mime-types (~> 1.16)
75 78 treetop (~> 1.4.8)
76 79 mime-types (1.25.1)
77 80 multi_json (1.10.1)
78 - mysql2 (0.3.16)
81 + mysql2 (0.3.17)
79 82 polyglot (0.3.5)
80 - power_assert (0.1.3)
83 + power_assert (0.2.2)
81 84 prototype-rails (3.2.1)
82 85 rails (~> 3.2)
83 86 rack (1.4.5)
84 87 rack-cache (1.2)
85 88 rack (>= 0.4)
86 89 rack-ssl (1.3.4)
87 90 rack
88 - rack-test (0.6.2)
91 + rack-test (0.6.3)
89 92 rack (>= 1.0)
90 - rails (3.2.19)
91 - actionmailer (= 3.2.19)
92 - actionpack (= 3.2.19)
93 - activerecord (= 3.2.19)
94 - activeresource (= 3.2.19)
95 - activesupport (= 3.2.19)
93 + rails (3.2.21)
94 + actionmailer (= 3.2.21)
95 + actionpack (= 3.2.21)
96 + activerecord (= 3.2.21)
97 + activeresource (= 3.2.21)
98 + activesupport (= 3.2.21)
96 99 bundler (~> 1.0)
97 - railties (= 3.2.19)
98 - railties (3.2.19)
99 - actionpack (= 3.2.19)
100 - activesupport (= 3.2.19)
100 + railties (= 3.2.21)
101 + railties (3.2.21)
102 + actionpack (= 3.2.21)
103 + activesupport (= 3.2.21)
101 104 rack-ssl (~> 1.3.2)
102 105 rake (>= 0.8.7)
103 106 rdoc (~> 3.4)
104 107 thor (>= 0.14.6, < 2.0)
105 - rake (10.3.2)
106 - rdiscount (2.1.7.1)
108 + rake (10.4.2)
109 + rdiscount (2.1.8)
107 110 rdoc (3.12.2)
108 111 json (~> 1.4)
109 - rouge (1.6.2)
110 - rspec-collection_matchers (1.0.0)
112 + rouge (1.8.0)
113 + rspec-collection_matchers (1.1.2)
111 114 rspec-expectations (>= 2.99.0.beta1)
112 115 rspec-core (2.99.2)
113 116 rspec-expectations (2.99.2)
114 117 diff-lcs (>= 1.1.3, < 2.0)
115 - rspec-mocks (2.99.2)
118 + rspec-mocks (2.99.3)
116 119 rspec-rails (2.99.0)
117 120 actionpack (>= 3.0)
118 121 activemodel (>= 3.0)
119 122 activesupport (>= 3.0)
120 123 railties (>= 3.0)
121 124 rspec-collection_matchers
122 125 rspec-core (~> 2.99.0)
123 126 rspec-expectations (~> 2.99.0)
124 127 rspec-mocks (~> 2.99.0)
125 - sass (3.4.1)
128 + sass (3.4.11)
126 129 sass-rails (3.2.6)
127 130 railties (~> 3.2.0)
128 131 sass (>= 3.1.10)
129 132 tilt (~> 1.3)
130 - sprockets (2.2.2)
133 + sprockets (2.2.3)
131 134 hike (~> 1.2)
132 135 multi_json (~> 1.0)
133 136 rack (~> 1.0)
134 137 tilt (~> 1.1, != 1.3.0)
135 - test-unit (3.0.1)
138 + test-unit (3.0.9)
136 139 power_assert
137 140 thor (0.19.1)
138 141 tilt (1.4.1)
139 142 treetop (1.4.15)
140 143 polyglot
141 144 polyglot (>= 0.3.1)
142 - tzinfo (0.3.41)
143 - uglifier (2.5.3)
145 + tzinfo (0.3.43)
146 + uglifier (2.7.0)
144 147 execjs (>= 0.3.0)
145 148 json (>= 1.8.0)
146 149 will_paginate (3.0.7)
147 150
148 151 PLATFORMS
149 152 ruby
150 153
151 154 DEPENDENCIES
152 - coffee-rails (~> 3.2.1)
155 + best_in_place (~> 3.0.1)
156 + coffee-rails (~> 3.2.2)
153 157 dynamic_form
154 158 haml
155 159 in_place_editing
156 160 jquery-rails
157 161 jquery-tablesorter
158 162 jquery-timepicker-addon-rails
159 163 jquery-ui-sass-rails
160 164 mail
161 165 mysql2
162 166 prototype-rails
163 - rails (= 3.2.19)
167 + rails (= 3.2.21)
164 168 rdiscount
165 169 rouge
166 - rspec-rails (~> 2.0)
167 - sass-rails (~> 3.2.3)
170 + rspec-rails (~> 2.99.0)
171 + sass-rails (~> 3.2.6)
168 172 test-unit
169 - uglifier (>= 1.0.3)
173 + uglifier
170 174 verification!
171 - will_paginate (~> 3.0.0)
175 + will_paginate (~> 3.0.7)
@@ -1,182 +1,10
1 - == Welcome to Rails
2 -
3 - Rails is a web-application and persistence framework that includes everything
4 - needed to create database-backed web-applications according to the
5 - Model-View-Control pattern of separation. This pattern splits the view (also
6 - called the presentation) into "dumb" templates that are primarily responsible
7 - for inserting pre-built data in between HTML tags. The model contains the
8 - "smart" domain objects (such as Account, Product, Person, Post) that holds all
9 - the business logic and knows how to persist themselves to a database. The
10 - controller handles the incoming requests (such as Save New Account, Update
11 - Product, Show Post) by manipulating the model and directing data to the view.
12 -
13 - In Rails, the model is handled by what's called an object-relational mapping
14 - layer entitled Active Record. This layer allows you to present the data from
15 - database rows as objects and embellish these data objects with business logic
16 - methods. You can read more about Active Record in
17 - link:files/vendor/rails/activerecord/README.html.
18 -
19 - The controller and view are handled by the Action Pack, which handles both
20 - layers by its two parts: Action View and Action Controller. These two layers
21 - are bundled in a single package due to their heavy interdependence. This is
22 - unlike the relationship between the Active Record and Action Pack that is much
23 - more separate. Each of these packages can be used independently outside of
24 - Rails. You can read more about Action Pack in
25 - link:files/vendor/rails/actionpack/README.html.
26 -
27 -
28 - == Getting started
29 -
30 - 1. At the command prompt, start a new rails application using the rails command
31 - and your application name. Ex: rails myapp
32 - (If you've downloaded rails in a complete tgz or zip, this step is already done)
33 - 2. Change directory into myapp and start the web server: <tt>script/server</tt> (run with --help for options)
34 - 3. Go to http://localhost:3000/ and get "Welcome aboard: You’re riding the Rails!"
35 - 4. Follow the guidelines to start developing your application
36 -
37 -
38 - == Web Servers
39 -
40 - By default, Rails will try to use Mongrel and lighttpd if they are installed, otherwise
41 - Rails will use the WEBrick, the webserver that ships with Ruby. When you run script/server,
42 - Rails will check if Mongrel exists, then lighttpd and finally fall back to WEBrick. This ensures
43 - that you can always get up and running quickly.
1 + == cafe grader
44 2
45 - Mongrel is a Ruby-based webserver with a C-component (which requires compilation) that is
46 - suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
47 - getting up and running with mongrel is as easy as: <tt>gem install mongrel</tt>.
48 - More info at: http://mongrel.rubyforge.org
49 -
50 - If Mongrel is not installed, Rails will look for lighttpd. It's considerably faster than
51 - Mongrel and WEBrick and also suited for production use, but requires additional
52 - installation and currently only works well on OS X/Unix (Windows users are encouraged
53 - to start with Mongrel). We recommend version 1.4.11 and higher. You can download it from
54 - http://www.lighttpd.net.
55 -
56 - And finally, if neither Mongrel or lighttpd are installed, Rails will use the built-in Ruby
57 - web server, WEBrick. WEBrick is a small Ruby web server suitable for development, but not
58 - for production.
59 -
60 - But of course its also possible to run Rails on any platform that supports FCGI.
61 - Apache, LiteSpeed, IIS are just a few. For more information on FCGI,
62 - please visit: http://wiki.rubyonrails.com/rails/pages/FastCGI
63 -
64 -
65 - == Debugging Rails
66 -
67 - Have "tail -f" commands running on the server.log and development.log. Rails will
68 - automatically display debugging and runtime information to these files. Debugging
69 - info will also be shown in the browser on requests from 127.0.0.1.
70 -
71 -
72 - == Breakpoints
73 -
74 - Breakpoint support is available through the script/breakpointer client. This
75 - means that you can break out of execution at any point in the code, investigate
76 - and change the model, AND then resume execution! Example:
77 -
78 - class WeblogController < ActionController::Base
79 - def index
80 - @posts = Post.find(:all)
81 - breakpoint "Breaking out from the list"
82 - end
83 - end
84 -
85 - So the controller will accept the action, run the first line, then present you
86 - with a IRB prompt in the breakpointer window. Here you can do things like:
87 -
88 - Executing breakpoint "Breaking out from the list" at .../webrick_server.rb:16 in 'breakpoint'
3 + cafe grader is a programming contest platform used in Thailand IOI training.
4 + The package includes 2 repositories, jittat/cafe-grader-web and jittat/cafe-grader-judge-scripts.
89 5
90 - >> @posts.inspect
91 - => "[#<Post:0x14a6be8 @attributes={\"title\"=>nil, \"body\"=>nil, \"id\"=>\"1\"}>,
92 - #<Post:0x14a6620 @attributes={\"title\"=>\"Rails you know!\", \"body\"=>\"Only ten..\", \"id\"=>\"2\"}>]"
93 - >> @posts.first.title = "hello from a breakpoint"
94 - => "hello from a breakpoint"
95 -
96 - ...and even better is that you can examine how your runtime objects actually work:
97 -
98 - >> f = @posts.first
99 - => #<Post:0x13630c4 @attributes={"title"=>nil, "body"=>nil, "id"=>"1"}>
100 - >> f.
101 - Display all 152 possibilities? (y or n)
102 -
103 - Finally, when you're ready to resume execution, you press CTRL-D
104 -
105 -
106 - == Console
107 -
108 - You can interact with the domain model by starting the console through <tt>script/console</tt>.
109 - Here you'll have all parts of the application configured, just like it is when the
110 - application is running. You can inspect domain models, change values, and save to the
111 - database. Starting the script without arguments will launch it in the development environment.
112 - Passing an argument will specify a different environment, like <tt>script/console production</tt>.
113 -
114 - To reload your controllers and models after launching the console run <tt>reload!</tt>
115 -
116 - To reload your controllers and models after launching the console run <tt>reload!</tt>
117 -
118 -
119 -
120 - == Description of contents
121 -
122 - app
123 - Holds all the code that's specific to this particular application.
124 -
125 - app/controllers
126 - Holds controllers that should be named like weblogs_controller.rb for
127 - automated URL mapping. All controllers should descend from ApplicationController
128 - which itself descends from ActionController::Base.
129 -
130 - app/models
131 - Holds models that should be named like post.rb.
132 - Most models will descend from ActiveRecord::Base.
6 + === Installation
133 7
134 - app/views
135 - Holds the template files for the view that should be named like
136 - weblogs/index.rhtml for the WeblogsController#index action. All views use eRuby
137 - syntax.
138 -
139 - app/views/layouts
140 - Holds the template files for layouts to be used with views. This models the common
141 - header/footer method of wrapping views. In your views, define a layout using the
142 - <tt>layout :default</tt> and create a file named default.rhtml. Inside default.rhtml,
143 - call <% yield %> to render the view using this layout.
144 -
145 - app/helpers
146 - Holds view helpers that should be named like weblogs_helper.rb. These are generated
147 - for you automatically when using script/generate for controllers. Helpers can be used to
148 - wrap functionality for your views into methods.
149 -
150 - config
151 - Configuration files for the Rails environment, the routing map, the database, and other dependencies.
152 -
153 - components
154 - Self-contained mini-applications that can bundle together controllers, models, and views.
8 + The system is tested on ubuntu 14.04 LTS. Use the installation script in
9 + cafe-grader-judge-scripts/installer/install.sh . See http://theory.cpe.ku.ac.th/wiki/index.php/%E0%B8%81%E0%B8%B2%E0%B8%A3%E0%B8%95%E0%B8%B4%E0%B8%94%E0%B8%95%E0%B8%B1%E0%B9%89%E0%B8%87_Cafe_grader for the detail.
155 10
156 - db
157 - Contains the database schema in schema.rb. db/migrate contains all
158 - the sequence of Migrations for your schema.
159 -
160 - doc
161 - This directory is where your application documentation will be stored when generated
162 - using <tt>rake doc:app</tt>
163 -
164 - lib
165 - Application specific libraries. Basically, any kind of custom code that doesn't
166 - belong under controllers, models, or helpers. This directory is in the load path.
167 -
168 - public
169 - The directory available for the web server. Contains subdirectories for images, stylesheets,
170 - and javascripts. Also contains the dispatchers and the default HTML files. This should be
171 - set as the DOCUMENT_ROOT of your web server.
172 -
173 - script
174 - Helper scripts for automation and generation.
175 -
176 - test
177 - Unit and functional tests along with fixtures. When using the script/generate scripts, template
178 - test files will be generated for you and placed in this directory.
179 -
180 - vendor
181 - External libraries that the application depends on. Also includes the plugins subdirectory.
182 - This directory is in the load path.
@@ -1,7 +1,14
1 1 //= require jquery
2 2 //= require jquery_ujs
3 3 //= require jquery.ui.all
4 4 //= require jquery.ui.datepicker
5 5 //= require jquery.ui.slider
6 6 //= require jquery-ui-timepicker-addon
7 7 //= require jquery-tablesorter
8 + //= require best_in_place
9 + //= require best_in_place.jquery-ui
10 +
11 + $(document).ready(function() {
12 + /* Activating Best In Place */
13 + jQuery(".best_in_place").best_in_place();
14 + });
@@ -1,20 +1,28
1 1 class ConfigurationsController < ApplicationController
2 2
3 3 before_filter :authenticate
4 4 before_filter { |controller| controller.authorization_by_roles(['admin'])}
5 5
6 - in_place_edit_for :grader_configuration, :key
7 - in_place_edit_for :grader_configuration, :type
8 - in_place_edit_for :grader_configuration, :value
9 6
10 7 def index
11 8 @configurations = GraderConfiguration.find(:all,
12 9 :order => '`key`')
13 10 end
14 11
15 12 def reload
16 13 GraderConfiguration.reload
17 14 redirect_to :action => 'index'
18 15 end
19 16
17 + def update
18 + @config = GraderConfiguration.find(params[:id])
19 + respond_to do |format|
20 + if @config.update_attributes(params[:grader_configuration])
21 + format.json { head :ok }
22 + else
23 + format.json { respond_with_bip(@config) }
24 + end
25 + end
26 + end
27 +
20 28 end
@@ -1,50 +1,50
1 1 class ContestManagementController < ApplicationController
2 2
3 3 before_filter :admin_authorization
4 4
5 5 def index
6 6 @num_contests = Contest.count()
7 7 end
8 8
9 9 def user_stat
10 10 if not GraderConfiguration.indv_contest_mode?
11 11 redirect_to :action => 'index' and return
12 12 end
13 13
14 14 @users = User.find(:all)
15 15 @start_times = {}
16 16 UserContestStat.find(:all).each do |stat|
17 17 @start_times[stat.user_id] = stat.started_at
18 18 end
19 19 end
20 20
21 21 def clear_stat
22 22 user = User.find(params[:id])
23 23 if user.contest_stat!=nil
24 24 user.contest_stat.destroy
25 25 end
26 26 redirect_to :action => 'user_stat'
27 27 end
28 28
29 29 def clear_all_stat
30 30 if not GraderConfiguration.indv_contest_mode?
31 31 redirect_to :action => 'index' and return
32 32 end
33 33
34 34 UserContestStat.delete_all()
35 35 flash[:notice] = 'All start time statistic cleared.'
36 36 redirect_to :action => 'index'
37 37 end
38 38
39 39 def change_contest_mode
40 - if ['standard', 'contest', 'indv-contest'].include? params[:id]
40 + if ['standard', 'contest', 'indv-contest', 'analysis'].include? params[:id]
41 41 config = GraderConfiguration.find_by_key('system.mode')
42 42 config.value = params[:id]
43 43 config.save
44 44 else
45 45 flash[:notice] = 'Wrong contest mode value'
46 46 end
47 47 redirect_to :action => 'index'
48 48 end
49 49
50 50 end
@@ -26,97 +26,97
26 26 # assigned action login as a default action.
27 27 def index
28 28 redirect_to :action => 'login'
29 29 end
30 30
31 31 def login
32 32 saved_notice = flash[:notice]
33 33 reset_session
34 34 flash.now[:notice] = saved_notice
35 35
36 36 # EXPERIMENT:
37 37 # Hide login if in single user mode and the url does not
38 38 # explicitly specify /login
39 39 #
40 40 # logger.info "PATH: #{request.path}"
41 41 # if GraderConfiguration['system.single_user_mode'] and
42 42 # request.path!='/main/login'
43 43 # @hidelogin = true
44 44 # end
45 45
46 46 @announcements = Announcement.find_for_frontpage
47 47 render :action => 'login', :layout => 'empty'
48 48 end
49 49
50 50 def list
51 51 prepare_list_information
52 52 end
53 53
54 54 def help
55 55 @user = User.find(session[:user_id])
56 56 end
57 57
58 58 def submit
59 59 user = User.find(session[:user_id])
60 60
61 61 @submission = Submission.new
62 62 @submission.problem_id = params[:submission][:problem_id]
63 63 @submission.user = user
64 64 @submission.language_id = 0
65 65 if (params['file']) and (params['file']!='')
66 66 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
67 67 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
68 68 @submission.source_filename = params['file'].original_filename
69 69 end
70 70 @submission.submitted_at = Time.new.gmtime
71 71 @submission.ip_address = request.remote_ip
72 72
73 73 if GraderConfiguration.time_limit_mode? and user.contest_finished?
74 - @submission.errors.add_to_base "The contest is over."
74 + @submission.errors.add(:base,"The contest is over.")
75 75 prepare_list_information
76 76 render :action => 'list' and return
77 77 end
78 78
79 79 if @submission.valid?
80 80 if @submission.save == false
81 81 flash[:notice] = 'Error saving your submission'
82 82 elsif Task.create(:submission_id => @submission.id,
83 83 :status => Task::STATUS_INQUEUE) == false
84 84 flash[:notice] = 'Error adding your submission to task queue'
85 85 end
86 86 else
87 87 prepare_list_information
88 88 render :action => 'list' and return
89 89 end
90 90 redirect_to :action => 'list'
91 91 end
92 92
93 93 def source
94 94 submission = Submission.find(params[:id])
95 95 if ((submission.user_id == session[:user_id]) and
96 96 (submission.problem != nil) and
97 97 (submission.problem.available))
98 98 send_data(submission.source,
99 99 {:filename => submission.download_filename,
100 100 :type => 'text/plain'})
101 101 else
102 102 flash[:notice] = 'Error viewing source'
103 103 redirect_to :action => 'list'
104 104 end
105 105 end
106 106
107 107 def compiler_msg
108 108 @submission = Submission.find(params[:id])
109 109 if @submission.user_id == session[:user_id]
110 110 render :action => 'compiler_msg', :layout => 'empty'
111 111 else
112 112 flash[:notice] = 'Error viewing source'
113 113 redirect_to :action => 'list'
114 114 end
115 115 end
116 116
117 117 def submission
118 118 @user = User.find(session[:user_id])
119 119 @problems = @user.available_problems
120 120 if params[:id]==nil
121 121 @problem = nil
122 122 @submissions = nil
@@ -149,97 +149,97
149 149 redirect_to :action => 'list' and return
150 150 end
151 151 @user = User.find(session[:user_id])
152 152 @submission = Submission.find(params[:id])
153 153 if @submission.user!=@user
154 154 flash[:notice] = 'You are not allowed to view result of other users.'
155 155 redirect_to :action => 'list' and return
156 156 end
157 157 case_num = params[:num].to_i
158 158 out_filename = output_filename(@user.login,
159 159 @submission.problem.name,
160 160 @submission.id,
161 161 case_num)
162 162 if !FileTest.exists?(out_filename)
163 163 flash[:notice] = 'Output not found.'
164 164 redirect_to :action => 'list' and return
165 165 end
166 166
167 167 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
168 168 response.headers['Content-Type'] = "application/force-download"
169 169 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
170 170 response.headers["X-Sendfile"] = out_filename
171 171 response.headers['Content-length'] = File.size(out_filename)
172 172 render :nothing => true
173 173 else
174 174 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
175 175 end
176 176 end
177 177
178 178 def error
179 179 @user = User.find(session[:user_id])
180 180 end
181 181
182 182 # announcement refreshing and hiding methods
183 183
184 184 def announcements
185 185 if params.has_key? 'recent'
186 186 prepare_announcements(params[:recent])
187 187 else
188 188 prepare_announcements
189 189 end
190 190 render(:partial => 'announcement',
191 191 :collection => @announcements,
192 192 :locals => {:announcement_effect => true})
193 193 end
194 194
195 195 def confirm_contest_start
196 196 user = User.find(session[:user_id])
197 - if request.method == :post
197 + if request.method == 'POST'
198 198 user.update_start_time
199 199 redirect_to :action => 'list'
200 200 else
201 201 @contests = user.contests
202 202 @user = user
203 203 end
204 204 end
205 205
206 206 protected
207 207
208 208 def prepare_announcements(recent=nil)
209 209 if GraderConfiguration.show_tasks_to?(@user)
210 210 @announcements = Announcement.find_published(true)
211 211 else
212 212 @announcements = Announcement.find_published
213 213 end
214 214 if recent!=nil
215 215 recent_id = recent.to_i
216 216 @announcements = @announcements.find_all { |a| a.id > recent_id }
217 217 end
218 218 end
219 219
220 220 def prepare_list_information
221 221 @user = User.find(session[:user_id])
222 222 if not GraderConfiguration.multicontests?
223 223 @problems = @user.available_problems
224 224 else
225 225 @contest_problems = @user.available_problems_group_by_contests
226 226 @problems = @user.available_problems
227 227 end
228 228 @prob_submissions = {}
229 229 @problems.each do |p|
230 230 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
231 231 if sub!=nil
232 232 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
233 233 else
234 234 @prob_submissions[p.id] = { :count => 0, :submission => nil }
235 235 end
236 236 end
237 237 prepare_announcements
238 238 end
239 239
240 240 def check_viewability
241 241 @user = User.find(session[:user_id])
242 242 if (!GraderConfiguration.show_tasks_to?(@user)) and
243 243 ((action_name=='submission') or (action_name=='submit'))
244 244 redirect_to :action => 'list' and return
245 245 end
@@ -1,85 +1,86
1 1 class MessagesController < ApplicationController
2 2
3 3 before_filter :authenticate
4 4
5 5 verify :method => :post, :only => ['create'],
6 6 :redirect_to => { :action => 'list' }
7 7
8 8 before_filter :admin_authorization, :only => ['console','show',
9 9 'reply','hide','list_all']
10 10
11 11 def list
12 12 @user = User.find(session[:user_id])
13 13 @messages = Message.find_all_sent_by_user(@user)
14 14 end
15 15
16 16 def console
17 17 @user = User.find(session[:user_id])
18 18 @messages = Message.find_all_system_unreplied_messages
19 19 end
20 20
21 21 def show
22 22 @message = Message.find(params[:id])
23 23 end
24 24
25 25 def list_all
26 26 @user = User.find(session[:user_id])
27 27 @messages = Message.where(receiver_id: nil).order(:created_at)
28 28 end
29 29
30 30 def create
31 31 user = User.find(session[:user_id])
32 32 @message = Message.new(params[:message])
33 33 @message.sender = user
34 - if !@message.save
35 - render :action => 'list' and return
34 + if @message.body == '' or !@message.save
35 + flash[:notice] = 'An error occurred'
36 36 else
37 37 flash[:notice] = 'New message posted'
38 - redirect_to :action => 'list'
39 38 end
39 + redirect_to :action => 'list'
40 40 end
41 41
42 42 def reply
43 43 user = User.find(session[:user_id])
44 44 @message = Message.new(params[:r_message])
45 45 @message.sender = user
46 - if !@message.save
47 - render :action => 'show' and return
46 + if @message.body == '' or !@message.save
47 + flash[:notice] = 'An error occurred'
48 + redirect_to :action => 'show', :id => @message.replying_message_id
48 49 else
49 50 flash[:notice] = 'Message replied'
50 51 rep_msg = @message.replying_message
51 52 rep_msg.replied = true
52 53 rep_msg.save
53 54 redirect_to :action => 'console'
54 55 end
55 56 end
56 57
57 58 def hide
58 59 message = Message.find(params[:id])
59 60 message.replied = true
60 61 message.save
61 - flash[:notice] = 'Message hided (just marked replied)'
62 + flash[:notice] = 'Message hidden (just marked replied)'
62 63 redirect_to :action => 'console'
63 64 end
64 65
65 66 protected
66 67 def build_replying_message_hierarchy(user)
67 68 @all_messages = {}
68 69
69 70
70 71 # manually build replies hierarchy (to improve efficiency)
71 72 [@messages, @replied_messages].each do |collection|
72 73 collection.each do |m|
73 74 @all_messages[m.id] = {:msg => m, :replies => []}
74 75 end
75 76 end
76 77
77 78 @all_messages.each do |m|
78 79 rep_id = m.replying_message_id
79 80 if @all_messages[rep_id]!=nil
80 81 @all_messages[rep_id][:replies] << m
81 82 end
82 83 end
83 84 end
84 85
85 86 end
@@ -1,51 +1,51
1 1 class ReportController < ApplicationController
2 2
3 - before_filter :admin_authorization, only: [:login_stat,:submission_stat]
3 + before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck]
4 4 before_filter(only: [:problem_hof]) { |c|
5 5 return false unless authenticate
6 6
7 7 if GraderConfiguration["right.user_view_submission"]
8 8 return true;
9 9 end
10 10
11 11 admin_authorization
12 12 }
13 13
14 14 def login_stat
15 15 @logins = Array.new
16 16
17 17 date_and_time = '%Y-%m-%d %H:%M'
18 18 begin
19 19 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
20 20 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
21 21 rescue
22 22 @since_time = DateTime.new(1000,1,1)
23 23 end
24 24 begin
25 25 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
26 26 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
27 27 rescue
28 28 @until_time = DateTime.new(3000,1,1)
29 29 end
30 30
31 31 User.all.each do |user|
32 32 @logins << { id: user.id,
33 33 login: user.login,
34 34 full_name: user.full_name,
35 35 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 36 user.id,@since_time,@until_time)
37 37 .count(:id),
38 38 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 39 user.id,@since_time,@until_time)
40 40 .minimum(:created_at),
41 41 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
42 42 user.id,@since_time,@until_time)
43 43 .maximum(:created_at),
44 44 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
45 45 user.id,@since_time,@until_time)
46 46 .select(:ip_address).uniq
47 47
48 48 }
49 49 end
50 50 end
51 51
@@ -73,175 +73,176
73 73 if @submissions[s.user_id]
74 74 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
75 75 a = nil
76 76 begin
77 77 a = Problem.find(s.problem_id)
78 78 rescue
79 79 a = nil
80 80 end
81 81 @submissions[s.user_id][:sub][s.problem_id] =
82 82 { prob_name: (a ? a.full_name : '(NULL)'),
83 83 sub_ids: [s.id] }
84 84 else
85 85 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
86 86 end
87 87 @submissions[s.user_id][:count] += 1
88 88 end
89 89 end
90 90 end
91 91
92 92 def problem_hof
93 93 # gen problem list
94 94 @user = User.find(session[:user_id])
95 95 @problems = @user.available_problems
96 96
97 97 # get selected problems or the default
98 98 if params[:id]
99 99 begin
100 100 @problem = Problem.available.find(params[:id])
101 101 rescue
102 102 redirect_to action: :problem_hof
103 103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
104 104 return
105 105 end
106 106 end
107 107
108 108 return unless @problem
109 109
110 110 @by_lang = {} #aggregrate by language
111 111
112 112 range =65
113 113 @histogram = { data: Array.new(range,0), summary: {} }
114 114 @summary = {count: 0, solve: 0, attempt: 0}
115 115 user = Hash.new(0)
116 116 Submission.where(problem_id: @problem.id).find_each do |sub|
117 117 #histogram
118 118 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
119 119 @histogram[:data][d.to_i] += 1 if d < range
120 120
121 + next unless sub.points
121 122 @summary[:count] += 1
122 123 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
123 124
124 125 lang = Language.find_by_id(sub.language_id)
125 126 next unless lang
126 127 next unless sub.points >= @problem.full_score
127 128
128 129 #initialize
129 130 unless @by_lang.has_key?(lang.pretty_name)
130 131 @by_lang[lang.pretty_name] = {
131 132 runtime: { avail: false, value: 2**30-1 },
132 133 memory: { avail: false, value: 2**30-1 },
133 134 length: { avail: false, value: 2**30-1 },
134 135 first: { avail: false, value: DateTime.new(3000,1,1) }
135 136 }
136 137 end
137 138
138 139 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
139 140 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
140 141 end
141 142
142 143 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
143 144 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
144 145 end
145 146
146 147 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
147 148 !sub.user.admin?
148 149 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
149 150 end
150 151
151 152 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
152 153 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
153 154 end
154 155 end
155 156
156 157 #process user_id
157 158 @by_lang.each do |lang,prop|
158 159 prop.each do |k,v|
159 160 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
160 161 end
161 162 end
162 163
163 164 #sum into best
164 165 if @by_lang and @by_lang.first
165 166 @best = @by_lang.first[1].clone
166 167 @by_lang.each do |lang,prop|
167 168 if @best[:runtime][:value] >= prop[:runtime][:value]
168 169 @best[:runtime] = prop[:runtime]
169 170 @best[:runtime][:lang] = lang
170 171 end
171 172 if @best[:memory][:value] >= prop[:memory][:value]
172 173 @best[:memory] = prop[:memory]
173 174 @best[:memory][:lang] = lang
174 175 end
175 176 if @best[:length][:value] >= prop[:length][:value]
176 177 @best[:length] = prop[:length]
177 178 @best[:length][:lang] = lang
178 179 end
179 180 if @best[:first][:value] >= prop[:first][:value]
180 181 @best[:first] = prop[:first]
181 182 @best[:first][:lang] = lang
182 183 end
183 184 end
184 185 end
185 186
186 187 @histogram[:summary][:max] = [@histogram[:data].max,1].max
187 188 @summary[:attempt] = user.count
188 189 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
189 190 end
190 191
191 192 def stuck #report struggling user,problem
192 193 # init
193 194 user,problem = nil
194 195 solve = true
195 196 tries = 0
196 197 @struggle = Array.new
197 198 record = {}
198 199 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
199 - next unless sub.user and sub.problem
200 + next unless sub.problem and sub.user
200 201 if user != sub.user_id or problem != sub.problem_id
201 202 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
202 203 record = {user: sub.user, problem: sub.problem}
203 204 user,problem = sub.user_id, sub.problem_id
204 205 solve = false
205 206 tries = 0
206 207 end
207 208 if sub.points >= sub.problem.full_score
208 209 solve = true
209 210 else
210 211 tries += 1
211 212 end
212 213 end
213 214 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
214 215 @struggle = @struggle[0..50]
215 216 end
216 217
217 218
218 219 def multiple_login
219 220 #user with multiple IP
220 221 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
221 222 last,count = 0,0
222 223 first = 0
223 224 @users = []
224 225 raw.each do |r|
225 226 if last != r.user.login
226 227 count = 1
227 228 last = r.user.login
228 229 first = r
229 230 else
230 231 @users << first if count == 1
231 232 @users << r
232 233 count += 1
233 234 end
234 235 end
235 236
236 237 #IP with multiple user
237 238 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
238 239 last,count = 0,0
239 240 first = 0
240 241 @ip = []
241 242 raw.each do |r|
242 243 if last != r.ip_address
243 244 count = 1
244 245 last = r.ip_address
245 246 first = r
246 247 else
247 248 @ip << first if count == 1
@@ -1,77 +1,77
1 1 class TestController < ApplicationController
2 2
3 3 before_filter :authenticate, :check_viewability
4 4
5 5 #
6 6 # COMMENT OUT: filter in each action instead
7 7 #
8 8 # before_filter :verify_time_limit, :only => [:submit]
9 9
10 10 verify :method => :post, :only => [:submit],
11 11 :redirect_to => { :action => :index }
12 12
13 13 def index
14 14 prepare_index_information
15 15 end
16 16
17 17 def submit
18 18 @user = User.find(session[:user_id])
19 19
20 20 @submitted_test_request = TestRequest.new_from_form_params(@user,params[:test_request])
21 21
22 22 if ! @submitted_test_request.errors.empty?
23 23 prepare_index_information
24 24 render :action => 'index' and return
25 25 end
26 26
27 27 if GraderConfiguration.time_limit_mode?
28 28 if @user.contest_finished?
29 - @submitted_test_request.errors.add_to_base('Contest is over.')
29 + @submitted_test_request.errors.add(:base,'Contest is over.')
30 30 prepare_index_information
31 31 render :action => 'index' and return
32 32 end
33 33
34 34 if !GraderConfiguration.allow_test_request(@user)
35 35 prepare_index_information
36 36 flash[:notice] = 'Test request is not allowed during the last 30 minutes'
37 37 redirect_to :action => 'index' and return
38 38 end
39 39 end
40 40
41 41 if @submitted_test_request.save
42 42 redirect_to :action => 'index'
43 43 else
44 44 prepare_index_information
45 45 render :action => 'index'
46 46 end
47 47 end
48 48
49 49 def read
50 50 user = User.find(session[:user_id])
51 51 begin
52 52 test_request = TestRequest.find(params[:id])
53 53 rescue
54 54 test_request = nil
55 55 end
56 56 if test_request==nil or test_request.user_id != user.id
57 57 flash[:notice] = 'Invalid output'
58 58 redirect_to :action => 'index'
59 59 return
60 60 end
61 61 if test_request.output_file_name!=nil
62 62 data = File.open(test_request.output_file_name).read(2048)
63 63 if data==nil
64 64 data=""
65 65 end
66 66 send_data(data,
67 67 {:filename => 'output.txt',
68 68 :type => 'text/plain'})
69 69 return
70 70 end
71 71 redirect_to :action => 'index'
72 72 end
73 73
74 74 def result
75 75 @user = User.find(session[:user_id])
76 76 begin
77 77 @test_request = TestRequest.find(params[:id])
@@ -1,201 +1,200
1 1 require 'csv'
2 2
3 3 class UserAdminController < ApplicationController
4 4
5 -
6 5 include MailHelperMethods
7 6
8 7 before_filter :admin_authorization
9 8
10 9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
11 10 verify :method => :post, :only => [ :destroy,
12 11 :create, :create_from_list,
13 12 :update,
14 13 :manage_contest,
15 14 :bulk_mail
16 15 ],
17 16 :redirect_to => { :action => :list }
18 17
19 18 def index
20 19 list
21 20 render :action => 'list'
22 21 end
23 22
24 23 def list
25 24 @user_count = User.count
26 25 if params[:page] == 'all'
27 26 @users = User.all
28 27 @paginated = false
29 28 else
30 29 @users = User.paginate :page => params[:page]
31 30 @paginated = true
32 31 end
33 32 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
34 33 @contests = Contest.enabled
35 34 end
36 35
37 36 def active
38 37 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
39 38 @users = []
40 39 sessions.each do |session|
41 40 if session.data[:user_id]
42 41 @users << User.find(session.data[:user_id])
43 42 end
44 43 end
45 44 end
46 45
47 46 def show
48 47 @user = User.find(params[:id])
49 48 end
50 49
51 50 def new
52 51 @user = User.new
53 52 end
54 53
55 54 def create
56 55 @user = User.new(params[:user])
57 56 @user.activated = true
58 57 if @user.save
59 58 flash[:notice] = 'User was successfully created.'
60 59 redirect_to :action => 'list'
61 60 else
62 61 render :action => 'new'
63 62 end
64 63 end
65 64
66 65 def create_from_list
67 66 lines = params[:user_list]
68 67
69 68 note = []
70 69
71 70 lines.split("\n").each do |line|
72 71 items = line.chomp.split(',')
73 72 if items.length>=2
74 73 login = items[0]
75 74 full_name = items[1]
76 75
77 76 added_random_password = false
78 77 if items.length>=3
79 78 password = items[2].chomp(" ")
80 79 user_alias = (items.length>=4) ? items[3] : login
81 80 else
82 81 password = random_password
83 82 user_alias = (items.length>=4) ? items[3] : login
84 83 added_random_password = true
85 84 end
86 85
87 86 user = User.find_by_login(login)
88 - if user
87 + if (user)
88 + user.full_name = full_name
89 89 user.password = password
90 90 else
91 91 user = User.new({:login => login,
92 92 :full_name => full_name,
93 93 :password => password,
94 94 :password_confirmation => password,
95 95 :alias => user_alias})
96 96 end
97 97 user.activated = true
98 98 user.save
99 99
100 100 if added_random_password
101 101 note << "'#{login}' (+)"
102 102 else
103 103 note << login
104 104 end
105 105 end
106 106 end
107 107 flash[:notice] = 'User(s) ' + note.join(', ') +
108 108 ' were successfully created. ' +
109 109 '( (+) - created with random passwords.)'
110 110 redirect_to :action => 'list'
111 111 end
112 112
113 113 def edit
114 114 @user = User.find(params[:id])
115 115 end
116 116
117 117 def update
118 118 @user = User.find(params[:id])
119 119 if @user.update_attributes(params[:user])
120 120 flash[:notice] = 'User was successfully updated.'
121 121 redirect_to :action => 'show', :id => @user
122 122 else
123 123 render :action => 'edit'
124 124 end
125 125 end
126 126
127 127 def destroy
128 128 User.find(params[:id]).destroy
129 129 redirect_to :action => 'list'
130 130 end
131 131
132 132 def user_stat
133 133 if params[:commit] == 'download csv'
134 134 @problems = Problem.all
135 135 else
136 136 @problems = Problem.find_available_problems
137 137 end
138 138 @users = User.find(:all, :include => [:contests, :contest_stat])
139 139 @scorearray = Array.new
140 140 @users.each do |u|
141 141 ustat = Array.new
142 142 ustat[0] = u
143 143 @problems.each do |p|
144 144 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
145 145 if (sub!=nil) and (sub.points!=nil)
146 146 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
147 147 else
148 148 ustat << [0,false]
149 149 end
150 150 end
151 151 @scorearray << ustat
152 152 end
153 -
154 153 if params[:commit] == 'download csv' then
155 154 csv = gen_csv_from_scorearray(@scorearray,@problems)
156 155 send_data csv, filename: 'last_score.csv'
157 156 else
158 157 render template: 'user_admin/user_stat'
159 158 end
160 159 end
161 160
162 161 def user_stat_max
163 162 if params[:commit] == 'download csv'
164 163 @problems = Problem.all
165 164 else
166 165 @problems = Problem.find_available_problems
167 166 end
168 167 @users = User.find(:all, :include => [:contests, :contest_stat])
169 168 @scorearray = Array.new
170 169 #set up range from param
171 170 since_id = params.fetch(:since_id, 0).to_i
172 171 until_id = params.fetch(:until_id, 0).to_i
173 172 @users.each do |u|
174 173 ustat = Array.new
175 174 ustat[0] = u
176 175 @problems.each do |p|
177 176 max_points = 0
178 177 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
179 178 max_points = sub.points if sub and sub.points and (sub.points > max_points)
180 179 end
181 180 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
182 181 end
183 182 @scorearray << ustat
184 183 end
185 184
186 185 if params[:commit] == 'download csv' then
187 186 csv = gen_csv_from_scorearray(@scorearray,@problems)
188 187 send_data csv, filename: 'max_score.csv'
189 188 else
190 189 render template: 'user_admin/user_stat'
191 190 end
192 191 end
193 192
194 193 def import
195 194 if params[:file]==''
196 195 flash[:notice] = 'Error importing no file'
197 196 redirect_to :action => 'list' and return
198 197 end
199 198 import_from_file(params[:file])
200 199 end
201 200
@@ -18,178 +18,178
18 18
19 19 verify :method => :post, :only => [:chg_passwd],
20 20 :redirect_to => { :action => :index }
21 21
22 22 #in_place_edit_for :user, :alias_for_editing
23 23 #in_place_edit_for :user, :email_for_editing
24 24
25 25 def index
26 26 if !GraderConfiguration['system.user_setting_enabled']
27 27 redirect_to :controller => 'main', :action => 'list'
28 28 else
29 29 @user = User.find(session[:user_id])
30 30 end
31 31 end
32 32
33 33 def chg_passwd
34 34 user = User.find(session[:user_id])
35 35 user.password = params[:passwd]
36 36 user.password_confirmation = params[:passwd_verify]
37 37 if user.save
38 38 flash[:notice] = 'password changed'
39 39 else
40 40 flash[:notice] = 'Error: password changing failed'
41 41 end
42 42 redirect_to :action => 'index'
43 43 end
44 44
45 45 def new
46 46 @user = User.new
47 47 render :action => 'new', :layout => 'empty'
48 48 end
49 49
50 50 def register
51 51 if(params[:cancel])
52 52 redirect_to :controller => 'main', :action => 'login'
53 53 return
54 54 end
55 55 @user = User.new(params[:user])
56 56 @user.password_confirmation = @user.password = User.random_password
57 57 @user.activated = false
58 58 if (@user.valid?) and (@user.save)
59 59 if send_confirmation_email(@user)
60 60 render :action => 'new_splash', :layout => 'empty'
61 61 else
62 62 @admin_email = GraderConfiguration['system.admin_email']
63 63 render :action => 'email_error', :layout => 'empty'
64 64 end
65 65 else
66 - @user.errors.add_to_base("Email cannot be blank") if @user.email==''
66 + @user.errors.add(:base,"Email cannot be blank") if @user.email==''
67 67 render :action => 'new', :layout => 'empty'
68 68 end
69 69 end
70 70
71 71 def confirm
72 72 login = params[:login]
73 73 key = params[:activation]
74 74 @user = User.find_by_login(login)
75 75 if (@user) and (@user.verify_activation_key(key))
76 76 if @user.valid? # check uniquenss of email
77 77 @user.activated = true
78 78 @user.save
79 79 @result = :successful
80 80 else
81 81 @result = :email_used
82 82 end
83 83 else
84 84 @result = :failed
85 85 end
86 86 render :action => 'confirm', :layout => 'empty'
87 87 end
88 88
89 89 def forget
90 90 render :action => 'forget', :layout => 'empty'
91 91 end
92 92
93 93 def retrieve_password
94 94 email = params[:email]
95 95 user = User.find_by_email(email)
96 96 if user
97 97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
98 98 if last_updated_time > Time.now.gmtime - 5.minutes
99 99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
100 100 else
101 101 user.password = user.password_confirmation = User.random_password
102 102 user.save
103 103 send_new_password_email(user)
104 104 flash[:notice] = 'New password has been mailed to you.'
105 105 end
106 106 else
107 107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
108 108 end
109 109 redirect_to :action => 'forget'
110 110 end
111 111
112 112 def profile
113 113 @user = User.find(params[:id])
114 114 @submission = Submission.includes(:problem).where(user_id: params[:id])
115 115
116 116 range = 120
117 117 @histogram = { data: Array.new(range,0), summary: {} }
118 118 @summary = {count: 0, solve: 0, attempt: 0}
119 119 problem = Hash.new(0)
120 120
121 121 @submission.find_each do |sub|
122 122 #histogram
123 123 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
124 124 @histogram[:data][d.to_i] += 1 if d < range
125 125
126 126 @summary[:count] += 1
127 127 next unless sub.problem
128 128 problem[sub.problem] = [problem[sub.problem], (sub.points >= sub.problem.full_score) ? 1 : 0].max
129 129 end
130 130
131 131 @histogram[:summary][:max] = [@histogram[:data].max,1].max
132 132 @summary[:attempt] = problem.count
133 133 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
134 134 end
135 135
136 136 protected
137 137
138 138 def verify_online_registration
139 139 if !GraderConfiguration['system.online_registration']
140 140 redirect_to :controller => 'main', :action => 'login'
141 141 end
142 142 end
143 143
144 144 def send_confirmation_email(user)
145 145 contest_name = GraderConfiguration['contest.name']
146 146 activation_url = url_for(:action => 'confirm',
147 147 :login => user.login,
148 148 :activation => user.activation_key)
149 149 home_url = url_for(:controller => 'main', :action => 'index')
150 150 mail_subject = "[#{contest_name}] Confirmation"
151 151 mail_body = t('registration.email_body', {
152 152 :full_name => user.full_name,
153 153 :contest_name => contest_name,
154 154 :login => user.login,
155 155 :password => user.password,
156 156 :activation_url => activation_url,
157 - :admin_email => admin_email
157 + :admin_email => GraderConfiguration['system.admin_email']
158 158 })
159 159
160 160 logger.info mail_body
161 161
162 162 send_mail(user.email, mail_subject, mail_body)
163 163 end
164 164
165 165 def send_new_password_email(user)
166 166 contest_name = GraderConfiguration['contest.name']
167 167 mail_subject = "[#{contest_name}] Password recovery"
168 168 mail_body = t('registration.password_retrieval.email_body', {
169 169 :full_name => user.full_name,
170 170 :contest_name => contest_name,
171 171 :login => user.login,
172 172 :password => user.password,
173 - :admin_email => admin_email
173 + :admin_email => GraderConfiguration['system.admin_email']
174 174 })
175 175
176 176 logger.info mail_body
177 177
178 178 send_mail(user.email, mail_subject, mail_body)
179 179 end
180 180
181 181 # allow viewing of regular user profile only when options allow so
182 182 # only admins can view admins profile
183 183 def profile_authorization
184 184 #if view admins' profile, allow only admin
185 185 return false unless(params[:id])
186 186 user = User.find(params[:id])
187 187 return false unless user
188 188 return admin_authorization if user.admin?
189 189 return true if GraderConfiguration["right.user_view_submission"]
190 190
191 191 #finally, we allow only admin
192 192 admin_authorization
193 193 end
194 194
195 195 end
@@ -73,66 +73,66
73 73 rescue
74 74 nil
75 75 end
76 76 end
77 77
78 78 def user_title_bar(user)
79 79 header = ''
80 80 time_left = ''
81 81
82 82 #
83 83 # if the contest is over
84 84 if GraderConfiguration.time_limit_mode?
85 85 if user.contest_finished?
86 86 header = <<CONTEST_OVER
87 87 <tr><td colspan="2" align="center">
88 88 <span class="contest-over-msg">THE CONTEST IS OVER</span>
89 89 </td></tr>
90 90 CONTEST_OVER
91 91 end
92 92 if !user.contest_started?
93 93 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
94 94 else
95 95 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
96 96 " #{format_short_duration(user.contest_time_left)}"
97 97 end
98 98 end
99 99
100 100 #
101 101 # if the contest is in the anaysis mode
102 102 if GraderConfiguration.analysis_mode?
103 103 header = <<ANALYSISMODE
104 104 <tr><td colspan="2" align="center">
105 105 <span class="contest-over-msg">ANALYSIS MODE</span>
106 106 </td></tr>
107 107 ANALYSISMODE
108 108 end
109 109
110 110 contest_name = GraderConfiguration['contest.name']
111 111
112 112 #
113 113 # build real title bar
114 114 result = <<TITLEBAR
115 115 <div class="title">
116 116 <table>
117 117 #{header}
118 118 <tr>
119 119 <td class="left-col">
120 120 #{user.full_name}<br/>
121 - #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
121 + #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
122 122 #{time_left}
123 123 <br/>
124 124 </td>
125 125 <td class="right-col">#{contest_name}</td>
126 126 </tr>
127 127 </table>
128 128 </div>
129 129 TITLEBAR
130 130 result.html_safe
131 131 end
132 132
133 133 def markdown(text)
134 134 markdown = RDiscount.new(text)
135 135 markdown.to_html.html_safe
136 136 end
137 137
138 138 end
@@ -1,128 +1,128
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 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 46 import_params[:checker_name],
47 47 import_to_db)
48 - problem.errors.add_to_base('Import error.')
48 + problem.errors.add(:base,'Import error.')
49 49 end
50 50
51 51 return problem, importer.log_msg
52 52 end
53 53
54 54 def self.download_file_basedir
55 55 return "#{Rails.root}/data/tasks"
56 56 end
57 57
58 58 def get_submission_stat
59 59 result = Hash.new
60 60 #total number of submission
61 61 result[:total_sub] = Submission.where(problem_id: self.id).count
62 62 result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
63 63 end
64 64
65 65 protected
66 66
67 67 def self.to_i_or_default(st, default)
68 68 if st!=''
69 69 result = st.to_i
70 70 end
71 71 result ||= default
72 72 end
73 73
74 74 def self.to_f_or_default(st, default)
75 75 if st!=''
76 76 result = st.to_f
77 77 end
78 78 result ||= default
79 79 end
80 80
81 81 def self.extract_params_and_check(params, problem)
82 82 time_limit = Problem.to_f_or_default(params[:time_limit],
83 83 DEFAULT_TIME_LIMIT)
84 84 memory_limit = Problem.to_i_or_default(params[:memory_limit],
85 85 DEFAULT_MEMORY_LIMIT)
86 86
87 87 if time_limit<=0 or time_limit >60
88 - problem.errors.add_to_base('Time limit out of range.')
88 + problem.errors.add(:base,'Time limit out of range.')
89 89 end
90 90
91 91 if memory_limit==0 and params[:memory_limit]!='0'
92 - problem.errors.add_to_base('Memory limit format errors.')
92 + problem.errors.add(:base,'Memory limit format errors.')
93 93 elsif memory_limit<=0 or memory_limit >512
94 - problem.errors.add_to_base('Memory limit out of range.')
94 + problem.errors.add(:base,'Memory limit out of range.')
95 95 end
96 96
97 97 if params[:file]==nil or params[:file]==''
98 - problem.errors.add_to_base('No testdata file.')
98 + problem.errors.add(:base,'No testdata file.')
99 99 end
100 100
101 101 checker_name = 'text'
102 102 if ['text','float'].include? params[:checker]
103 103 checker_name = params[:checker]
104 104 end
105 105
106 106 file = params[:file]
107 107
108 108 if !problem.errors.empty?
109 109 return nil, problem
110 110 end
111 111
112 112 problem.name = params[:name]
113 113 if params[:full_name]!=''
114 114 problem.full_name = params[:full_name]
115 115 else
116 116 problem.full_name = params[:name]
117 117 end
118 118
119 119 return [{
120 120 :time_limit => time_limit,
121 121 :memory_limit => memory_limit,
122 122 :file => file,
123 123 :checker_name => checker_name
124 124 },
125 125 problem]
126 126 end
127 127
128 128 end
@@ -25,102 +25,102
25 25
26 26 validates_presence_of :submission
27 27 validate :must_have_valid_problem
28 28
29 29 def problem_name
30 30 TestRequest.name_of(self.problem)
31 31 end
32 32
33 33 def language
34 34 self.submission.language
35 35 end
36 36
37 37 def self.get_inqueue_and_change_status(status)
38 38 # since there will be only one grader grading TestRequest
39 39 # we do not need locking (hopefully)
40 40
41 41 test_request = TestRequest.find(:first,
42 42 :order => "created_at",
43 43 :conditions => {:status=> Task::STATUS_INQUEUE})
44 44 if test_request!=nil
45 45 test_request.status = status
46 46 test_request.save!
47 47 end
48 48
49 49 test_request
50 50 end
51 51
52 52 # interfacing with form
53 53 def self.new_from_form_params(user,params)
54 54 test_request = TestRequest.new
55 55 test_request.user = user
56 56 begin
57 57 problem = Problem.find(params[:problem_id])
58 58 rescue ActiveRecord::RecordNotFound
59 59 problem = nil
60 60 end
61 61 test_request.problem = problem
62 62 if problem!=nil
63 63 test_request.submission =
64 64 Submission.find_by_user_problem_number(user.id,
65 65 problem.id,
66 66 params[:submission_number])
67 67 else
68 68 test_request.submission = nil
69 69 end
70 70
71 71 # checks if the user submits any input file
72 72 if params[:input_file]==nil or params[:input_file]==""
73 - test_request.errors.add_to_base("No input submitted.")
73 + test_request.errors.add(:base,"No input submitted.")
74 74 test_request.input_file_name = nil
75 75 else
76 76 test_request.input_file_name = save_input_file(params[:input_file], user, problem)
77 77 if test_request.input_file_name == nil
78 - test_request.errors.add_to_base("No input submitted.")
78 + test_request.errors.adds(:base,"No input submitted.")
79 79 end
80 80 if params[:additional_file]!=nil and params[:additional_file]!=""
81 81 save_additional_file(params[:additional_file],
82 82 "#{test_request.input_file_name}.files")
83 83 end
84 84 end
85 85 test_request.submitted_at = Time.new.gmtime
86 86 test_request.status_inqueue
87 87 test_request
88 88 end
89 89
90 90 protected
91 91
92 92 def self.name_of(problem)
93 93 if problem!=nil
94 94 problem.name
95 95 else
96 96 "default"
97 97 end
98 98 end
99 99
100 100 def self.random_input_file_name(user,problem)
101 101 problem_name = TestRequest.name_of(problem)
102 102 begin
103 103 tmpname = TEST_REQUEST_INPUT_FILE_DIR + "/#{user.login}/#{problem_name}/#{rand(10000)}"
104 104 end while File.exists?(tmpname)
105 105 tmpname
106 106 end
107 107
108 108 def self.save_input_file(tempfile, user, problem)
109 109 new_file_name = random_input_file_name(user,problem)
110 110 dirname = File.dirname(new_file_name)
111 111 FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname)
112 112
113 113 # when the user did not submit any file
114 114 return nil if tempfile==""
115 115
116 116 if tempfile.instance_of?(Tempfile)
117 117 tempfile.close
118 118 FileUtils.move(tempfile.path,new_file_name)
119 119 else
120 120 File.open(new_file_name, "wb") do |f|
121 121 f.write(tempfile.read)
122 122 end
123 123 end
124 124 new_file_name
125 125 end
126 126
@@ -22,101 +22,101
22 22
23 23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
24 24
25 25 belongs_to :site
26 26 belongs_to :country
27 27
28 28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
29 29
30 30 scope :activated_users, :conditions => {:activated => true}
31 31
32 32 validates_presence_of :login
33 33 validates_uniqueness_of :login
34 34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
35 35 validates_length_of :login, :within => 3..30
36 36
37 37 validates_presence_of :full_name
38 38 validates_length_of :full_name, :minimum => 1
39 39
40 40 validates_presence_of :password, :if => :password_required?
41 41 validates_length_of :password, :within => 4..20, :if => :password_required?
42 42 validates_confirmation_of :password, :if => :password_required?
43 43
44 44 validates_format_of :email,
45 45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
46 46 :if => :email_validation?
47 47 validate :uniqueness_of_email_from_activated_users,
48 48 :if => :email_validation?
49 49 validate :enough_time_interval_between_same_email_registrations,
50 50 :if => :email_validation?
51 51
52 52 # these are for ytopc
53 53 # disable for now
54 54 #validates_presence_of :province
55 55
56 56 attr_accessor :password
57 57
58 58 before_save :encrypt_new_password
59 59 before_save :assign_default_site
60 60 before_save :assign_default_contest
61 61
62 62 # this is for will_paginate
63 63 cattr_reader :per_page
64 64 @@per_page = 50
65 65
66 66 def self.authenticate(login, password)
67 67 user = find_by_login(login)
68 68 if user
69 69 return user if user.authenticated?(password)
70 - # if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 - # user.password = password
72 - # user.save
73 - # return user
74 - # end
70 + if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 + user.password = password
72 + user.save
73 + return user
74 + end
75 75 end
76 76 end
77 77
78 78 def authenticated?(password)
79 79 if self.activated
80 80 hashed_password == User.encrypt(password,self.salt)
81 81 else
82 82 false
83 83 end
84 84 end
85 85
86 86 def authenticated_by_pop3?(password)
87 87 Net::POP3.enable_ssl
88 88 pop = Net::POP3.new('pops.it.chula.ac.th')
89 89 authen = true
90 90 begin
91 91 pop.start(login, password)
92 92 pop.finish
93 93 return true
94 94 rescue
95 95 return false
96 96 end
97 97 end
98 98
99 99 def authenticated_by_cucas?(password)
100 100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
101 101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
102 102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
103 103 post_args = {
104 104 'appid' => appid,
105 105 'appsecret' => appsecret,
106 106 'username' => login,
107 107 'password' => password
108 108 }
109 109
110 110 #simple call
111 111 begin
112 112 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
113 113 http.use_ssl = true
114 114 result = [ ]
115 115 http.start do |http|
116 116 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
117 117 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
118 118 resp = http.request(req,param)
119 119 result = JSON.parse resp.body
120 120 end
121 121 return true if result["type"] == "beanStudent"
122 122 rescue
@@ -306,71 +306,71
306 306 return problem_in_user_contests? problem
307 307 end
308 308 end
309 309
310 310 protected
311 311 def encrypt_new_password
312 312 return if password.blank?
313 313 self.salt = (10+rand(90)).to_s
314 314 self.hashed_password = User.encrypt(self.password,self.salt)
315 315 end
316 316
317 317 def assign_default_site
318 318 # have to catch error when migrating (because self.site is not available).
319 319 begin
320 320 if self.site==nil
321 321 self.site = Site.find_by_name('default')
322 322 if self.site==nil
323 323 self.site = Site.find(1) # when 'default has be renamed'
324 324 end
325 325 end
326 326 rescue
327 327 end
328 328 end
329 329
330 330 def assign_default_contest
331 331 # have to catch error when migrating (because self.site is not available).
332 332 begin
333 333 if self.contests.length == 0
334 334 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
335 335 if default_contest
336 336 self.contests = [default_contest]
337 337 end
338 338 end
339 339 rescue
340 340 end
341 341 end
342 342
343 343 def password_required?
344 344 self.hashed_password.blank? || !self.password.blank?
345 345 end
346 346
347 347 def self.encrypt(string,salt)
348 348 Digest::SHA1.hexdigest(salt + string)
349 349 end
350 350
351 351 def uniqueness_of_email_from_activated_users
352 352 user = User.activated_users.find_by_email(self.email)
353 353 if user and (user.login != self.login)
354 - self.errors.add_to_base("Email has already been taken")
354 + self.errors.add(:base,"Email has already been taken")
355 355 end
356 356 end
357 357
358 358 def enough_time_interval_between_same_email_registrations
359 359 return if !self.new_record?
360 360 return if self.activated
361 361 open_user = User.find_by_email(self.email,
362 362 :order => 'created_at DESC')
363 363 if open_user and open_user.created_at and
364 364 (open_user.created_at > Time.now.gmtime - 5.minutes)
365 - self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
365 + self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
366 366 end
367 367 end
368 368
369 369 def email_validation?
370 370 begin
371 371 return VALIDATE_USER_EMAILS
372 372 rescue
373 373 return false
374 374 end
375 375 end
376 376 end
@@ -1,29 +1,32
1 + - content_for :header do
2 + = javascript_include_tag 'local_jquery'
3 +
1 4 %h1 System configuration
2 5
3 6 %table.info
4 7 %tr.info-head
5 8 %th Key
6 9 %th Type
7 10 %th Value
8 11 %th Description
9 12 - @configurations.each do |conf|
10 13 - @grader_configuration = conf
11 14 %tr{:class => cycle("info-odd", "info-even")}
12 15 %td
13 16 = in_place_editor_field :grader_configuration, :key, {}, :rows=>1
14 17 %td
15 18 = in_place_editor_field :grader_configuration, :value_type, {}, :rows=>1
16 19 %td
17 - = in_place_editor_field :grader_configuration, :value, {}, :rows=>1
20 + = best_in_place @grader_configuration, :value, ok_button: "ok", cancel_button: "cancel"
18 21 %td= conf.description
19 22
20 23 - if GraderConfiguration.config_cached?
21 24 %br/
22 25 Your config is saved, but it does not automatically take effect.
23 26 %br/
24 27 If you have one mongrel process running, you can
25 28 = link_to '[click]', :action => 'reload'
26 29 here to reload.
27 30 %br/
28 31 If you have more than one process running, you should restart
29 32 them manually.
@@ -1,31 +1,34
1 1 %h1 Contest management
2 2
3 3 .infobox
4 4
5 5 - if @num_contests>1
6 6 %b Multiple contests:
7 7 = "There are #{@num_contests} contests running."
8 8 - else
9 9 %b Single contest:
10 10 =raw "[#{link_to 'Add/remove contests', :controller => 'contests', :action => 'index'}]"
11 11
12 12 .infobox
13 13 %b Web interface mode:
14 - - if (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
15 - standard mode
14 + - if GraderConfiguration.analysis_mode?
15 + Analysis Mode
16 + - elsif (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
17 + Standard Mode
16 18 - elsif GraderConfiguration.contest_mode?
17 - normal contest mode.
19 + Normal Contest Mode
18 20 - else
19 - individual contest mode.
21 + Individual Contest Mode
20 22
21 23 %br/
22 24 Change mode to:
23 - =raw "[#{link_to 'standard', :action => 'change_contest_mode', :id => 'standard'}]"
24 - =raw "[#{link_to 'contest', :action => 'change_contest_mode', :id => 'contest'}]"
25 - =raw "[#{link_to 'individual contest', :action => 'change_contest_mode', :id => 'indv-contest'}]"
25 + =raw "[#{link_to 'Standard', :action => 'change_contest_mode', :id => 'standard'}]"
26 + =raw "[#{link_to 'Contest', :action => 'change_contest_mode', :id => 'contest'}]"
27 + =raw "[#{link_to 'Individual Contest', :action => 'change_contest_mode', :id => 'indv-contest'}]"
28 + =raw "[#{link_to 'Analysis', :action => 'change_contest_mode', :id => 'analysis'}]"
26 29
27 30 - if GraderConfiguration.indv_contest_mode?
28 31 = render :partial => 'indv_contest_mode_index'
29 32
30 33 %br/
31 34
@@ -1,72 +1,73
1 1 - content_for :head do
2 2 = stylesheet_link_tag 'graders'
3 + = javascript_include_tag 'local_jquery'
3 4 <meta http-equiv ="refresh" content="60"/>
4 5
5 6 %h1 Grader information
6 7
7 8 = link_to '[Refresh]', :action => 'list'
8 9 %br/
9 10
10 11 .submitbox
11 12 .item
12 13 Grader control:
13 14 .item
14 15 = form_for :clear, :url => {:action => 'start_grading'} do |f|
15 16 = submit_tag 'Start graders in grading env'
16 17 .item
17 18 = form_for :clear, :url => {:action => 'start_exam'} do |f|
18 19 = submit_tag 'Start graders in exam env'
19 20 .item
20 21 = form_for :clear, :url => {:action => 'stop_all'} do |f|
21 22 = submit_tag 'Stop all running graders'
22 23 .item
23 24 = form_for :clear, :url => {:action => 'clear_all'} do |f|
24 25 = submit_tag 'Clear all data'
25 26 %br{:style => 'clear:both'}/
26 27
27 28 %div{style: 'width:500px; float: left;'}
28 29 - if @last_task
29 30 Last task:
30 31 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
31 32
32 33 %br/
33 34
34 35 - if @last_test_request
35 36 Last test_request:
36 37 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
37 38
38 39 %h2 Current graders
39 40
40 41 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
41 42
42 43 %h2 Stalled graders
43 44
44 45 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
45 46
46 47 %h2 Terminated graders
47 48
48 49 = form_for :clear, :url => {:action => 'clear_terminated'} do |f|
49 50 = submit_tag 'Clear data for terminated graders'
50 51
51 52 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
52 53 %div{}
53 54 %h2 Last 20 submissions
54 55 %table.graders
55 56 %thead
56 57 %th ID
57 58 %th User
58 59 %th Problem
59 60 %th Submitted
60 61 %th Graded
61 62 %th Result
62 63 %tbody
63 64 - @submission.each do |sub|
64 65 %tr.inactive
65 66 %td= link_to sub.id, controller: 'graders' ,action: 'submission', id: sub.id
66 67 %td= sub.try(:user).try(:full_name)
67 68 %td= sub.try(:problem).try(:full_name)
68 69 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
69 - %td= "#{sub.graded_at ? time_ago_in_words(sub.graded_at) : ''} ago"
70 + %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
70 71 %td= sub.grader_comment
71 72
72 73
@@ -1,40 +1,40
1 1 %h1= "Test Request: #{@test_request.id}"
2 2
3 3 %p
4 4 User:
5 5 = "#{@test_request.user.login}"
6 6 %br/
7 7 Problem:
8 8 - if @test_request.problem!=nil
9 9 = "#{@test_request.problem.full_name}"
10 10 - else
11 11 = "(n/a)"
12 12 %br/
13 13 = "Submission: #{@test_request.submission.number}"
14 14 = link_to '[view submission]', :action => 'submission', :id => @test_request.submission.id
15 15 %br/
16 16 = "Test submitted at: #{format_short_time(@test_request.submitted_at)}"
17 17 %br/
18 18 = "Execution time: #{@test_request.running_time} s."
19 19 %br/
20 20 = "Memory usage: #{@test_request.memory_usage}kb"
21 21 %br/
22 22 %b= @test_request.exit_status
23 23 %br/
24 24
25 25 - if @test_request.compiler_message!=nil and @test_request.compiler_message!=''
26 26 %b Compiler Message
27 27 %div{:style => "border: 1px solid black; background: lightgrey"}
28 - = simple_format(truncate((@test_request.compiler_message or ''),200))
28 + = simple_format(truncate((@test_request.compiler_message or ''), :length => 200))
29 29
30 30 %b Input (first 2kb)
31 31 %div{:style => "border: 1px solid black; background: lightgrey"}
32 32 - if @test_request.input_file_name!=nil
33 33 = simple_format(read_textfile(@test_request.input_file_name,2048))
34 34
35 35 %b Output (first 2kb)
36 36 %div{:style => "border: 1px solid black; background: lightgrey"}
37 37 - if @test_request.output_file_name!=nil
38 38 = simple_format(read_textfile(@test_request.output_file_name,2048))
39 39 - else
40 40 (no output)
@@ -1,15 +1,15
1 1
2 - <% if compiler_message==nil or compiler_message=='' %>
2 + <% if compiler_message == nil or compiler_message.chomp == '' %>
3 3 No message
4 4 <% else %>
5 5 <div><div><a href="#" onClick="n = this.parentNode.parentNode.lastChild;
6 6 if(n.style.display == 'none') { n.style.display = 'block'; }
7 7 else {n.style.display ='none'; } return false;">
8 8 (click to see)</a>
9 9 </div>
10 10 <div style="display: none">
11 11 <div class="compilermsgbody" style="border: thin solid grey; margin: 2px">
12 12 <%=simple_format(compiler_message) %>
13 13 </div>
14 14 </div></div>
15 15 <% end %>
@@ -1,20 +1,24
1 1
2 2 %tr{:class => ((submission_counter%2==0) ? "info-even" : "info-odd")}
3 3 %td.info{:align => "center"}
4 4 = submission_counter+1
5 5 %td.info{:align => "center"}
6 6 = link_to "##{submission.id}", controller: :graders, action: :submission, id: submission.id
7 - %td.info= format_short_time(submission.submitted_at)
7 + %td.info
8 + = l submission.submitted_at, format: :long
9 + = "( #{time_ago_in_words(submission.submitted_at)} ago)"
8 10 %td.info{:align => "center"}
11 + = submission.source_filename
12 + = " (#{submission.language.pretty_name}) "
9 13 = link_to('[load]',{:action => 'source', :id => submission.id})
10 14 %td.info
11 15 - if submission.graded_at!=nil
12 16 = "Graded at #{format_short_time(submission.graded_at)}."
13 17 %br/
14 18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
15 19 = " ["
16 20 %tt
17 21 = submission.grader_comment
18 22 = "]"
19 23 %td.info
20 24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
@@ -1,6 +1,6
1 1 %h2= "Compiler message for submission \##{@submission.number}, task: #{@submission.problem.name}"
2 2 %p
3 - - if @submission.compiler_message.chomp == ''
4 - no message
3 + - if @submission.compiler_message == nil or @submission.compiler_message.chomp == ''
4 + No message
5 5 - else
6 6 = simple_format(@submission.compiler_message)
@@ -1,16 +1,16
1 1 = user_title_bar(@user)
2 2
3 3 .announcementbox
4 4 %span{:class => 'title'}
5 5 =t 'main.confirm_contest_start.box_title'
6 6 .announcement
7 7 %center
8 8 =t 'main.confirm_contest_start.contest_list'
9 9 - @contests.each do |contest|
10 10 = contest.title
11 11 %br
12 12
13 13 =t 'main.confirm_contest_start.timer_starts_after_click'
14 14
15 - = form_tag :action => 'confirm_contest_start', :method => 'post' do
15 + = form_tag :action => 'confirm_contest_start' do
16 16 = submit_tag t('main.confirm_contest_start.start_button'), :confirm => t('main.confirm_contest_start.start_button_confirm')
@@ -1,19 +1,18
1 1 - content_for :head do
2 2 = stylesheet_link_tag 'problems'
3 3
4 4 %h1 Import problems: successful
5 5
6 6 %p
7 7 %b Problem:
8 8 = "#{@problem.full_name} (#{@problem.name})"
9 9 %br/
10 - Note that the full score has be assigned to the default value, 100.
11 - You should change it to the correct full score.
10 + = "Note that the full score has been set to #{@problem.full_score}."
12 11
13 12 %p
14 13 = link_to '[Back to problem list]', :action => 'list'
15 14 = link_to '[Import other problems]', :action => 'import'
16 15
17 16 %h3 Import log
18 17 %pre.import-log
19 18 = @log
@@ -1,60 +1,59
1 1 - content_for :header do
2 2 = javascript_include_tag 'local_jquery'
3 3
4 4 :javascript
5 5 $(document).ready( function() {
6 6 $("#mem_remark").hover( function() {
7 7 $("#mem_remark_box").show();
8 8 }, function() {
9 9 $("#mem_remark_box").hide();
10 10 });
11 11 });
12 - alert("hahaha");
13 12 :css
14 13 .hof_user { color: orangered; font-style: italic; }
15 14 .hof_language { color: green; font-style: italic; }
16 15 .hof_value { color: deeppink;font-style: italic; }
17 16 .info_param { font-weight: bold;text-align: right; }
18 17 .tooltip {
19 18 font-family: Verdana,sans-serif;
20 19 font-weight: normal;
21 20 text-align: left;
22 21 font-size: 1.0em;
23 22 color: black;
24 23 line-height: 1.1;
25 24 display: none;
26 25 min-width: 20em;
27 26 position: absolute;
28 27 left: 25px;
29 28 bottom: 5px;
30 29 border: 1px solid;
31 30 padding: 5px;
32 31 background-color: #FFF;
33 32 word-wrap: break-word;
34 33 z-index: 9999;
35 34 overflow: auto;
36 35 }
37 36
38 37 %h1 (#{Problem.find(params[:id]).name}) #{Problem.find(params[:id]).full_name}
39 38
40 39 %h2 Problem Stat
41 40 %table.info
42 41 %thead
43 42 %tr.info-head
44 43 %th Stat
45 44 %th Value
46 45 %tbody
47 46 %tr{class: cycle('info-even','info-odd')}
48 47 %td.info_param Submissions
49 48 %td= @summary[:count]
50 49 %tr{class: cycle('info-even','info-odd')}
51 50 %td.info_param Solved/Attempted User
52 51 %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
53 52 - if @best
54 53 %tr{class: cycle('info-even','info-odd')}
55 54 %td.info_param Best Runtime
56 55 %td
57 56 by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
58 57 using <span class="hof_language">#{@best[:runtime][:lang]}</span>
59 58 with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span>
60 59 at submission
@@ -1,22 +1,25
1 1 <%= error_messages_for 'user' %>
2 2
3 3 <!--[form:user]-->
4 4 <p><label for="user_name">Login</label><br/>
5 5 <%= text_field 'user', 'login' %></p>
6 6
7 7 <p><label for="user_name">Full name</label><br/>
8 8 <%= text_field 'user', 'full_name' %></p>
9 9
10 10 <p><label for="password">Password</label><br/>
11 11 <%= password_field 'user', 'password' %></p>
12 12
13 13 <p><label for="password_confirmation">Password (confirm)</label><br/>
14 14 <%= password_field 'user', 'password_confirmation' %></p>
15 15
16 16 <p><label for="user_email">E-mail</label><br/>
17 - <%= text_field 'user', 'email' %></p>
17 + <%= email_field 'user', 'email' %></p>
18 18
19 19 <p><label for="user_alias">Alias</label><br/>
20 20 <%= text_field 'user', 'alias' %></p>
21 +
22 + <p><label for="user_remark">Remark</label><br/>
23 + <%= text_field 'user', 'remark' %></p>
21 24 <!--[eoform:user]-->
22 25
@@ -1,67 +1,67
1 1 <h1>Listing users</h1>
2 2
3 3 <div class="submitbox">
4 4 <b>Quick add</b>
5 5 <%= form_tag :action => 'create' do %>
6 6 <table border="0">
7 7 <tr>
8 8 <td><label for="user_login">Login</label></td>
9 9 <td><label for="user_full_name">Full name</label></td>
10 10 <td><label for="user_password">Password</label></td>
11 11 <td><label for="user_password_confirmation">Confirm</label></td>
12 12 <td><label for="user_email">Email</label></td>
13 13 </tr>
14 14 <tr>
15 15 <td><%= text_field 'user', 'login', :size => 10 %></td>
16 16 <td><%= text_field 'user', 'full_name', :size => 30 %></td>
17 17 <td><%= password_field 'user', 'password', :size => 10 %></td>
18 18 <td><%= password_field 'user', 'password_confirmation', :size => 10 %></td>
19 - <td><%= text_field 'user', 'email', :size => 15 %></td>
19 + <td><%= email_field 'user', 'email', :size => 15 %></td>
20 20 <td><%= submit_tag "Create" %></td>
21 21 </tr>
22 22 </table>
23 23 <% end %>
24 24 <br/>
25 25 <b>Import from site management</b>
26 26 <%= form_tag({:action => 'import'}, :multipart => true) do %>
27 27 File: <%= file_field_tag 'file' %> <%= submit_tag 'Import' %>
28 28 <% end %>
29 29 <br/>
30 30 <b>What else: </b>
31 31 <%= link_to '[New user]', :action => 'new' %>
32 32 <%= link_to '[New list of users]', :action => 'new_list' %>
33 33 <%= link_to '[View administrators]', :action => 'admin' %>
34 34 <%= link_to '[Random passwords]', :action => 'random_all_passwords' %>
35 35 <%= link_to '[View active users]', :action => 'active' %>
36 36 <%= link_to '[Mass mailing]', :action => 'mass_mailing' %>
37 37 <% if GraderConfiguration.multicontests? %>
38 38 <br/><b>Multi-contest:</b>
39 39 <%= link_to '[Manage bulk users in contests]', :action => 'contest_management' %>
40 40 View users in:
41 41 <% @contests.each do |contest| %>
42 42 <%= link_to "[#{contest.name}]", :action => 'contests', :id => contest.id %>
43 43 <% end %>
44 44 <%= link_to "[no contest]", :action => 'contests', :id => 'none' %>
45 45 <% end %>
46 46 </div>
47 47
48 48 Total <%= @user_count %> users |
49 49 <% if !@paginated %>
50 50 Display all users.
51 51 <%= link_to '[show in pages]', :action => 'list', :page => '1' %>
52 52 <% else %>
53 53 Display in pages.
54 54 <%= link_to '[display all]', :action => 'list', :page => 'all' %> |
55 55 <%= will_paginate @users, :container => false %>
56 56 <% end %>
57 57 <table class="info">
58 58 <tr class="info-head">
59 59 <% for column in User.content_columns %>
60 60 <% if !@hidden_columns.index(column.name) %>
61 61 <th><%= column.human_name %></th>
62 62 <% end %>
63 63 <% end %>
64 64 <th></th>
65 65 <th></th>
66 66 <th></th>
67 67 </tr>
@@ -1,59 +1,59
1 1 - content_for :header do
2 2 = javascript_include_tag 'local_jquery'
3 3 = stylesheet_link_tag 'tablesorter-theme.cafe'
4 4
5 5 %script{:type=>"text/javascript"}
6 6 $(function () {
7 7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 8 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 9 $('#my_table').tablesorter({widgets: ['zebra']});
10 10 });
11 11
12 12 %h1 User grading results
13 13 %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range"
14 14
15 15
16 16 - if @problem and @problem.errors
17 17 =error_messages_for 'problem'
18 18
19 19 = render partial: 'submission_range'
20 20
21 21 - if params[:action] == 'user_stat'
22 22 %h3 Latest score
23 23 = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat, commit: 'download csv'
24 24 - else
25 25 %h3 Max score
26 26 = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
27 27 = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat_max, commit: 'download csv'
28 28
29 29 %table.tablesorter-cafe#my_table
30 30 %thead
31 31 %tr
32 32 %th User
33 33 %th Name
34 34 %th Activated?
35 35 %th Logged in
36 36 %th Contest(s)
37 - %th Section
37 + %th Remark
38 38 - @problems.each do |p|
39 39 %th= p.name
40 40 %th Total
41 41 %th Passed
42 42 %tbody
43 43 - @scorearray.each do |sc|
44 44 %tr{class: cycle('info-even','info-odd')}
45 45 - total,num_passed = 0,0
46 46 - sc.each_index do |i|
47 47 - if i == 0
48 48 %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i]
49 49 %td= sc[i].full_name
50 50 %td= sc[i].activated
51 51 %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
52 52 %td= sc[i].contests.collect {|c| c.name}.join(', ')
53 - %td= sc[i].section
53 + %td= sc[i].remark
54 54 - else
55 55 %td= sc[i][0]
56 56 - total += sc[i][0]
57 57 - num_passed += 1 if sc[i][1]
58 58 %td= total
59 59 %td= num_passed
@@ -1,18 +1,19
1 1 .contest-title
2 2 %h1
3 3 = "#{GraderConfiguration['contest.name']}: #{t 'registration.password_retrieval.header'}"
4 4
5 5 - if flash[:notice]
6 6 %hr/
7 7 %b= flash[:notice]
8 8 %hr/
9 9
10 10 %br/
11 11
12 12 = form_tag :action => 'retrieve_password' do
13 13 =t 'registration.password_retrieval.instructions'
14 - = text_field 'email', nil, :size => 20
14 + %br/
15 + = email_field 'email', nil, :size => 20
15 16 %br/
16 17 = submit_tag(t 'registration.password_retrieval.button_label')
17 18
18 19 = link_to "#{t 'go_back_to'}#{t 'home_page'}", :controller => 'main', :action => 'index'
@@ -1,39 +1,39
1 1 .contest-title
2 2 %h1
3 3 = "#{GraderConfiguration['contest.name']}: #{t 'registration.title'}"
4 4
5 5 .registration-desc
6 6 =t 'registration.description'
7 7
8 8 = error_messages_for :user, :header_message => (t 'registration.errors.header')
9 9
10 10 %table
11 11 = form_for @user, :url => { :action => 'register' } do |f|
12 12 %tr
13 13 %td{:align => "right"}
14 14 = "#{t 'login_label'}:"
15 15 %td= f.text_field :login
16 16 %tr
17 17 %td
18 18 %td
19 19 %small
20 20 =t 'registration.login_guide'
21 21 %tr
22 22 %td{:align => "right"}
23 23 = "#{t 'full_name_label'}:"
24 24 %td= f.text_field :full_name
25 25 %tr
26 26 %td{:align => "right"}
27 27 = "#{t 'email_label'}:"
28 - %td= f.text_field :email
28 + %td= f.email_field :email
29 29 %tr
30 30 %td
31 31 %td
32 32 %small
33 - =t 'registration.email_guide'
33 + =t('registration.email_guide').html_safe
34 34 %tr
35 35 %td/
36 36 %td
37 37 = submit_tag((t 'registration.register'), :name => 'commit')
38 38 = submit_tag((t 'cancel'), :name => 'cancel')
39 39
@@ -1,37 +1,40
1 1 CafeGrader::Application.configure do
2 2 # Settings specified here will take precedence over those in config/application.rb
3 3
4 4 # In the development environment your application's code is reloaded on
5 5 # every request. This slows down response time but is perfect for development
6 6 # since you don't have to restart the web server when you make code changes.
7 7 config.cache_classes = false
8 8
9 9 # Log error messages when you accidentally call methods on nil.
10 10 config.whiny_nils = true
11 11
12 12 # Show full error reports and disable caching
13 13 config.consider_all_requests_local = true
14 14 config.action_controller.perform_caching = false
15 15
16 16 # Don't care if the mailer can't send
17 17 config.action_mailer.raise_delivery_errors = false
18 18
19 19 # Print deprecation notices to the Rails logger
20 20 config.active_support.deprecation = :log
21 21
22 22 # Only use best-standards-support built into browsers
23 23 config.action_dispatch.best_standards_support = :builtin
24 24
25 25 # Raise exception on mass assignment protection for Active Record models
26 26 config.active_record.mass_assignment_sanitizer = :strict
27 27
28 28 # Log the query plan for queries taking more than this (works
29 29 # with SQLite, MySQL, and PostgreSQL)
30 30 config.active_record.auto_explain_threshold_in_seconds = 0.5
31 31
32 32 # Do not compress assets
33 33 config.assets.compress = false
34 34
35 35 # Expands the lines which load the assets
36 36 config.assets.debug = true
37 +
38 + # Prevents assets from rendering twice
39 + config.serve_static_assets = false
37 40 end
@@ -1,61 +1,61
1 1 # Sample localization file for English. Add more files in this directory for other locales.
2 2 # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 3
4 4 en:
5 5 cancel: 'Cancel'
6 6
7 7 login_label: 'Login'
8 8 full_name_label: 'Full name'
9 9 email_label: 'E-mail'
10 10 password_label: 'Password'
11 11
12 - go_ahead_to: "Go ahead to"
13 - go_back_to: "Go back to"
12 + go_ahead_to: "Go ahead to "
13 + go_back_to: "Go back to "
14 14 login_page: "login page"
15 15 home_page: "home page"
16 16
17 17 menu:
18 18 main: 'Main'
19 19 messages: 'Messages'
20 20 tasks: 'Tasks'
21 21 submissions: 'Submissions'
22 22 test: 'Test Interface'
23 23 hall_of_fame: 'Hall of Fame'
24 24 help: 'Help'
25 25 settings: 'Settings'
26 26 log_out: 'Log out'
27 27
28 28 title_bar:
29 29 current_time: "Current time is"
30 30 remaining_time: "Time left: "
31 31 contest_not_started: "The contest has not started."
32 32
33 33 login:
34 34 message: 'Please login to see the problem list'
35 35 login_submit: 'Login'
36 36 participation: 'Want to participate?'
37 37 please: 'Please'
38 38 register: 'register'
39 39 forget_password: 'Forget password?'
40 40
41 41 main:
42 42 start_soon: "The contest at your site will start soon. Please wait."
43 43 specified_in_header: "Specified in header"
44 44
45 45 problem_desc: "desc"
46 46 submitted_at: "Submitted at"
47 47 graded_at: "Graded at"
48 48 score: "score: "
49 49 cmp_msg: "compiler msg"
50 50 src_link: "src"
51 51 submissions_link: "submissions"
52 52
53 53 confirm_contest_start:
54 54 box_title: "Contest confirmation"
55 55 contest_list: "You will participate in contest:"
56 56 timer_starts_after_click: "The timer will start after you click the start button."
57 57 start_button: "Start!"
58 58 start_button_confirm: "Are you sure?"
59 59
60 60 test:
61 61 title: "Test Interface"
@@ -1,56 +1,58
1 1 CafeGrader::Application.routes.draw do
2 2 get "report/login"
3 3
4 4 resources :contests
5 5
6 6 resources :announcements
7 7 resources :sites
8 8
9 + resources :grader_configuration, controller: 'configurations'
10 +
9 11 # The priority is based upon order of creation:
10 12 # first created -> highest priority.
11 13
12 14 # Sample of regular route:
13 15 # match 'products/:id' => 'catalog#view'
14 16 # Keep in mind you can assign values other than :controller and :action
15 17
16 18 # Sample of named route:
17 19 # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
18 20 # This route can be invoked with purchase_url(:id => product.id)
19 21
20 22 # Sample resource route (maps HTTP verbs to controller actions automatically):
21 23 # resources :products
22 24
23 25 # Sample resource route with options:
24 26 # resources :products do
25 27 # member do
26 28 # get 'short'
27 29 # post 'toggle'
28 30 # end
29 31 #
30 32 # collection do
31 33 # get 'sold'
32 34 # end
33 35 # end
34 36
35 37 # Sample resource route with sub-resources:
36 38 # resources :products do
37 39 # resources :comments, :sales
38 40 # resource :seller
39 41 # end
40 42
41 43 # Sample resource route with more complex sub-resources
42 44 # resources :products do
43 45 # resources :comments
44 46 # resources :sales do
45 47 # get 'recent', :on => :collection
46 48 # end
47 49 # end
48 50
49 51 # Sample resource route within a namespace:
50 52 # namespace :admin do
51 53 # # Directs /admin/products/* to Admin::ProductsController
52 54 # # (app/controllers/admin/products_controller.rb)
53 55 # resources :products
54 56 # end
55 57
56 58 # You can have the root of your site routed with "root"
@@ -1,62 +1,62
1 1 # encoding: UTF-8
2 2 # This file is auto-generated from the current state of the database. Instead
3 3 # of editing this file, please use the migrations feature of Active Record to
4 4 # incrementally modify your database, and then regenerate this schema definition.
5 5 #
6 6 # Note that this schema.rb definition is the authoritative source for your
7 7 # database schema. If you need to create the application database on another
8 8 # system, you should be using db:schema:load, not running all the migrations
9 9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 11 #
12 12 # It's strongly recommended to check this file into your version control system.
13 13
14 - ActiveRecord::Schema.define(:version => 20140917150629) do
14 + ActiveRecord::Schema.define(:version => 20150203153534) do
15 15
16 16 create_table "announcements", :force => true do |t|
17 17 t.string "author"
18 18 t.text "body"
19 19 t.boolean "published"
20 20 t.datetime "created_at", :null => false
21 21 t.datetime "updated_at", :null => false
22 22 t.boolean "frontpage", :default => false
23 23 t.boolean "contest_only", :default => false
24 24 t.string "title"
25 25 t.string "notes"
26 26 end
27 27
28 28 create_table "contests", :force => true do |t|
29 29 t.string "title"
30 30 t.boolean "enabled"
31 31 t.datetime "created_at", :null => false
32 32 t.datetime "updated_at", :null => false
33 33 t.string "name"
34 34 end
35 35
36 36 create_table "contests_problems", :id => false, :force => true do |t|
37 37 t.integer "contest_id"
38 38 t.integer "problem_id"
39 39 end
40 40
41 41 create_table "contests_users", :id => false, :force => true do |t|
42 42 t.integer "contest_id"
43 43 t.integer "user_id"
44 44 end
45 45
46 46 create_table "countries", :force => true do |t|
47 47 t.string "name"
48 48 t.datetime "created_at", :null => false
49 49 t.datetime "updated_at", :null => false
50 50 end
51 51
52 52 create_table "descriptions", :force => true do |t|
53 53 t.text "body"
54 54 t.boolean "markdowned"
55 55 t.datetime "created_at", :null => false
56 56 t.datetime "updated_at", :null => false
57 57 end
58 58
59 59 create_table "grader_configurations", :force => true do |t|
60 60 t.string "key"
61 61 t.string "value_type"
62 62 t.string "value"
@@ -194,54 +194,55
194 194 t.text "input", :limit => 16777215
195 195 t.text "solution", :limit => 16777215
196 196 t.datetime "created_at", :null => false
197 197 t.datetime "updated_at", :null => false
198 198 end
199 199
200 200 create_table "test_requests", :force => true do |t|
201 201 t.integer "user_id"
202 202 t.integer "problem_id"
203 203 t.integer "submission_id"
204 204 t.string "input_file_name"
205 205 t.string "output_file_name"
206 206 t.string "running_stat"
207 207 t.integer "status"
208 208 t.datetime "updated_at", :null => false
209 209 t.datetime "submitted_at"
210 210 t.datetime "compiled_at"
211 211 t.text "compiler_message"
212 212 t.datetime "graded_at"
213 213 t.string "grader_comment"
214 214 t.datetime "created_at", :null => false
215 215 t.float "running_time"
216 216 t.string "exit_status"
217 217 t.integer "memory_usage"
218 218 end
219 219
220 220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
221 221
222 222 create_table "user_contest_stats", :force => true do |t|
223 223 t.integer "user_id"
224 224 t.datetime "started_at"
225 225 t.datetime "created_at", :null => false
226 226 t.datetime "updated_at", :null => false
227 227 t.boolean "forced_logout"
228 228 end
229 229
230 230 create_table "users", :force => true do |t|
231 231 t.string "login", :limit => 50
232 232 t.string "full_name"
233 233 t.string "hashed_password"
234 234 t.string "salt", :limit => 5
235 235 t.string "alias"
236 236 t.string "email"
237 237 t.integer "site_id"
238 238 t.integer "country_id"
239 239 t.boolean "activated", :default => false
240 240 t.datetime "created_at"
241 241 t.datetime "updated_at"
242 - t.string "section"
242 + t.boolean "enabled", :default => true
243 + t.string "remark"
243 244 end
244 245
245 246 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
246 247
247 248 end
@@ -55,97 +55,97
55 55
56 56 {
57 57 :key => 'right.user_hall_of_fame',
58 58 :value_type => 'boolean',
59 59 :default_value => 'false',
60 60 :description => 'If true, any user can access hall of fame page.'
61 61 },
62 62
63 63 {
64 64 :key => 'right.user_view_submission',
65 65 :value_type => 'boolean',
66 66 :default_value => 'false',
67 67 :description => 'If true, any user can view submissions of every one.'
68 68 },
69 69
70 70 # If Configuration['system.online_registration'] is true, the
71 71 # system allows online registration, and will use these
72 72 # information for sending confirmation emails.
73 73 {
74 74 :key => 'system.online_registration.smtp',
75 75 :value_type => 'string',
76 76 :default_value => 'smtp.somehost.com'
77 77 },
78 78
79 79 {
80 80 :key => 'system.online_registration.from',
81 81 :value_type => 'string',
82 82 :default_value => 'your.email@address'
83 83 },
84 84
85 85 {
86 86 :key => 'system.admin_email',
87 87 :value_type => 'string',
88 88 :default_value => 'admin@admin.email'
89 89 },
90 90
91 91 {
92 92 :key => 'system.user_setting_enabled',
93 93 :value_type => 'boolean',
94 94 :default_value => 'true',
95 95 :description => 'If this option is true, users can change their settings'
96 96 },
97 97
98 98 {
99 99 :key => 'system.user_setting_enabled',
100 100 :value_type => 'boolean',
101 101 :default_value => 'true',
102 102 :description => 'If this option is true, users can change their settings'
103 - }
103 + },
104 104
105 105 # If Configuration['contest.test_request.early_timeout'] is true
106 106 # the user will not be able to use test request at 30 minutes
107 107 # before the contest ends.
108 108 {
109 109 :key => 'contest.test_request.early_timeout',
110 110 :value_type => 'boolean',
111 111 :default_value => 'false'
112 112 },
113 113
114 114 {
115 115 :key => 'system.multicontests',
116 116 :value_type => 'boolean',
117 117 :default_value => 'false'
118 118 },
119 119
120 120 {
121 121 :key => 'contest.confirm_indv_contest_start',
122 122 :value_type => 'boolean',
123 123 :default_value => 'false'
124 124 },
125 125
126 126 {
127 127 :key => 'contest.default_contest_name',
128 128 :value_type => 'string',
129 129 :default_value => 'none',
130 130 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
131 131 }
132 132
133 133 ]
134 134
135 135
136 136 def create_configuration_key(key,
137 137 value_type,
138 138 default_value,
139 139 description='')
140 140 conf = (GraderConfiguration.find_by_key(key) ||
141 141 GraderConfiguration.new(:key => key,
142 142 :value_type => value_type,
143 143 :value => default_value))
144 144 conf.description = description
145 145 conf.save
146 146 end
147 147
148 148 def seed_config
149 149 CONFIGURATIONS.each do |conf|
150 150 if conf.has_key? :description
151 151 desc = conf[:description]
@@ -1,30 +1,41
1 1 module MailHelperMethods
2 2
3 3 def send_mail(mail_to, mail_subject, mail_body)
4 4 mail_from = GraderConfiguration['system.online_registration.from']
5 5 smtp_server = GraderConfiguration['system.online_registration.smtp']
6 6
7 7 if ['fake', 'debug'].include? smtp_server
8 8 puts "-------------------------
9 9 To: #{mail_to}
10 10 From: #{mail_from}
11 11 Subject: #{mail_subject}
12 12 #{mail_body}
13 13 --------------------------
14 14 "
15 15 return true
16 16 end
17 17
18 18 mail = Mail.new do
19 19 from mail_from
20 20 to mail_to
21 21 subject mail_subject
22 22 body mail_body
23 23 end
24 24
25 - mail.delivery_settings = { :address => smtp_server }
25 + mail_option = {
26 + :address => smtp_server,
27 + # :domain => nil,
28 + # :port => 25,
29 + # :user_name => nil,
30 + # :password => nil,
31 + # :authentication=>'plain',
32 + # :enable_starttls_auto => true
33 + }
34 +
35 + mail.delivery_method :smtp, mail_option
36 +
26 37 mail.deliver
27 38 end
28 39
29 40 end
30 41
deleted file
You need to be logged in to leave comments. Login now