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 source 'https://rubygems.org'
1 source 'https://rubygems.org'
2
2
3 - gem 'rails', '3.2.19'
3 + gem 'rails', '3.2.21'
4
4
5 # Bundle edge Rails instead:
5 # Bundle edge Rails instead:
6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
7
7
8 gem 'mysql2'
8 gem 'mysql2'
9
9
10 # Gems used only for assets and not required
10 # Gems used only for assets and not required
11 # in production environments by default.
11 # in production environments by default.
12 group :assets do
12 group :assets do
13 - gem 'sass-rails', '~> 3.2.3'
13 + gem 'sass-rails', '~> 3.2.6'
14 - gem 'coffee-rails', '~> 3.2.1'
14 + gem 'coffee-rails', '~> 3.2.2'
15
15
16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
17 # gem 'therubyracer', :platforms => :ruby
17 # gem 'therubyracer', :platforms => :ruby
18
18
19 - gem 'uglifier', '>= 1.0.3'
19 + gem 'uglifier'
20 end
20 end
21
21
22 gem 'prototype-rails'
22 gem 'prototype-rails'
23
23
24 # To use ActiveModel has_secure_password
24 # To use ActiveModel has_secure_password
25 # gem 'bcrypt-ruby', '~> 3.0.0'
25 # gem 'bcrypt-ruby', '~> 3.0.0'
26
26
27 # To use Jbuilder templates for JSON
27 # To use Jbuilder templates for JSON
28 # gem 'jbuilder'
28 # gem 'jbuilder'
29
29
30 # Use unicorn as the app server
30 # Use unicorn as the app server
31 # gem 'unicorn'
31 # gem 'unicorn'
32
32
33 # Deploy with Capistrano
33 # Deploy with Capistrano
34 # gem 'capistrano'
34 # gem 'capistrano'
35
35
36 # To use debugger
36 # To use debugger
37 # gem 'debugger'
37 # gem 'debugger'
38 #
38 #
39
39
40 + #in-place editor
41 + gem 'best_in_place', '~> 3.0.1'
42 +
40 # jquery addition
43 # jquery addition
41 gem 'jquery-rails'
44 gem 'jquery-rails'
42 gem 'jquery-ui-sass-rails'
45 gem 'jquery-ui-sass-rails'
43 gem 'jquery-timepicker-addon-rails'
46 gem 'jquery-timepicker-addon-rails'
44 gem 'jquery-tablesorter'
47 gem 'jquery-tablesorter'
45
48
46 #syntax highlighter
49 #syntax highlighter
47 gem 'rouge'
50 gem 'rouge'
48
51
49 - gem "haml"
52 + gem 'haml'
50 - gem "mail"
53 + gem 'mail'
51 - gem "rdiscount"
54 + gem 'rdiscount'
52 - gem "test-unit"
55 + gem 'test-unit'
53 - gem 'will_paginate', '~> 3.0.0'
56 + gem 'will_paginate', '~> 3.0.7'
54 gem 'dynamic_form'
57 gem 'dynamic_form'
55 gem 'in_place_editing'
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 group :test, :development do
61 group :test, :development do
59 - gem "rspec-rails", "~> 2.0"
62 + gem 'rspec-rails', '~> 2.99.0'
60 end
63 end
@@ -1,171 +1,175
1 GIT
1 GIT
2 - remote: git://github.com/sikachu/verification.git
2 + remote: https://github.com/sikachu/verification.git
3 revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
3 revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
4 specs:
4 specs:
5 verification (1.0.3)
5 verification (1.0.3)
6 actionpack (>= 3.0.0, < 5.0)
6 actionpack (>= 3.0.0, < 5.0)
7 activesupport (>= 3.0.0, < 5.0)
7 activesupport (>= 3.0.0, < 5.0)
8
8
9 GEM
9 GEM
10 remote: https://rubygems.org/
10 remote: https://rubygems.org/
11 specs:
11 specs:
12 - actionmailer (3.2.19)
12 + actionmailer (3.2.21)
13 - actionpack (= 3.2.19)
13 + actionpack (= 3.2.21)
14 mail (~> 2.5.4)
14 mail (~> 2.5.4)
15 - actionpack (3.2.19)
15 + actionpack (3.2.21)
16 - activemodel (= 3.2.19)
16 + activemodel (= 3.2.21)
17 - activesupport (= 3.2.19)
17 + activesupport (= 3.2.21)
18 builder (~> 3.0.0)
18 builder (~> 3.0.0)
19 erubis (~> 2.7.0)
19 erubis (~> 2.7.0)
20 journey (~> 1.0.4)
20 journey (~> 1.0.4)
21 rack (~> 1.4.5)
21 rack (~> 1.4.5)
22 rack-cache (~> 1.2)
22 rack-cache (~> 1.2)
23 rack-test (~> 0.6.1)
23 rack-test (~> 0.6.1)
24 sprockets (~> 2.2.1)
24 sprockets (~> 2.2.1)
25 - activemodel (3.2.19)
25 + activemodel (3.2.21)
26 - activesupport (= 3.2.19)
26 + activesupport (= 3.2.21)
27 builder (~> 3.0.0)
27 builder (~> 3.0.0)
28 - activerecord (3.2.19)
28 + activerecord (3.2.21)
29 - activemodel (= 3.2.19)
29 + activemodel (= 3.2.21)
30 - activesupport (= 3.2.19)
30 + activesupport (= 3.2.21)
31 arel (~> 3.0.2)
31 arel (~> 3.0.2)
32 tzinfo (~> 0.3.29)
32 tzinfo (~> 0.3.29)
33 - activeresource (3.2.19)
33 + activeresource (3.2.21)
34 - activemodel (= 3.2.19)
34 + activemodel (= 3.2.21)
35 - activesupport (= 3.2.19)
35 + activesupport (= 3.2.21)
36 - activesupport (3.2.19)
36 + activesupport (3.2.21)
37 i18n (~> 0.6, >= 0.6.4)
37 i18n (~> 0.6, >= 0.6.4)
38 multi_json (~> 1.0)
38 multi_json (~> 1.0)
39 arel (3.0.3)
39 arel (3.0.3)
40 + best_in_place (3.0.3)
41 + actionpack (>= 3.2)
42 + railties (>= 3.2)
40 builder (3.0.4)
43 builder (3.0.4)
41 coffee-rails (3.2.2)
44 coffee-rails (3.2.2)
42 coffee-script (>= 2.2.0)
45 coffee-script (>= 2.2.0)
43 railties (~> 3.2.0)
46 railties (~> 3.2.0)
44 coffee-script (2.3.0)
47 coffee-script (2.3.0)
45 coffee-script-source
48 coffee-script-source
46 execjs
49 execjs
47 - coffee-script-source (1.7.1)
50 + coffee-script-source (1.9.0)
48 diff-lcs (1.2.5)
51 diff-lcs (1.2.5)
49 dynamic_form (1.1.4)
52 dynamic_form (1.1.4)
50 erubis (2.7.0)
53 erubis (2.7.0)
51 - execjs (2.2.1)
54 + execjs (2.3.0)
52 - haml (4.0.5)
55 + haml (4.0.6)
53 tilt
56 tilt
54 hike (1.2.3)
57 hike (1.2.3)
55 - i18n (0.6.11)
58 + i18n (0.7.0)
56 in_place_editing (1.2.0)
59 in_place_editing (1.2.0)
57 journey (1.0.4)
60 journey (1.0.4)
58 - jquery-rails (3.1.1)
61 + jquery-rails (3.1.2)
59 railties (>= 3.0, < 5.0)
62 railties (>= 3.0, < 5.0)
60 thor (>= 0.14, < 2.0)
63 thor (>= 0.14, < 2.0)
61 - jquery-tablesorter (1.12.7)
64 + jquery-tablesorter (1.13.4)
62 railties (>= 3.1, < 5)
65 railties (>= 3.1, < 5)
63 jquery-timepicker-addon-rails (1.4.1)
66 jquery-timepicker-addon-rails (1.4.1)
64 railties (>= 3.1)
67 railties (>= 3.1)
65 jquery-ui-rails (4.0.3)
68 jquery-ui-rails (4.0.3)
66 jquery-rails
69 jquery-rails
67 railties (>= 3.1.0)
70 railties (>= 3.1.0)
68 jquery-ui-sass-rails (4.0.3.0)
71 jquery-ui-sass-rails (4.0.3.0)
69 jquery-rails
72 jquery-rails
70 jquery-ui-rails (= 4.0.3)
73 jquery-ui-rails (= 4.0.3)
71 railties (>= 3.1.0)
74 railties (>= 3.1.0)
72 - json (1.8.1)
75 + json (1.8.2)
73 mail (2.5.4)
76 mail (2.5.4)
74 mime-types (~> 1.16)
77 mime-types (~> 1.16)
75 treetop (~> 1.4.8)
78 treetop (~> 1.4.8)
76 mime-types (1.25.1)
79 mime-types (1.25.1)
77 multi_json (1.10.1)
80 multi_json (1.10.1)
78 - mysql2 (0.3.16)
81 + mysql2 (0.3.17)
79 polyglot (0.3.5)
82 polyglot (0.3.5)
80 - power_assert (0.1.3)
83 + power_assert (0.2.2)
81 prototype-rails (3.2.1)
84 prototype-rails (3.2.1)
82 rails (~> 3.2)
85 rails (~> 3.2)
83 rack (1.4.5)
86 rack (1.4.5)
84 rack-cache (1.2)
87 rack-cache (1.2)
85 rack (>= 0.4)
88 rack (>= 0.4)
86 rack-ssl (1.3.4)
89 rack-ssl (1.3.4)
87 rack
90 rack
88 - rack-test (0.6.2)
91 + rack-test (0.6.3)
89 rack (>= 1.0)
92 rack (>= 1.0)
90 - rails (3.2.19)
93 + rails (3.2.21)
91 - actionmailer (= 3.2.19)
94 + actionmailer (= 3.2.21)
92 - actionpack (= 3.2.19)
95 + actionpack (= 3.2.21)
93 - activerecord (= 3.2.19)
96 + activerecord (= 3.2.21)
94 - activeresource (= 3.2.19)
97 + activeresource (= 3.2.21)
95 - activesupport (= 3.2.19)
98 + activesupport (= 3.2.21)
96 bundler (~> 1.0)
99 bundler (~> 1.0)
97 - railties (= 3.2.19)
100 + railties (= 3.2.21)
98 - railties (3.2.19)
101 + railties (3.2.21)
99 - actionpack (= 3.2.19)
102 + actionpack (= 3.2.21)
100 - activesupport (= 3.2.19)
103 + activesupport (= 3.2.21)
101 rack-ssl (~> 1.3.2)
104 rack-ssl (~> 1.3.2)
102 rake (>= 0.8.7)
105 rake (>= 0.8.7)
103 rdoc (~> 3.4)
106 rdoc (~> 3.4)
104 thor (>= 0.14.6, < 2.0)
107 thor (>= 0.14.6, < 2.0)
105 - rake (10.3.2)
108 + rake (10.4.2)
106 - rdiscount (2.1.7.1)
109 + rdiscount (2.1.8)
107 rdoc (3.12.2)
110 rdoc (3.12.2)
108 json (~> 1.4)
111 json (~> 1.4)
109 - rouge (1.6.2)
112 + rouge (1.8.0)
110 - rspec-collection_matchers (1.0.0)
113 + rspec-collection_matchers (1.1.2)
111 rspec-expectations (>= 2.99.0.beta1)
114 rspec-expectations (>= 2.99.0.beta1)
112 rspec-core (2.99.2)
115 rspec-core (2.99.2)
113 rspec-expectations (2.99.2)
116 rspec-expectations (2.99.2)
114 diff-lcs (>= 1.1.3, < 2.0)
117 diff-lcs (>= 1.1.3, < 2.0)
115 - rspec-mocks (2.99.2)
118 + rspec-mocks (2.99.3)
116 rspec-rails (2.99.0)
119 rspec-rails (2.99.0)
117 actionpack (>= 3.0)
120 actionpack (>= 3.0)
118 activemodel (>= 3.0)
121 activemodel (>= 3.0)
119 activesupport (>= 3.0)
122 activesupport (>= 3.0)
120 railties (>= 3.0)
123 railties (>= 3.0)
121 rspec-collection_matchers
124 rspec-collection_matchers
122 rspec-core (~> 2.99.0)
125 rspec-core (~> 2.99.0)
123 rspec-expectations (~> 2.99.0)
126 rspec-expectations (~> 2.99.0)
124 rspec-mocks (~> 2.99.0)
127 rspec-mocks (~> 2.99.0)
125 - sass (3.4.1)
128 + sass (3.4.11)
126 sass-rails (3.2.6)
129 sass-rails (3.2.6)
127 railties (~> 3.2.0)
130 railties (~> 3.2.0)
128 sass (>= 3.1.10)
131 sass (>= 3.1.10)
129 tilt (~> 1.3)
132 tilt (~> 1.3)
130 - sprockets (2.2.2)
133 + sprockets (2.2.3)
131 hike (~> 1.2)
134 hike (~> 1.2)
132 multi_json (~> 1.0)
135 multi_json (~> 1.0)
133 rack (~> 1.0)
136 rack (~> 1.0)
134 tilt (~> 1.1, != 1.3.0)
137 tilt (~> 1.1, != 1.3.0)
135 - test-unit (3.0.1)
138 + test-unit (3.0.9)
136 power_assert
139 power_assert
137 thor (0.19.1)
140 thor (0.19.1)
138 tilt (1.4.1)
141 tilt (1.4.1)
139 treetop (1.4.15)
142 treetop (1.4.15)
140 polyglot
143 polyglot
141 polyglot (>= 0.3.1)
144 polyglot (>= 0.3.1)
142 - tzinfo (0.3.41)
145 + tzinfo (0.3.43)
143 - uglifier (2.5.3)
146 + uglifier (2.7.0)
144 execjs (>= 0.3.0)
147 execjs (>= 0.3.0)
145 json (>= 1.8.0)
148 json (>= 1.8.0)
146 will_paginate (3.0.7)
149 will_paginate (3.0.7)
147
150
148 PLATFORMS
151 PLATFORMS
149 ruby
152 ruby
150
153
151 DEPENDENCIES
154 DEPENDENCIES
152 - coffee-rails (~> 3.2.1)
155 + best_in_place (~> 3.0.1)
156 + coffee-rails (~> 3.2.2)
153 dynamic_form
157 dynamic_form
154 haml
158 haml
155 in_place_editing
159 in_place_editing
156 jquery-rails
160 jquery-rails
157 jquery-tablesorter
161 jquery-tablesorter
158 jquery-timepicker-addon-rails
162 jquery-timepicker-addon-rails
159 jquery-ui-sass-rails
163 jquery-ui-sass-rails
160 mail
164 mail
161 mysql2
165 mysql2
162 prototype-rails
166 prototype-rails
163 - rails (= 3.2.19)
167 + rails (= 3.2.21)
164 rdiscount
168 rdiscount
165 rouge
169 rouge
166 - rspec-rails (~> 2.0)
170 + rspec-rails (~> 2.99.0)
167 - sass-rails (~> 3.2.3)
171 + sass-rails (~> 3.2.6)
168 test-unit
172 test-unit
169 - uglifier (>= 1.0.3)
173 + uglifier
170 verification!
174 verification!
171 - will_paginate (~> 3.0.0)
175 + will_paginate (~> 3.0.7)
@@ -1,182 +1,10
1 - == Welcome to Rails
1 + == cafe grader
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.
44
2
45 - Mongrel is a Ruby-based webserver with a C-component (which requires compilation) that is
3 + cafe grader is a programming contest platform used in Thailand IOI training.
46 - suitable for development and deployment of Rails applications. If you have Ruby Gems installed,
4 + The package includes 2 repositories, jittat/cafe-grader-web and jittat/cafe-grader-judge-scripts.
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'
89
5
90 - >> @posts.inspect
6 + === Installation
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.
133
7
134 - app/views
8 + The system is tested on ubuntu 14.04 LTS. Use the installation script in
135 - Holds the template files for the view that should be named like
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.
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.
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 //= require jquery
1 //= require jquery
2 //= require jquery_ujs
2 //= require jquery_ujs
3 //= require jquery.ui.all
3 //= require jquery.ui.all
4 //= require jquery.ui.datepicker
4 //= require jquery.ui.datepicker
5 //= require jquery.ui.slider
5 //= require jquery.ui.slider
6 //= require jquery-ui-timepicker-addon
6 //= require jquery-ui-timepicker-addon
7 //= require jquery-tablesorter
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 class ConfigurationsController < ApplicationController
1 class ConfigurationsController < ApplicationController
2
2
3 before_filter :authenticate
3 before_filter :authenticate
4 before_filter { |controller| controller.authorization_by_roles(['admin'])}
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 def index
7 def index
11 @configurations = GraderConfiguration.find(:all,
8 @configurations = GraderConfiguration.find(:all,
12 :order => '`key`')
9 :order => '`key`')
13 end
10 end
14
11
15 def reload
12 def reload
16 GraderConfiguration.reload
13 GraderConfiguration.reload
17 redirect_to :action => 'index'
14 redirect_to :action => 'index'
18 end
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 end
28 end
@@ -16,35 +16,35
16 UserContestStat.find(:all).each do |stat|
16 UserContestStat.find(:all).each do |stat|
17 @start_times[stat.user_id] = stat.started_at
17 @start_times[stat.user_id] = stat.started_at
18 end
18 end
19 end
19 end
20
20
21 def clear_stat
21 def clear_stat
22 user = User.find(params[:id])
22 user = User.find(params[:id])
23 if user.contest_stat!=nil
23 if user.contest_stat!=nil
24 user.contest_stat.destroy
24 user.contest_stat.destroy
25 end
25 end
26 redirect_to :action => 'user_stat'
26 redirect_to :action => 'user_stat'
27 end
27 end
28
28
29 def clear_all_stat
29 def clear_all_stat
30 if not GraderConfiguration.indv_contest_mode?
30 if not GraderConfiguration.indv_contest_mode?
31 redirect_to :action => 'index' and return
31 redirect_to :action => 'index' and return
32 end
32 end
33
33
34 UserContestStat.delete_all()
34 UserContestStat.delete_all()
35 flash[:notice] = 'All start time statistic cleared.'
35 flash[:notice] = 'All start time statistic cleared.'
36 redirect_to :action => 'index'
36 redirect_to :action => 'index'
37 end
37 end
38
38
39 def change_contest_mode
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 config = GraderConfiguration.find_by_key('system.mode')
41 config = GraderConfiguration.find_by_key('system.mode')
42 config.value = params[:id]
42 config.value = params[:id]
43 config.save
43 config.save
44 else
44 else
45 flash[:notice] = 'Wrong contest mode value'
45 flash[:notice] = 'Wrong contest mode value'
46 end
46 end
47 redirect_to :action => 'index'
47 redirect_to :action => 'index'
48 end
48 end
49
49
50 end
50 end
@@ -50,49 +50,49
50 def list
50 def list
51 prepare_list_information
51 prepare_list_information
52 end
52 end
53
53
54 def help
54 def help
55 @user = User.find(session[:user_id])
55 @user = User.find(session[:user_id])
56 end
56 end
57
57
58 def submit
58 def submit
59 user = User.find(session[:user_id])
59 user = User.find(session[:user_id])
60
60
61 @submission = Submission.new
61 @submission = Submission.new
62 @submission.problem_id = params[:submission][:problem_id]
62 @submission.problem_id = params[:submission][:problem_id]
63 @submission.user = user
63 @submission.user = user
64 @submission.language_id = 0
64 @submission.language_id = 0
65 if (params['file']) and (params['file']!='')
65 if (params['file']) and (params['file']!='')
66 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
66 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
67 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
67 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
68 @submission.source_filename = params['file'].original_filename
68 @submission.source_filename = params['file'].original_filename
69 end
69 end
70 @submission.submitted_at = Time.new.gmtime
70 @submission.submitted_at = Time.new.gmtime
71 @submission.ip_address = request.remote_ip
71 @submission.ip_address = request.remote_ip
72
72
73 if GraderConfiguration.time_limit_mode? and user.contest_finished?
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 prepare_list_information
75 prepare_list_information
76 render :action => 'list' and return
76 render :action => 'list' and return
77 end
77 end
78
78
79 if @submission.valid?
79 if @submission.valid?
80 if @submission.save == false
80 if @submission.save == false
81 flash[:notice] = 'Error saving your submission'
81 flash[:notice] = 'Error saving your submission'
82 elsif Task.create(:submission_id => @submission.id,
82 elsif Task.create(:submission_id => @submission.id,
83 :status => Task::STATUS_INQUEUE) == false
83 :status => Task::STATUS_INQUEUE) == false
84 flash[:notice] = 'Error adding your submission to task queue'
84 flash[:notice] = 'Error adding your submission to task queue'
85 end
85 end
86 else
86 else
87 prepare_list_information
87 prepare_list_information
88 render :action => 'list' and return
88 render :action => 'list' and return
89 end
89 end
90 redirect_to :action => 'list'
90 redirect_to :action => 'list'
91 end
91 end
92
92
93 def source
93 def source
94 submission = Submission.find(params[:id])
94 submission = Submission.find(params[:id])
95 if ((submission.user_id == session[:user_id]) and
95 if ((submission.user_id == session[:user_id]) and
96 (submission.problem != nil) and
96 (submission.problem != nil) and
97 (submission.problem.available))
97 (submission.problem.available))
98 send_data(submission.source,
98 send_data(submission.source,
@@ -173,49 +173,49
173 else
173 else
174 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
174 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
175 end
175 end
176 end
176 end
177
177
178 def error
178 def error
179 @user = User.find(session[:user_id])
179 @user = User.find(session[:user_id])
180 end
180 end
181
181
182 # announcement refreshing and hiding methods
182 # announcement refreshing and hiding methods
183
183
184 def announcements
184 def announcements
185 if params.has_key? 'recent'
185 if params.has_key? 'recent'
186 prepare_announcements(params[:recent])
186 prepare_announcements(params[:recent])
187 else
187 else
188 prepare_announcements
188 prepare_announcements
189 end
189 end
190 render(:partial => 'announcement',
190 render(:partial => 'announcement',
191 :collection => @announcements,
191 :collection => @announcements,
192 :locals => {:announcement_effect => true})
192 :locals => {:announcement_effect => true})
193 end
193 end
194
194
195 def confirm_contest_start
195 def confirm_contest_start
196 user = User.find(session[:user_id])
196 user = User.find(session[:user_id])
197 - if request.method == :post
197 + if request.method == 'POST'
198 user.update_start_time
198 user.update_start_time
199 redirect_to :action => 'list'
199 redirect_to :action => 'list'
200 else
200 else
201 @contests = user.contests
201 @contests = user.contests
202 @user = user
202 @user = user
203 end
203 end
204 end
204 end
205
205
206 protected
206 protected
207
207
208 def prepare_announcements(recent=nil)
208 def prepare_announcements(recent=nil)
209 if GraderConfiguration.show_tasks_to?(@user)
209 if GraderConfiguration.show_tasks_to?(@user)
210 @announcements = Announcement.find_published(true)
210 @announcements = Announcement.find_published(true)
211 else
211 else
212 @announcements = Announcement.find_published
212 @announcements = Announcement.find_published
213 end
213 end
214 if recent!=nil
214 if recent!=nil
215 recent_id = recent.to_i
215 recent_id = recent.to_i
216 @announcements = @announcements.find_all { |a| a.id > recent_id }
216 @announcements = @announcements.find_all { |a| a.id > recent_id }
217 end
217 end
218 end
218 end
219
219
220 def prepare_list_information
220 def prepare_list_information
221 @user = User.find(session[:user_id])
221 @user = User.find(session[:user_id])
@@ -10,76 +10,77
10
10
11 def list
11 def list
12 @user = User.find(session[:user_id])
12 @user = User.find(session[:user_id])
13 @messages = Message.find_all_sent_by_user(@user)
13 @messages = Message.find_all_sent_by_user(@user)
14 end
14 end
15
15
16 def console
16 def console
17 @user = User.find(session[:user_id])
17 @user = User.find(session[:user_id])
18 @messages = Message.find_all_system_unreplied_messages
18 @messages = Message.find_all_system_unreplied_messages
19 end
19 end
20
20
21 def show
21 def show
22 @message = Message.find(params[:id])
22 @message = Message.find(params[:id])
23 end
23 end
24
24
25 def list_all
25 def list_all
26 @user = User.find(session[:user_id])
26 @user = User.find(session[:user_id])
27 @messages = Message.where(receiver_id: nil).order(:created_at)
27 @messages = Message.where(receiver_id: nil).order(:created_at)
28 end
28 end
29
29
30 def create
30 def create
31 user = User.find(session[:user_id])
31 user = User.find(session[:user_id])
32 @message = Message.new(params[:message])
32 @message = Message.new(params[:message])
33 @message.sender = user
33 @message.sender = user
34 - if !@message.save
34 + if @message.body == '' or !@message.save
35 - render :action => 'list' and return
35 + flash[:notice] = 'An error occurred'
36 else
36 else
37 flash[:notice] = 'New message posted'
37 flash[:notice] = 'New message posted'
38 - redirect_to :action => 'list'
39 end
38 end
39 + redirect_to :action => 'list'
40 end
40 end
41
41
42 def reply
42 def reply
43 user = User.find(session[:user_id])
43 user = User.find(session[:user_id])
44 @message = Message.new(params[:r_message])
44 @message = Message.new(params[:r_message])
45 @message.sender = user
45 @message.sender = user
46 - if !@message.save
46 + if @message.body == '' or !@message.save
47 - render :action => 'show' and return
47 + flash[:notice] = 'An error occurred'
48 + redirect_to :action => 'show', :id => @message.replying_message_id
48 else
49 else
49 flash[:notice] = 'Message replied'
50 flash[:notice] = 'Message replied'
50 rep_msg = @message.replying_message
51 rep_msg = @message.replying_message
51 rep_msg.replied = true
52 rep_msg.replied = true
52 rep_msg.save
53 rep_msg.save
53 redirect_to :action => 'console'
54 redirect_to :action => 'console'
54 end
55 end
55 end
56 end
56
57
57 def hide
58 def hide
58 message = Message.find(params[:id])
59 message = Message.find(params[:id])
59 message.replied = true
60 message.replied = true
60 message.save
61 message.save
61 - flash[:notice] = 'Message hided (just marked replied)'
62 + flash[:notice] = 'Message hidden (just marked replied)'
62 redirect_to :action => 'console'
63 redirect_to :action => 'console'
63 end
64 end
64
65
65 protected
66 protected
66 def build_replying_message_hierarchy(user)
67 def build_replying_message_hierarchy(user)
67 @all_messages = {}
68 @all_messages = {}
68
69
69
70
70 # manually build replies hierarchy (to improve efficiency)
71 # manually build replies hierarchy (to improve efficiency)
71 [@messages, @replied_messages].each do |collection|
72 [@messages, @replied_messages].each do |collection|
72 collection.each do |m|
73 collection.each do |m|
73 @all_messages[m.id] = {:msg => m, :replies => []}
74 @all_messages[m.id] = {:msg => m, :replies => []}
74 end
75 end
75 end
76 end
76
77
77 @all_messages.each do |m|
78 @all_messages.each do |m|
78 rep_id = m.replying_message_id
79 rep_id = m.replying_message_id
79 if @all_messages[rep_id]!=nil
80 if @all_messages[rep_id]!=nil
80 @all_messages[rep_id][:replies] << m
81 @all_messages[rep_id][:replies] << m
81 end
82 end
82 end
83 end
83 end
84 end
84
85
85 end
86 end
@@ -1,27 +1,27
1 class ReportController < ApplicationController
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 before_filter(only: [:problem_hof]) { |c|
4 before_filter(only: [:problem_hof]) { |c|
5 return false unless authenticate
5 return false unless authenticate
6
6
7 if GraderConfiguration["right.user_view_submission"]
7 if GraderConfiguration["right.user_view_submission"]
8 return true;
8 return true;
9 end
9 end
10
10
11 admin_authorization
11 admin_authorization
12 }
12 }
13
13
14 def login_stat
14 def login_stat
15 @logins = Array.new
15 @logins = Array.new
16
16
17 date_and_time = '%Y-%m-%d %H:%M'
17 date_and_time = '%Y-%m-%d %H:%M'
18 begin
18 begin
19 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
19 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
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)
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 rescue
21 rescue
22 @since_time = DateTime.new(1000,1,1)
22 @since_time = DateTime.new(1000,1,1)
23 end
23 end
24 begin
24 begin
25 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
25 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
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)
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 rescue
27 rescue
@@ -97,48 +97,49
97 # get selected problems or the default
97 # get selected problems or the default
98 if params[:id]
98 if params[:id]
99 begin
99 begin
100 @problem = Problem.available.find(params[:id])
100 @problem = Problem.available.find(params[:id])
101 rescue
101 rescue
102 redirect_to action: :problem_hof
102 redirect_to action: :problem_hof
103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
104 return
104 return
105 end
105 end
106 end
106 end
107
107
108 return unless @problem
108 return unless @problem
109
109
110 @by_lang = {} #aggregrate by language
110 @by_lang = {} #aggregrate by language
111
111
112 range =65
112 range =65
113 @histogram = { data: Array.new(range,0), summary: {} }
113 @histogram = { data: Array.new(range,0), summary: {} }
114 @summary = {count: 0, solve: 0, attempt: 0}
114 @summary = {count: 0, solve: 0, attempt: 0}
115 user = Hash.new(0)
115 user = Hash.new(0)
116 Submission.where(problem_id: @problem.id).find_each do |sub|
116 Submission.where(problem_id: @problem.id).find_each do |sub|
117 #histogram
117 #histogram
118 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
118 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
119 @histogram[:data][d.to_i] += 1 if d < range
119 @histogram[:data][d.to_i] += 1 if d < range
120
120
121 + next unless sub.points
121 @summary[:count] += 1
122 @summary[:count] += 1
122 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
123 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
123
124
124 lang = Language.find_by_id(sub.language_id)
125 lang = Language.find_by_id(sub.language_id)
125 next unless lang
126 next unless lang
126 next unless sub.points >= @problem.full_score
127 next unless sub.points >= @problem.full_score
127
128
128 #initialize
129 #initialize
129 unless @by_lang.has_key?(lang.pretty_name)
130 unless @by_lang.has_key?(lang.pretty_name)
130 @by_lang[lang.pretty_name] = {
131 @by_lang[lang.pretty_name] = {
131 runtime: { avail: false, value: 2**30-1 },
132 runtime: { avail: false, value: 2**30-1 },
132 memory: { avail: false, value: 2**30-1 },
133 memory: { avail: false, value: 2**30-1 },
133 length: { avail: false, value: 2**30-1 },
134 length: { avail: false, value: 2**30-1 },
134 first: { avail: false, value: DateTime.new(3000,1,1) }
135 first: { avail: false, value: DateTime.new(3000,1,1) }
135 }
136 }
136 end
137 end
137
138
138 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
139 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
139 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
140 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
140 end
141 end
141
142
142 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
143 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
143 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
144 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
144 end
145 end
@@ -175,49 +176,49
175 if @best[:length][:value] >= prop[:length][:value]
176 if @best[:length][:value] >= prop[:length][:value]
176 @best[:length] = prop[:length]
177 @best[:length] = prop[:length]
177 @best[:length][:lang] = lang
178 @best[:length][:lang] = lang
178 end
179 end
179 if @best[:first][:value] >= prop[:first][:value]
180 if @best[:first][:value] >= prop[:first][:value]
180 @best[:first] = prop[:first]
181 @best[:first] = prop[:first]
181 @best[:first][:lang] = lang
182 @best[:first][:lang] = lang
182 end
183 end
183 end
184 end
184 end
185 end
185
186
186 @histogram[:summary][:max] = [@histogram[:data].max,1].max
187 @histogram[:summary][:max] = [@histogram[:data].max,1].max
187 @summary[:attempt] = user.count
188 @summary[:attempt] = user.count
188 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
189 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
189 end
190 end
190
191
191 def stuck #report struggling user,problem
192 def stuck #report struggling user,problem
192 # init
193 # init
193 user,problem = nil
194 user,problem = nil
194 solve = true
195 solve = true
195 tries = 0
196 tries = 0
196 @struggle = Array.new
197 @struggle = Array.new
197 record = {}
198 record = {}
198 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
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 if user != sub.user_id or problem != sub.problem_id
201 if user != sub.user_id or problem != sub.problem_id
201 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
202 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
202 record = {user: sub.user, problem: sub.problem}
203 record = {user: sub.user, problem: sub.problem}
203 user,problem = sub.user_id, sub.problem_id
204 user,problem = sub.user_id, sub.problem_id
204 solve = false
205 solve = false
205 tries = 0
206 tries = 0
206 end
207 end
207 if sub.points >= sub.problem.full_score
208 if sub.points >= sub.problem.full_score
208 solve = true
209 solve = true
209 else
210 else
210 tries += 1
211 tries += 1
211 end
212 end
212 end
213 end
213 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
214 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
214 @struggle = @struggle[0..50]
215 @struggle = @struggle[0..50]
215 end
216 end
216
217
217
218
218 def multiple_login
219 def multiple_login
219 #user with multiple IP
220 #user with multiple IP
220 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
221 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
221 last,count = 0,0
222 last,count = 0,0
222 first = 0
223 first = 0
223 @users = []
224 @users = []
@@ -5,49 +5,49
5 #
5 #
6 # COMMENT OUT: filter in each action instead
6 # COMMENT OUT: filter in each action instead
7 #
7 #
8 # before_filter :verify_time_limit, :only => [:submit]
8 # before_filter :verify_time_limit, :only => [:submit]
9
9
10 verify :method => :post, :only => [:submit],
10 verify :method => :post, :only => [:submit],
11 :redirect_to => { :action => :index }
11 :redirect_to => { :action => :index }
12
12
13 def index
13 def index
14 prepare_index_information
14 prepare_index_information
15 end
15 end
16
16
17 def submit
17 def submit
18 @user = User.find(session[:user_id])
18 @user = User.find(session[:user_id])
19
19
20 @submitted_test_request = TestRequest.new_from_form_params(@user,params[:test_request])
20 @submitted_test_request = TestRequest.new_from_form_params(@user,params[:test_request])
21
21
22 if ! @submitted_test_request.errors.empty?
22 if ! @submitted_test_request.errors.empty?
23 prepare_index_information
23 prepare_index_information
24 render :action => 'index' and return
24 render :action => 'index' and return
25 end
25 end
26
26
27 if GraderConfiguration.time_limit_mode?
27 if GraderConfiguration.time_limit_mode?
28 if @user.contest_finished?
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 prepare_index_information
30 prepare_index_information
31 render :action => 'index' and return
31 render :action => 'index' and return
32 end
32 end
33
33
34 if !GraderConfiguration.allow_test_request(@user)
34 if !GraderConfiguration.allow_test_request(@user)
35 prepare_index_information
35 prepare_index_information
36 flash[:notice] = 'Test request is not allowed during the last 30 minutes'
36 flash[:notice] = 'Test request is not allowed during the last 30 minutes'
37 redirect_to :action => 'index' and return
37 redirect_to :action => 'index' and return
38 end
38 end
39 end
39 end
40
40
41 if @submitted_test_request.save
41 if @submitted_test_request.save
42 redirect_to :action => 'index'
42 redirect_to :action => 'index'
43 else
43 else
44 prepare_index_information
44 prepare_index_information
45 render :action => 'index'
45 render :action => 'index'
46 end
46 end
47 end
47 end
48
48
49 def read
49 def read
50 user = User.find(session[:user_id])
50 user = User.find(session[:user_id])
51 begin
51 begin
52 test_request = TestRequest.find(params[:id])
52 test_request = TestRequest.find(params[:id])
53 rescue
53 rescue
@@ -1,29 +1,28
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5 -
6 include MailHelperMethods
5 include MailHelperMethods
7
6
8 before_filter :admin_authorization
7 before_filter :admin_authorization
9
8
10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
11 verify :method => :post, :only => [ :destroy,
10 verify :method => :post, :only => [ :destroy,
12 :create, :create_from_list,
11 :create, :create_from_list,
13 :update,
12 :update,
14 :manage_contest,
13 :manage_contest,
15 :bulk_mail
14 :bulk_mail
16 ],
15 ],
17 :redirect_to => { :action => :list }
16 :redirect_to => { :action => :list }
18
17
19 def index
18 def index
20 list
19 list
21 render :action => 'list'
20 render :action => 'list'
22 end
21 end
23
22
24 def list
23 def list
25 @user_count = User.count
24 @user_count = User.count
26 if params[:page] == 'all'
25 if params[:page] == 'all'
27 @users = User.all
26 @users = User.all
28 @paginated = false
27 @paginated = false
29 else
28 else
@@ -64,49 +63,50
64 end
63 end
65
64
66 def create_from_list
65 def create_from_list
67 lines = params[:user_list]
66 lines = params[:user_list]
68
67
69 note = []
68 note = []
70
69
71 lines.split("\n").each do |line|
70 lines.split("\n").each do |line|
72 items = line.chomp.split(',')
71 items = line.chomp.split(',')
73 if items.length>=2
72 if items.length>=2
74 login = items[0]
73 login = items[0]
75 full_name = items[1]
74 full_name = items[1]
76
75
77 added_random_password = false
76 added_random_password = false
78 if items.length>=3
77 if items.length>=3
79 password = items[2].chomp(" ")
78 password = items[2].chomp(" ")
80 user_alias = (items.length>=4) ? items[3] : login
79 user_alias = (items.length>=4) ? items[3] : login
81 else
80 else
82 password = random_password
81 password = random_password
83 user_alias = (items.length>=4) ? items[3] : login
82 user_alias = (items.length>=4) ? items[3] : login
84 added_random_password = true
83 added_random_password = true
85 end
84 end
86
85
87 user = User.find_by_login(login)
86 user = User.find_by_login(login)
88 - if user
87 + if (user)
88 + user.full_name = full_name
89 user.password = password
89 user.password = password
90 else
90 else
91 user = User.new({:login => login,
91 user = User.new({:login => login,
92 :full_name => full_name,
92 :full_name => full_name,
93 :password => password,
93 :password => password,
94 :password_confirmation => password,
94 :password_confirmation => password,
95 :alias => user_alias})
95 :alias => user_alias})
96 end
96 end
97 user.activated = true
97 user.activated = true
98 user.save
98 user.save
99
99
100 if added_random_password
100 if added_random_password
101 note << "'#{login}' (+)"
101 note << "'#{login}' (+)"
102 else
102 else
103 note << login
103 note << login
104 end
104 end
105 end
105 end
106 end
106 end
107 flash[:notice] = 'User(s) ' + note.join(', ') +
107 flash[:notice] = 'User(s) ' + note.join(', ') +
108 ' were successfully created. ' +
108 ' were successfully created. ' +
109 '( (+) - created with random passwords.)'
109 '( (+) - created with random passwords.)'
110 redirect_to :action => 'list'
110 redirect_to :action => 'list'
111 end
111 end
112
112
@@ -129,49 +129,48
129 redirect_to :action => 'list'
129 redirect_to :action => 'list'
130 end
130 end
131
131
132 def user_stat
132 def user_stat
133 if params[:commit] == 'download csv'
133 if params[:commit] == 'download csv'
134 @problems = Problem.all
134 @problems = Problem.all
135 else
135 else
136 @problems = Problem.find_available_problems
136 @problems = Problem.find_available_problems
137 end
137 end
138 @users = User.find(:all, :include => [:contests, :contest_stat])
138 @users = User.find(:all, :include => [:contests, :contest_stat])
139 @scorearray = Array.new
139 @scorearray = Array.new
140 @users.each do |u|
140 @users.each do |u|
141 ustat = Array.new
141 ustat = Array.new
142 ustat[0] = u
142 ustat[0] = u
143 @problems.each do |p|
143 @problems.each do |p|
144 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
144 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
145 if (sub!=nil) and (sub.points!=nil)
145 if (sub!=nil) and (sub.points!=nil)
146 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
146 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
147 else
147 else
148 ustat << [0,false]
148 ustat << [0,false]
149 end
149 end
150 end
150 end
151 @scorearray << ustat
151 @scorearray << ustat
152 end
152 end
153 -
154 if params[:commit] == 'download csv' then
153 if params[:commit] == 'download csv' then
155 csv = gen_csv_from_scorearray(@scorearray,@problems)
154 csv = gen_csv_from_scorearray(@scorearray,@problems)
156 send_data csv, filename: 'last_score.csv'
155 send_data csv, filename: 'last_score.csv'
157 else
156 else
158 render template: 'user_admin/user_stat'
157 render template: 'user_admin/user_stat'
159 end
158 end
160 end
159 end
161
160
162 def user_stat_max
161 def user_stat_max
163 if params[:commit] == 'download csv'
162 if params[:commit] == 'download csv'
164 @problems = Problem.all
163 @problems = Problem.all
165 else
164 else
166 @problems = Problem.find_available_problems
165 @problems = Problem.find_available_problems
167 end
166 end
168 @users = User.find(:all, :include => [:contests, :contest_stat])
167 @users = User.find(:all, :include => [:contests, :contest_stat])
169 @scorearray = Array.new
168 @scorearray = Array.new
170 #set up range from param
169 #set up range from param
171 since_id = params.fetch(:since_id, 0).to_i
170 since_id = params.fetch(:since_id, 0).to_i
172 until_id = params.fetch(:until_id, 0).to_i
171 until_id = params.fetch(:until_id, 0).to_i
173 @users.each do |u|
172 @users.each do |u|
174 ustat = Array.new
173 ustat = Array.new
175 ustat[0] = u
174 ustat[0] = u
176 @problems.each do |p|
175 @problems.each do |p|
177 max_points = 0
176 max_points = 0
@@ -42,49 +42,49
42 redirect_to :action => 'index'
42 redirect_to :action => 'index'
43 end
43 end
44
44
45 def new
45 def new
46 @user = User.new
46 @user = User.new
47 render :action => 'new', :layout => 'empty'
47 render :action => 'new', :layout => 'empty'
48 end
48 end
49
49
50 def register
50 def register
51 if(params[:cancel])
51 if(params[:cancel])
52 redirect_to :controller => 'main', :action => 'login'
52 redirect_to :controller => 'main', :action => 'login'
53 return
53 return
54 end
54 end
55 @user = User.new(params[:user])
55 @user = User.new(params[:user])
56 @user.password_confirmation = @user.password = User.random_password
56 @user.password_confirmation = @user.password = User.random_password
57 @user.activated = false
57 @user.activated = false
58 if (@user.valid?) and (@user.save)
58 if (@user.valid?) and (@user.save)
59 if send_confirmation_email(@user)
59 if send_confirmation_email(@user)
60 render :action => 'new_splash', :layout => 'empty'
60 render :action => 'new_splash', :layout => 'empty'
61 else
61 else
62 @admin_email = GraderConfiguration['system.admin_email']
62 @admin_email = GraderConfiguration['system.admin_email']
63 render :action => 'email_error', :layout => 'empty'
63 render :action => 'email_error', :layout => 'empty'
64 end
64 end
65 else
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 render :action => 'new', :layout => 'empty'
67 render :action => 'new', :layout => 'empty'
68 end
68 end
69 end
69 end
70
70
71 def confirm
71 def confirm
72 login = params[:login]
72 login = params[:login]
73 key = params[:activation]
73 key = params[:activation]
74 @user = User.find_by_login(login)
74 @user = User.find_by_login(login)
75 if (@user) and (@user.verify_activation_key(key))
75 if (@user) and (@user.verify_activation_key(key))
76 if @user.valid? # check uniquenss of email
76 if @user.valid? # check uniquenss of email
77 @user.activated = true
77 @user.activated = true
78 @user.save
78 @user.save
79 @result = :successful
79 @result = :successful
80 else
80 else
81 @result = :email_used
81 @result = :email_used
82 end
82 end
83 else
83 else
84 @result = :failed
84 @result = :failed
85 end
85 end
86 render :action => 'confirm', :layout => 'empty'
86 render :action => 'confirm', :layout => 'empty'
87 end
87 end
88
88
89 def forget
89 def forget
90 render :action => 'forget', :layout => 'empty'
90 render :action => 'forget', :layout => 'empty'
@@ -133,63 +133,63
133 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
133 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
134 end
134 end
135
135
136 protected
136 protected
137
137
138 def verify_online_registration
138 def verify_online_registration
139 if !GraderConfiguration['system.online_registration']
139 if !GraderConfiguration['system.online_registration']
140 redirect_to :controller => 'main', :action => 'login'
140 redirect_to :controller => 'main', :action => 'login'
141 end
141 end
142 end
142 end
143
143
144 def send_confirmation_email(user)
144 def send_confirmation_email(user)
145 contest_name = GraderConfiguration['contest.name']
145 contest_name = GraderConfiguration['contest.name']
146 activation_url = url_for(:action => 'confirm',
146 activation_url = url_for(:action => 'confirm',
147 :login => user.login,
147 :login => user.login,
148 :activation => user.activation_key)
148 :activation => user.activation_key)
149 home_url = url_for(:controller => 'main', :action => 'index')
149 home_url = url_for(:controller => 'main', :action => 'index')
150 mail_subject = "[#{contest_name}] Confirmation"
150 mail_subject = "[#{contest_name}] Confirmation"
151 mail_body = t('registration.email_body', {
151 mail_body = t('registration.email_body', {
152 :full_name => user.full_name,
152 :full_name => user.full_name,
153 :contest_name => contest_name,
153 :contest_name => contest_name,
154 :login => user.login,
154 :login => user.login,
155 :password => user.password,
155 :password => user.password,
156 :activation_url => activation_url,
156 :activation_url => activation_url,
157 - :admin_email => admin_email
157 + :admin_email => GraderConfiguration['system.admin_email']
158 })
158 })
159
159
160 logger.info mail_body
160 logger.info mail_body
161
161
162 send_mail(user.email, mail_subject, mail_body)
162 send_mail(user.email, mail_subject, mail_body)
163 end
163 end
164
164
165 def send_new_password_email(user)
165 def send_new_password_email(user)
166 contest_name = GraderConfiguration['contest.name']
166 contest_name = GraderConfiguration['contest.name']
167 mail_subject = "[#{contest_name}] Password recovery"
167 mail_subject = "[#{contest_name}] Password recovery"
168 mail_body = t('registration.password_retrieval.email_body', {
168 mail_body = t('registration.password_retrieval.email_body', {
169 :full_name => user.full_name,
169 :full_name => user.full_name,
170 :contest_name => contest_name,
170 :contest_name => contest_name,
171 :login => user.login,
171 :login => user.login,
172 :password => user.password,
172 :password => user.password,
173 - :admin_email => admin_email
173 + :admin_email => GraderConfiguration['system.admin_email']
174 })
174 })
175
175
176 logger.info mail_body
176 logger.info mail_body
177
177
178 send_mail(user.email, mail_subject, mail_body)
178 send_mail(user.email, mail_subject, mail_body)
179 end
179 end
180
180
181 # allow viewing of regular user profile only when options allow so
181 # allow viewing of regular user profile only when options allow so
182 # only admins can view admins profile
182 # only admins can view admins profile
183 def profile_authorization
183 def profile_authorization
184 #if view admins' profile, allow only admin
184 #if view admins' profile, allow only admin
185 return false unless(params[:id])
185 return false unless(params[:id])
186 user = User.find(params[:id])
186 user = User.find(params[:id])
187 return false unless user
187 return false unless user
188 return admin_authorization if user.admin?
188 return admin_authorization if user.admin?
189 return true if GraderConfiguration["right.user_view_submission"]
189 return true if GraderConfiguration["right.user_view_submission"]
190
190
191 #finally, we allow only admin
191 #finally, we allow only admin
192 admin_authorization
192 admin_authorization
193 end
193 end
194
194
195 end
195 end
@@ -97,42 +97,42
97 end
97 end
98 end
98 end
99
99
100 #
100 #
101 # if the contest is in the anaysis mode
101 # if the contest is in the anaysis mode
102 if GraderConfiguration.analysis_mode?
102 if GraderConfiguration.analysis_mode?
103 header = <<ANALYSISMODE
103 header = <<ANALYSISMODE
104 <tr><td colspan="2" align="center">
104 <tr><td colspan="2" align="center">
105 <span class="contest-over-msg">ANALYSIS MODE</span>
105 <span class="contest-over-msg">ANALYSIS MODE</span>
106 </td></tr>
106 </td></tr>
107 ANALYSISMODE
107 ANALYSISMODE
108 end
108 end
109
109
110 contest_name = GraderConfiguration['contest.name']
110 contest_name = GraderConfiguration['contest.name']
111
111
112 #
112 #
113 # build real title bar
113 # build real title bar
114 result = <<TITLEBAR
114 result = <<TITLEBAR
115 <div class="title">
115 <div class="title">
116 <table>
116 <table>
117 #{header}
117 #{header}
118 <tr>
118 <tr>
119 <td class="left-col">
119 <td class="left-col">
120 #{user.full_name}<br/>
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 #{time_left}
122 #{time_left}
123 <br/>
123 <br/>
124 </td>
124 </td>
125 <td class="right-col">#{contest_name}</td>
125 <td class="right-col">#{contest_name}</td>
126 </tr>
126 </tr>
127 </table>
127 </table>
128 </div>
128 </div>
129 TITLEBAR
129 TITLEBAR
130 result.html_safe
130 result.html_safe
131 end
131 end
132
132
133 def markdown(text)
133 def markdown(text)
134 markdown = RDiscount.new(text)
134 markdown = RDiscount.new(text)
135 markdown.to_html.html_safe
135 markdown.to_html.html_safe
136 end
136 end
137
137
138 end
138 end
@@ -24,99 +24,99
24
24
25 if !problem.errors.empty?
25 if !problem.errors.empty?
26 return problem, 'Error importing'
26 return problem, 'Error importing'
27 end
27 end
28
28
29 problem.full_score = 100
29 problem.full_score = 100
30 problem.date_added = Time.new
30 problem.date_added = Time.new
31 problem.test_allowed = true
31 problem.test_allowed = true
32 problem.output_only = false
32 problem.output_only = false
33 problem.available = false
33 problem.available = false
34
34
35 if not problem.save
35 if not problem.save
36 return problem, 'Error importing'
36 return problem, 'Error importing'
37 end
37 end
38
38
39 import_to_db = params.has_key? :import_to_db
39 import_to_db = params.has_key? :import_to_db
40
40
41 importer = TestdataImporter.new(problem)
41 importer = TestdataImporter.new(problem)
42
42
43 if not importer.import_from_file(import_params[:file],
43 if not importer.import_from_file(import_params[:file],
44 import_params[:time_limit],
44 import_params[:time_limit],
45 import_params[:memory_limit],
45 import_params[:memory_limit],
46 import_params[:checker_name],
46 import_params[:checker_name],
47 import_to_db)
47 import_to_db)
48 - problem.errors.add_to_base('Import error.')
48 + problem.errors.add(:base,'Import error.')
49 end
49 end
50
50
51 return problem, importer.log_msg
51 return problem, importer.log_msg
52 end
52 end
53
53
54 def self.download_file_basedir
54 def self.download_file_basedir
55 return "#{Rails.root}/data/tasks"
55 return "#{Rails.root}/data/tasks"
56 end
56 end
57
57
58 def get_submission_stat
58 def get_submission_stat
59 result = Hash.new
59 result = Hash.new
60 #total number of submission
60 #total number of submission
61 result[:total_sub] = Submission.where(problem_id: self.id).count
61 result[:total_sub] = Submission.where(problem_id: self.id).count
62 result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
62 result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
63 end
63 end
64
64
65 protected
65 protected
66
66
67 def self.to_i_or_default(st, default)
67 def self.to_i_or_default(st, default)
68 if st!=''
68 if st!=''
69 result = st.to_i
69 result = st.to_i
70 end
70 end
71 result ||= default
71 result ||= default
72 end
72 end
73
73
74 def self.to_f_or_default(st, default)
74 def self.to_f_or_default(st, default)
75 if st!=''
75 if st!=''
76 result = st.to_f
76 result = st.to_f
77 end
77 end
78 result ||= default
78 result ||= default
79 end
79 end
80
80
81 def self.extract_params_and_check(params, problem)
81 def self.extract_params_and_check(params, problem)
82 time_limit = Problem.to_f_or_default(params[:time_limit],
82 time_limit = Problem.to_f_or_default(params[:time_limit],
83 DEFAULT_TIME_LIMIT)
83 DEFAULT_TIME_LIMIT)
84 memory_limit = Problem.to_i_or_default(params[:memory_limit],
84 memory_limit = Problem.to_i_or_default(params[:memory_limit],
85 DEFAULT_MEMORY_LIMIT)
85 DEFAULT_MEMORY_LIMIT)
86
86
87 if time_limit<=0 or time_limit >60
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 end
89 end
90
90
91 if memory_limit==0 and params[:memory_limit]!='0'
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 elsif memory_limit<=0 or memory_limit >512
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 end
95 end
96
96
97 if params[:file]==nil or params[:file]==''
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 end
99 end
100
100
101 checker_name = 'text'
101 checker_name = 'text'
102 if ['text','float'].include? params[:checker]
102 if ['text','float'].include? params[:checker]
103 checker_name = params[:checker]
103 checker_name = params[:checker]
104 end
104 end
105
105
106 file = params[:file]
106 file = params[:file]
107
107
108 if !problem.errors.empty?
108 if !problem.errors.empty?
109 return nil, problem
109 return nil, problem
110 end
110 end
111
111
112 problem.name = params[:name]
112 problem.name = params[:name]
113 if params[:full_name]!=''
113 if params[:full_name]!=''
114 problem.full_name = params[:full_name]
114 problem.full_name = params[:full_name]
115 else
115 else
116 problem.full_name = params[:name]
116 problem.full_name = params[:name]
117 end
117 end
118
118
119 return [{
119 return [{
120 :time_limit => time_limit,
120 :time_limit => time_limit,
121 :memory_limit => memory_limit,
121 :memory_limit => memory_limit,
122 :file => file,
122 :file => file,
@@ -49,54 +49,54
49 test_request
49 test_request
50 end
50 end
51
51
52 # interfacing with form
52 # interfacing with form
53 def self.new_from_form_params(user,params)
53 def self.new_from_form_params(user,params)
54 test_request = TestRequest.new
54 test_request = TestRequest.new
55 test_request.user = user
55 test_request.user = user
56 begin
56 begin
57 problem = Problem.find(params[:problem_id])
57 problem = Problem.find(params[:problem_id])
58 rescue ActiveRecord::RecordNotFound
58 rescue ActiveRecord::RecordNotFound
59 problem = nil
59 problem = nil
60 end
60 end
61 test_request.problem = problem
61 test_request.problem = problem
62 if problem!=nil
62 if problem!=nil
63 test_request.submission =
63 test_request.submission =
64 Submission.find_by_user_problem_number(user.id,
64 Submission.find_by_user_problem_number(user.id,
65 problem.id,
65 problem.id,
66 params[:submission_number])
66 params[:submission_number])
67 else
67 else
68 test_request.submission = nil
68 test_request.submission = nil
69 end
69 end
70
70
71 # checks if the user submits any input file
71 # checks if the user submits any input file
72 if params[:input_file]==nil or params[:input_file]==""
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 test_request.input_file_name = nil
74 test_request.input_file_name = nil
75 else
75 else
76 test_request.input_file_name = save_input_file(params[:input_file], user, problem)
76 test_request.input_file_name = save_input_file(params[:input_file], user, problem)
77 if test_request.input_file_name == nil
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 end
79 end
80 if params[:additional_file]!=nil and params[:additional_file]!=""
80 if params[:additional_file]!=nil and params[:additional_file]!=""
81 save_additional_file(params[:additional_file],
81 save_additional_file(params[:additional_file],
82 "#{test_request.input_file_name}.files")
82 "#{test_request.input_file_name}.files")
83 end
83 end
84 end
84 end
85 test_request.submitted_at = Time.new.gmtime
85 test_request.submitted_at = Time.new.gmtime
86 test_request.status_inqueue
86 test_request.status_inqueue
87 test_request
87 test_request
88 end
88 end
89
89
90 protected
90 protected
91
91
92 def self.name_of(problem)
92 def self.name_of(problem)
93 if problem!=nil
93 if problem!=nil
94 problem.name
94 problem.name
95 else
95 else
96 "default"
96 "default"
97 end
97 end
98 end
98 end
99
99
100 def self.random_input_file_name(user,problem)
100 def self.random_input_file_name(user,problem)
101 problem_name = TestRequest.name_of(problem)
101 problem_name = TestRequest.name_of(problem)
102 begin
102 begin
@@ -46,53 +46,53
46 :if => :email_validation?
46 :if => :email_validation?
47 validate :uniqueness_of_email_from_activated_users,
47 validate :uniqueness_of_email_from_activated_users,
48 :if => :email_validation?
48 :if => :email_validation?
49 validate :enough_time_interval_between_same_email_registrations,
49 validate :enough_time_interval_between_same_email_registrations,
50 :if => :email_validation?
50 :if => :email_validation?
51
51
52 # these are for ytopc
52 # these are for ytopc
53 # disable for now
53 # disable for now
54 #validates_presence_of :province
54 #validates_presence_of :province
55
55
56 attr_accessor :password
56 attr_accessor :password
57
57
58 before_save :encrypt_new_password
58 before_save :encrypt_new_password
59 before_save :assign_default_site
59 before_save :assign_default_site
60 before_save :assign_default_contest
60 before_save :assign_default_contest
61
61
62 # this is for will_paginate
62 # this is for will_paginate
63 cattr_reader :per_page
63 cattr_reader :per_page
64 @@per_page = 50
64 @@per_page = 50
65
65
66 def self.authenticate(login, password)
66 def self.authenticate(login, password)
67 user = find_by_login(login)
67 user = find_by_login(login)
68 if user
68 if user
69 return user if user.authenticated?(password)
69 return user if user.authenticated?(password)
70 - # if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
70 + if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 - # user.password = password
71 + user.password = password
72 - # user.save
72 + user.save
73 - # return user
73 + return user
74 - # end
74 + end
75 end
75 end
76 end
76 end
77
77
78 def authenticated?(password)
78 def authenticated?(password)
79 if self.activated
79 if self.activated
80 hashed_password == User.encrypt(password,self.salt)
80 hashed_password == User.encrypt(password,self.salt)
81 else
81 else
82 false
82 false
83 end
83 end
84 end
84 end
85
85
86 def authenticated_by_pop3?(password)
86 def authenticated_by_pop3?(password)
87 Net::POP3.enable_ssl
87 Net::POP3.enable_ssl
88 pop = Net::POP3.new('pops.it.chula.ac.th')
88 pop = Net::POP3.new('pops.it.chula.ac.th')
89 authen = true
89 authen = true
90 begin
90 begin
91 pop.start(login, password)
91 pop.start(login, password)
92 pop.finish
92 pop.finish
93 return true
93 return true
94 rescue
94 rescue
95 return false
95 return false
96 end
96 end
97 end
97 end
98
98
@@ -330,47 +330,47
330 def assign_default_contest
330 def assign_default_contest
331 # have to catch error when migrating (because self.site is not available).
331 # have to catch error when migrating (because self.site is not available).
332 begin
332 begin
333 if self.contests.length == 0
333 if self.contests.length == 0
334 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
334 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
335 if default_contest
335 if default_contest
336 self.contests = [default_contest]
336 self.contests = [default_contest]
337 end
337 end
338 end
338 end
339 rescue
339 rescue
340 end
340 end
341 end
341 end
342
342
343 def password_required?
343 def password_required?
344 self.hashed_password.blank? || !self.password.blank?
344 self.hashed_password.blank? || !self.password.blank?
345 end
345 end
346
346
347 def self.encrypt(string,salt)
347 def self.encrypt(string,salt)
348 Digest::SHA1.hexdigest(salt + string)
348 Digest::SHA1.hexdigest(salt + string)
349 end
349 end
350
350
351 def uniqueness_of_email_from_activated_users
351 def uniqueness_of_email_from_activated_users
352 user = User.activated_users.find_by_email(self.email)
352 user = User.activated_users.find_by_email(self.email)
353 if user and (user.login != self.login)
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 end
355 end
356 end
356 end
357
357
358 def enough_time_interval_between_same_email_registrations
358 def enough_time_interval_between_same_email_registrations
359 return if !self.new_record?
359 return if !self.new_record?
360 return if self.activated
360 return if self.activated
361 open_user = User.find_by_email(self.email,
361 open_user = User.find_by_email(self.email,
362 :order => 'created_at DESC')
362 :order => 'created_at DESC')
363 if open_user and open_user.created_at and
363 if open_user and open_user.created_at and
364 (open_user.created_at > Time.now.gmtime - 5.minutes)
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 end
366 end
367 end
367 end
368
368
369 def email_validation?
369 def email_validation?
370 begin
370 begin
371 return VALIDATE_USER_EMAILS
371 return VALIDATE_USER_EMAILS
372 rescue
372 rescue
373 return false
373 return false
374 end
374 end
375 end
375 end
376 end
376 end
@@ -1,29 +1,32
1 + - content_for :header do
2 + = javascript_include_tag 'local_jquery'
3 +
1 %h1 System configuration
4 %h1 System configuration
2
5
3 %table.info
6 %table.info
4 %tr.info-head
7 %tr.info-head
5 %th Key
8 %th Key
6 %th Type
9 %th Type
7 %th Value
10 %th Value
8 %th Description
11 %th Description
9 - @configurations.each do |conf|
12 - @configurations.each do |conf|
10 - @grader_configuration = conf
13 - @grader_configuration = conf
11 %tr{:class => cycle("info-odd", "info-even")}
14 %tr{:class => cycle("info-odd", "info-even")}
12 %td
15 %td
13 = in_place_editor_field :grader_configuration, :key, {}, :rows=>1
16 = in_place_editor_field :grader_configuration, :key, {}, :rows=>1
14 %td
17 %td
15 = in_place_editor_field :grader_configuration, :value_type, {}, :rows=>1
18 = in_place_editor_field :grader_configuration, :value_type, {}, :rows=>1
16 %td
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 %td= conf.description
21 %td= conf.description
19
22
20 - if GraderConfiguration.config_cached?
23 - if GraderConfiguration.config_cached?
21 %br/
24 %br/
22 Your config is saved, but it does not automatically take effect.
25 Your config is saved, but it does not automatically take effect.
23 %br/
26 %br/
24 If you have one mongrel process running, you can
27 If you have one mongrel process running, you can
25 = link_to '[click]', :action => 'reload'
28 = link_to '[click]', :action => 'reload'
26 here to reload.
29 here to reload.
27 %br/
30 %br/
28 If you have more than one process running, you should restart
31 If you have more than one process running, you should restart
29 them manually.
32 them manually.
@@ -1,31 +1,34
1 %h1 Contest management
1 %h1 Contest management
2
2
3 .infobox
3 .infobox
4
4
5 - if @num_contests>1
5 - if @num_contests>1
6 %b Multiple contests:
6 %b Multiple contests:
7 = "There are #{@num_contests} contests running."
7 = "There are #{@num_contests} contests running."
8 - else
8 - else
9 %b Single contest:
9 %b Single contest:
10 =raw "[#{link_to 'Add/remove contests', :controller => 'contests', :action => 'index'}]"
10 =raw "[#{link_to 'Add/remove contests', :controller => 'contests', :action => 'index'}]"
11
11
12 .infobox
12 .infobox
13 %b Web interface mode:
13 %b Web interface mode:
14 - - if (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
14 + - if GraderConfiguration.analysis_mode?
15 - standard mode
15 + Analysis Mode
16 + - elsif (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
17 + Standard Mode
16 - elsif GraderConfiguration.contest_mode?
18 - elsif GraderConfiguration.contest_mode?
17 - normal contest mode.
19 + Normal Contest Mode
18 - else
20 - else
19 - individual contest mode.
21 + Individual Contest Mode
20
22
21 %br/
23 %br/
22 Change mode to:
24 Change mode to:
23 - =raw "[#{link_to 'standard', :action => 'change_contest_mode', :id => 'standard'}]"
25 + =raw "[#{link_to 'Standard', :action => 'change_contest_mode', :id => 'standard'}]"
24 - =raw "[#{link_to 'contest', :action => 'change_contest_mode', :id => 'contest'}]"
26 + =raw "[#{link_to 'Contest', :action => 'change_contest_mode', :id => 'contest'}]"
25 - =raw "[#{link_to 'individual contest', :action => 'change_contest_mode', :id => 'indv-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 - if GraderConfiguration.indv_contest_mode?
30 - if GraderConfiguration.indv_contest_mode?
28 = render :partial => 'indv_contest_mode_index'
31 = render :partial => 'indv_contest_mode_index'
29
32
30 %br/
33 %br/
31
34
@@ -1,26 +1,27
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'graders'
2 = stylesheet_link_tag 'graders'
3 + = javascript_include_tag 'local_jquery'
3 <meta http-equiv ="refresh" content="60"/>
4 <meta http-equiv ="refresh" content="60"/>
4
5
5 %h1 Grader information
6 %h1 Grader information
6
7
7 = link_to '[Refresh]', :action => 'list'
8 = link_to '[Refresh]', :action => 'list'
8 %br/
9 %br/
9
10
10 .submitbox
11 .submitbox
11 .item
12 .item
12 Grader control:
13 Grader control:
13 .item
14 .item
14 = form_for :clear, :url => {:action => 'start_grading'} do |f|
15 = form_for :clear, :url => {:action => 'start_grading'} do |f|
15 = submit_tag 'Start graders in grading env'
16 = submit_tag 'Start graders in grading env'
16 .item
17 .item
17 = form_for :clear, :url => {:action => 'start_exam'} do |f|
18 = form_for :clear, :url => {:action => 'start_exam'} do |f|
18 = submit_tag 'Start graders in exam env'
19 = submit_tag 'Start graders in exam env'
19 .item
20 .item
20 = form_for :clear, :url => {:action => 'stop_all'} do |f|
21 = form_for :clear, :url => {:action => 'stop_all'} do |f|
21 = submit_tag 'Stop all running graders'
22 = submit_tag 'Stop all running graders'
22 .item
23 .item
23 = form_for :clear, :url => {:action => 'clear_all'} do |f|
24 = form_for :clear, :url => {:action => 'clear_all'} do |f|
24 = submit_tag 'Clear all data'
25 = submit_tag 'Clear all data'
25 %br{:style => 'clear:both'}/
26 %br{:style => 'clear:both'}/
26
27
@@ -45,28 +46,28
45
46
46 %h2 Terminated graders
47 %h2 Terminated graders
47
48
48 = form_for :clear, :url => {:action => 'clear_terminated'} do |f|
49 = form_for :clear, :url => {:action => 'clear_terminated'} do |f|
49 = submit_tag 'Clear data for terminated graders'
50 = submit_tag 'Clear data for terminated graders'
50
51
51 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
52 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
52 %div{}
53 %div{}
53 %h2 Last 20 submissions
54 %h2 Last 20 submissions
54 %table.graders
55 %table.graders
55 %thead
56 %thead
56 %th ID
57 %th ID
57 %th User
58 %th User
58 %th Problem
59 %th Problem
59 %th Submitted
60 %th Submitted
60 %th Graded
61 %th Graded
61 %th Result
62 %th Result
62 %tbody
63 %tbody
63 - @submission.each do |sub|
64 - @submission.each do |sub|
64 %tr.inactive
65 %tr.inactive
65 %td= link_to sub.id, controller: 'graders' ,action: 'submission', id: sub.id
66 %td= link_to sub.id, controller: 'graders' ,action: 'submission', id: sub.id
66 %td= sub.try(:user).try(:full_name)
67 %td= sub.try(:user).try(:full_name)
67 %td= sub.try(:problem).try(:full_name)
68 %td= sub.try(:problem).try(:full_name)
68 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
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 %td= sub.grader_comment
71 %td= sub.grader_comment
71
72
72
73
@@ -4,37 +4,37
4 User:
4 User:
5 = "#{@test_request.user.login}"
5 = "#{@test_request.user.login}"
6 %br/
6 %br/
7 Problem:
7 Problem:
8 - if @test_request.problem!=nil
8 - if @test_request.problem!=nil
9 = "#{@test_request.problem.full_name}"
9 = "#{@test_request.problem.full_name}"
10 - else
10 - else
11 = "(n/a)"
11 = "(n/a)"
12 %br/
12 %br/
13 = "Submission: #{@test_request.submission.number}"
13 = "Submission: #{@test_request.submission.number}"
14 = link_to '[view submission]', :action => 'submission', :id => @test_request.submission.id
14 = link_to '[view submission]', :action => 'submission', :id => @test_request.submission.id
15 %br/
15 %br/
16 = "Test submitted at: #{format_short_time(@test_request.submitted_at)}"
16 = "Test submitted at: #{format_short_time(@test_request.submitted_at)}"
17 %br/
17 %br/
18 = "Execution time: #{@test_request.running_time} s."
18 = "Execution time: #{@test_request.running_time} s."
19 %br/
19 %br/
20 = "Memory usage: #{@test_request.memory_usage}kb"
20 = "Memory usage: #{@test_request.memory_usage}kb"
21 %br/
21 %br/
22 %b= @test_request.exit_status
22 %b= @test_request.exit_status
23 %br/
23 %br/
24
24
25 - if @test_request.compiler_message!=nil and @test_request.compiler_message!=''
25 - if @test_request.compiler_message!=nil and @test_request.compiler_message!=''
26 %b Compiler Message
26 %b Compiler Message
27 %div{:style => "border: 1px solid black; background: lightgrey"}
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 %b Input (first 2kb)
30 %b Input (first 2kb)
31 %div{:style => "border: 1px solid black; background: lightgrey"}
31 %div{:style => "border: 1px solid black; background: lightgrey"}
32 - if @test_request.input_file_name!=nil
32 - if @test_request.input_file_name!=nil
33 = simple_format(read_textfile(@test_request.input_file_name,2048))
33 = simple_format(read_textfile(@test_request.input_file_name,2048))
34
34
35 %b Output (first 2kb)
35 %b Output (first 2kb)
36 %div{:style => "border: 1px solid black; background: lightgrey"}
36 %div{:style => "border: 1px solid black; background: lightgrey"}
37 - if @test_request.output_file_name!=nil
37 - if @test_request.output_file_name!=nil
38 = simple_format(read_textfile(@test_request.output_file_name,2048))
38 = simple_format(read_textfile(@test_request.output_file_name,2048))
39 - else
39 - else
40 (no output)
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 No message
3 No message
4 <% else %>
4 <% else %>
5 <div><div><a href="#" onClick="n = this.parentNode.parentNode.lastChild;
5 <div><div><a href="#" onClick="n = this.parentNode.parentNode.lastChild;
6 if(n.style.display == 'none') { n.style.display = 'block'; }
6 if(n.style.display == 'none') { n.style.display = 'block'; }
7 else {n.style.display ='none'; } return false;">
7 else {n.style.display ='none'; } return false;">
8 (click to see)</a>
8 (click to see)</a>
9 </div>
9 </div>
10 <div style="display: none">
10 <div style="display: none">
11 <div class="compilermsgbody" style="border: thin solid grey; margin: 2px">
11 <div class="compilermsgbody" style="border: thin solid grey; margin: 2px">
12 <%=simple_format(compiler_message) %>
12 <%=simple_format(compiler_message) %>
13 </div>
13 </div>
14 </div></div>
14 </div></div>
15 <% end %>
15 <% end %>
@@ -1,20 +1,24
1
1
2 %tr{:class => ((submission_counter%2==0) ? "info-even" : "info-odd")}
2 %tr{:class => ((submission_counter%2==0) ? "info-even" : "info-odd")}
3 %td.info{:align => "center"}
3 %td.info{:align => "center"}
4 = submission_counter+1
4 = submission_counter+1
5 %td.info{:align => "center"}
5 %td.info{:align => "center"}
6 = link_to "##{submission.id}", controller: :graders, action: :submission, id: submission.id
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 %td.info{:align => "center"}
10 %td.info{:align => "center"}
11 + = submission.source_filename
12 + = " (#{submission.language.pretty_name}) "
9 = link_to('[load]',{:action => 'source', :id => submission.id})
13 = link_to('[load]',{:action => 'source', :id => submission.id})
10 %td.info
14 %td.info
11 - if submission.graded_at!=nil
15 - if submission.graded_at!=nil
12 = "Graded at #{format_short_time(submission.graded_at)}."
16 = "Graded at #{format_short_time(submission.graded_at)}."
13 %br/
17 %br/
14 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
15 = " ["
19 = " ["
16 %tt
20 %tt
17 = submission.grader_comment
21 = submission.grader_comment
18 = "]"
22 = "]"
19 %td.info
23 %td.info
20 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
@@ -1,6 +1,6
1 %h2= "Compiler message for submission \##{@submission.number}, task: #{@submission.problem.name}"
1 %h2= "Compiler message for submission \##{@submission.number}, task: #{@submission.problem.name}"
2 %p
2 %p
3 - - if @submission.compiler_message.chomp == ''
3 + - if @submission.compiler_message == nil or @submission.compiler_message.chomp == ''
4 - no message
4 + No message
5 - else
5 - else
6 = simple_format(@submission.compiler_message)
6 = simple_format(@submission.compiler_message)
@@ -1,16 +1,16
1 = user_title_bar(@user)
1 = user_title_bar(@user)
2
2
3 .announcementbox
3 .announcementbox
4 %span{:class => 'title'}
4 %span{:class => 'title'}
5 =t 'main.confirm_contest_start.box_title'
5 =t 'main.confirm_contest_start.box_title'
6 .announcement
6 .announcement
7 %center
7 %center
8 =t 'main.confirm_contest_start.contest_list'
8 =t 'main.confirm_contest_start.contest_list'
9 - @contests.each do |contest|
9 - @contests.each do |contest|
10 = contest.title
10 = contest.title
11 %br
11 %br
12
12
13 =t 'main.confirm_contest_start.timer_starts_after_click'
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 = submit_tag t('main.confirm_contest_start.start_button'), :confirm => t('main.confirm_contest_start.start_button_confirm')
16 = submit_tag t('main.confirm_contest_start.start_button'), :confirm => t('main.confirm_contest_start.start_button_confirm')
@@ -1,19 +1,18
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3
3
4 %h1 Import problems: successful
4 %h1 Import problems: successful
5
5
6 %p
6 %p
7 %b Problem:
7 %b Problem:
8 = "#{@problem.full_name} (#{@problem.name})"
8 = "#{@problem.full_name} (#{@problem.name})"
9 %br/
9 %br/
10 - Note that the full score has be assigned to the default value, 100.
10 + = "Note that the full score has been set to #{@problem.full_score}."
11 - You should change it to the correct full score.
12
11
13 %p
12 %p
14 = link_to '[Back to problem list]', :action => 'list'
13 = link_to '[Back to problem list]', :action => 'list'
15 = link_to '[Import other problems]', :action => 'import'
14 = link_to '[Import other problems]', :action => 'import'
16
15
17 %h3 Import log
16 %h3 Import log
18 %pre.import-log
17 %pre.import-log
19 = @log
18 = @log
@@ -1,36 +1,35
1 - content_for :header do
1 - content_for :header do
2 = javascript_include_tag 'local_jquery'
2 = javascript_include_tag 'local_jquery'
3
3
4 :javascript
4 :javascript
5 $(document).ready( function() {
5 $(document).ready( function() {
6 $("#mem_remark").hover( function() {
6 $("#mem_remark").hover( function() {
7 $("#mem_remark_box").show();
7 $("#mem_remark_box").show();
8 }, function() {
8 }, function() {
9 $("#mem_remark_box").hide();
9 $("#mem_remark_box").hide();
10 });
10 });
11 });
11 });
12 - alert("hahaha");
13 :css
12 :css
14 .hof_user { color: orangered; font-style: italic; }
13 .hof_user { color: orangered; font-style: italic; }
15 .hof_language { color: green; font-style: italic; }
14 .hof_language { color: green; font-style: italic; }
16 .hof_value { color: deeppink;font-style: italic; }
15 .hof_value { color: deeppink;font-style: italic; }
17 .info_param { font-weight: bold;text-align: right; }
16 .info_param { font-weight: bold;text-align: right; }
18 .tooltip {
17 .tooltip {
19 font-family: Verdana,sans-serif;
18 font-family: Verdana,sans-serif;
20 font-weight: normal;
19 font-weight: normal;
21 text-align: left;
20 text-align: left;
22 font-size: 1.0em;
21 font-size: 1.0em;
23 color: black;
22 color: black;
24 line-height: 1.1;
23 line-height: 1.1;
25 display: none;
24 display: none;
26 min-width: 20em;
25 min-width: 20em;
27 position: absolute;
26 position: absolute;
28 left: 25px;
27 left: 25px;
29 bottom: 5px;
28 bottom: 5px;
30 border: 1px solid;
29 border: 1px solid;
31 padding: 5px;
30 padding: 5px;
32 background-color: #FFF;
31 background-color: #FFF;
33 word-wrap: break-word;
32 word-wrap: break-word;
34 z-index: 9999;
33 z-index: 9999;
35 overflow: auto;
34 overflow: auto;
36 }
35 }
@@ -1,22 +1,25
1 <%= error_messages_for 'user' %>
1 <%= error_messages_for 'user' %>
2
2
3 <!--[form:user]-->
3 <!--[form:user]-->
4 <p><label for="user_name">Login</label><br/>
4 <p><label for="user_name">Login</label><br/>
5 <%= text_field 'user', 'login' %></p>
5 <%= text_field 'user', 'login' %></p>
6
6
7 <p><label for="user_name">Full name</label><br/>
7 <p><label for="user_name">Full name</label><br/>
8 <%= text_field 'user', 'full_name' %></p>
8 <%= text_field 'user', 'full_name' %></p>
9
9
10 <p><label for="password">Password</label><br/>
10 <p><label for="password">Password</label><br/>
11 <%= password_field 'user', 'password' %></p>
11 <%= password_field 'user', 'password' %></p>
12
12
13 <p><label for="password_confirmation">Password (confirm)</label><br/>
13 <p><label for="password_confirmation">Password (confirm)</label><br/>
14 <%= password_field 'user', 'password_confirmation' %></p>
14 <%= password_field 'user', 'password_confirmation' %></p>
15
15
16 <p><label for="user_email">E-mail</label><br/>
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 <p><label for="user_alias">Alias</label><br/>
19 <p><label for="user_alias">Alias</label><br/>
20 <%= text_field 'user', 'alias' %></p>
20 <%= text_field 'user', 'alias' %></p>
21 +
22 + <p><label for="user_remark">Remark</label><br/>
23 + <%= text_field 'user', 'remark' %></p>
21 <!--[eoform:user]-->
24 <!--[eoform:user]-->
22
25
@@ -1,43 +1,43
1 <h1>Listing users</h1>
1 <h1>Listing users</h1>
2
2
3 <div class="submitbox">
3 <div class="submitbox">
4 <b>Quick add</b>
4 <b>Quick add</b>
5 <%= form_tag :action => 'create' do %>
5 <%= form_tag :action => 'create' do %>
6 <table border="0">
6 <table border="0">
7 <tr>
7 <tr>
8 <td><label for="user_login">Login</label></td>
8 <td><label for="user_login">Login</label></td>
9 <td><label for="user_full_name">Full name</label></td>
9 <td><label for="user_full_name">Full name</label></td>
10 <td><label for="user_password">Password</label></td>
10 <td><label for="user_password">Password</label></td>
11 <td><label for="user_password_confirmation">Confirm</label></td>
11 <td><label for="user_password_confirmation">Confirm</label></td>
12 <td><label for="user_email">Email</label></td>
12 <td><label for="user_email">Email</label></td>
13 </tr>
13 </tr>
14 <tr>
14 <tr>
15 <td><%= text_field 'user', 'login', :size => 10 %></td>
15 <td><%= text_field 'user', 'login', :size => 10 %></td>
16 <td><%= text_field 'user', 'full_name', :size => 30 %></td>
16 <td><%= text_field 'user', 'full_name', :size => 30 %></td>
17 <td><%= password_field 'user', 'password', :size => 10 %></td>
17 <td><%= password_field 'user', 'password', :size => 10 %></td>
18 <td><%= password_field 'user', 'password_confirmation', :size => 10 %></td>
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 <td><%= submit_tag "Create" %></td>
20 <td><%= submit_tag "Create" %></td>
21 </tr>
21 </tr>
22 </table>
22 </table>
23 <% end %>
23 <% end %>
24 <br/>
24 <br/>
25 <b>Import from site management</b>
25 <b>Import from site management</b>
26 <%= form_tag({:action => 'import'}, :multipart => true) do %>
26 <%= form_tag({:action => 'import'}, :multipart => true) do %>
27 File: <%= file_field_tag 'file' %> <%= submit_tag 'Import' %>
27 File: <%= file_field_tag 'file' %> <%= submit_tag 'Import' %>
28 <% end %>
28 <% end %>
29 <br/>
29 <br/>
30 <b>What else: </b>
30 <b>What else: </b>
31 <%= link_to '[New user]', :action => 'new' %>
31 <%= link_to '[New user]', :action => 'new' %>
32 <%= link_to '[New list of users]', :action => 'new_list' %>
32 <%= link_to '[New list of users]', :action => 'new_list' %>
33 <%= link_to '[View administrators]', :action => 'admin' %>
33 <%= link_to '[View administrators]', :action => 'admin' %>
34 <%= link_to '[Random passwords]', :action => 'random_all_passwords' %>
34 <%= link_to '[Random passwords]', :action => 'random_all_passwords' %>
35 <%= link_to '[View active users]', :action => 'active' %>
35 <%= link_to '[View active users]', :action => 'active' %>
36 <%= link_to '[Mass mailing]', :action => 'mass_mailing' %>
36 <%= link_to '[Mass mailing]', :action => 'mass_mailing' %>
37 <% if GraderConfiguration.multicontests? %>
37 <% if GraderConfiguration.multicontests? %>
38 <br/><b>Multi-contest:</b>
38 <br/><b>Multi-contest:</b>
39 <%= link_to '[Manage bulk users in contests]', :action => 'contest_management' %>
39 <%= link_to '[Manage bulk users in contests]', :action => 'contest_management' %>
40 View users in:
40 View users in:
41 <% @contests.each do |contest| %>
41 <% @contests.each do |contest| %>
42 <%= link_to "[#{contest.name}]", :action => 'contests', :id => contest.id %>
42 <%= link_to "[#{contest.name}]", :action => 'contests', :id => contest.id %>
43 <% end %>
43 <% end %>
@@ -13,47 +13,47
13 %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range"
13 %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range"
14
14
15
15
16 - if @problem and @problem.errors
16 - if @problem and @problem.errors
17 =error_messages_for 'problem'
17 =error_messages_for 'problem'
18
18
19 = render partial: 'submission_range'
19 = render partial: 'submission_range'
20
20
21 - if params[:action] == 'user_stat'
21 - if params[:action] == 'user_stat'
22 %h3 Latest score
22 %h3 Latest score
23 = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat, commit: 'download csv'
23 = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat, commit: 'download csv'
24 - else
24 - else
25 %h3 Max score
25 %h3 Max score
26 = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
26 = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
27 = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat_max, commit: 'download csv'
27 = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat_max, commit: 'download csv'
28
28
29 %table.tablesorter-cafe#my_table
29 %table.tablesorter-cafe#my_table
30 %thead
30 %thead
31 %tr
31 %tr
32 %th User
32 %th User
33 %th Name
33 %th Name
34 %th Activated?
34 %th Activated?
35 %th Logged in
35 %th Logged in
36 %th Contest(s)
36 %th Contest(s)
37 - %th Section
37 + %th Remark
38 - @problems.each do |p|
38 - @problems.each do |p|
39 %th= p.name
39 %th= p.name
40 %th Total
40 %th Total
41 %th Passed
41 %th Passed
42 %tbody
42 %tbody
43 - @scorearray.each do |sc|
43 - @scorearray.each do |sc|
44 %tr{class: cycle('info-even','info-odd')}
44 %tr{class: cycle('info-even','info-odd')}
45 - total,num_passed = 0,0
45 - total,num_passed = 0,0
46 - sc.each_index do |i|
46 - sc.each_index do |i|
47 - if i == 0
47 - if i == 0
48 %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i]
48 %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i]
49 %td= sc[i].full_name
49 %td= sc[i].full_name
50 %td= sc[i].activated
50 %td= sc[i].activated
51 %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
51 %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
52 %td= sc[i].contests.collect {|c| c.name}.join(', ')
52 %td= sc[i].contests.collect {|c| c.name}.join(', ')
53 - %td= sc[i].section
53 + %td= sc[i].remark
54 - else
54 - else
55 %td= sc[i][0]
55 %td= sc[i][0]
56 - total += sc[i][0]
56 - total += sc[i][0]
57 - num_passed += 1 if sc[i][1]
57 - num_passed += 1 if sc[i][1]
58 %td= total
58 %td= total
59 %td= num_passed
59 %td= num_passed
@@ -1,18 +1,19
1 .contest-title
1 .contest-title
2 %h1
2 %h1
3 = "#{GraderConfiguration['contest.name']}: #{t 'registration.password_retrieval.header'}"
3 = "#{GraderConfiguration['contest.name']}: #{t 'registration.password_retrieval.header'}"
4
4
5 - if flash[:notice]
5 - if flash[:notice]
6 %hr/
6 %hr/
7 %b= flash[:notice]
7 %b= flash[:notice]
8 %hr/
8 %hr/
9
9
10 %br/
10 %br/
11
11
12 = form_tag :action => 'retrieve_password' do
12 = form_tag :action => 'retrieve_password' do
13 =t 'registration.password_retrieval.instructions'
13 =t 'registration.password_retrieval.instructions'
14 - = text_field 'email', nil, :size => 20
14 + %br/
15 + = email_field 'email', nil, :size => 20
15 %br/
16 %br/
16 = submit_tag(t 'registration.password_retrieval.button_label')
17 = submit_tag(t 'registration.password_retrieval.button_label')
17
18
18 = link_to "#{t 'go_back_to'}#{t 'home_page'}", :controller => 'main', :action => 'index'
19 = link_to "#{t 'go_back_to'}#{t 'home_page'}", :controller => 'main', :action => 'index'
@@ -4,36 +4,36
4
4
5 .registration-desc
5 .registration-desc
6 =t 'registration.description'
6 =t 'registration.description'
7
7
8 = error_messages_for :user, :header_message => (t 'registration.errors.header')
8 = error_messages_for :user, :header_message => (t 'registration.errors.header')
9
9
10 %table
10 %table
11 = form_for @user, :url => { :action => 'register' } do |f|
11 = form_for @user, :url => { :action => 'register' } do |f|
12 %tr
12 %tr
13 %td{:align => "right"}
13 %td{:align => "right"}
14 = "#{t 'login_label'}:"
14 = "#{t 'login_label'}:"
15 %td= f.text_field :login
15 %td= f.text_field :login
16 %tr
16 %tr
17 %td
17 %td
18 %td
18 %td
19 %small
19 %small
20 =t 'registration.login_guide'
20 =t 'registration.login_guide'
21 %tr
21 %tr
22 %td{:align => "right"}
22 %td{:align => "right"}
23 = "#{t 'full_name_label'}:"
23 = "#{t 'full_name_label'}:"
24 %td= f.text_field :full_name
24 %td= f.text_field :full_name
25 %tr
25 %tr
26 %td{:align => "right"}
26 %td{:align => "right"}
27 = "#{t 'email_label'}:"
27 = "#{t 'email_label'}:"
28 - %td= f.text_field :email
28 + %td= f.email_field :email
29 %tr
29 %tr
30 %td
30 %td
31 %td
31 %td
32 %small
32 %small
33 - =t 'registration.email_guide'
33 + =t('registration.email_guide').html_safe
34 %tr
34 %tr
35 %td/
35 %td/
36 %td
36 %td
37 = submit_tag((t 'registration.register'), :name => 'commit')
37 = submit_tag((t 'registration.register'), :name => 'commit')
38 = submit_tag((t 'cancel'), :name => 'cancel')
38 = submit_tag((t 'cancel'), :name => 'cancel')
39
39
@@ -13,25 +13,28
13 config.consider_all_requests_local = true
13 config.consider_all_requests_local = true
14 config.action_controller.perform_caching = false
14 config.action_controller.perform_caching = false
15
15
16 # Don't care if the mailer can't send
16 # Don't care if the mailer can't send
17 config.action_mailer.raise_delivery_errors = false
17 config.action_mailer.raise_delivery_errors = false
18
18
19 # Print deprecation notices to the Rails logger
19 # Print deprecation notices to the Rails logger
20 config.active_support.deprecation = :log
20 config.active_support.deprecation = :log
21
21
22 # Only use best-standards-support built into browsers
22 # Only use best-standards-support built into browsers
23 config.action_dispatch.best_standards_support = :builtin
23 config.action_dispatch.best_standards_support = :builtin
24
24
25 # Raise exception on mass assignment protection for Active Record models
25 # Raise exception on mass assignment protection for Active Record models
26 config.active_record.mass_assignment_sanitizer = :strict
26 config.active_record.mass_assignment_sanitizer = :strict
27
27
28 # Log the query plan for queries taking more than this (works
28 # Log the query plan for queries taking more than this (works
29 # with SQLite, MySQL, and PostgreSQL)
29 # with SQLite, MySQL, and PostgreSQL)
30 config.active_record.auto_explain_threshold_in_seconds = 0.5
30 config.active_record.auto_explain_threshold_in_seconds = 0.5
31
31
32 # Do not compress assets
32 # Do not compress assets
33 config.assets.compress = false
33 config.assets.compress = false
34
34
35 # Expands the lines which load the assets
35 # Expands the lines which load the assets
36 config.assets.debug = true
36 config.assets.debug = true
37 +
38 + # Prevents assets from rendering twice
39 + config.serve_static_assets = false
37 end
40 end
@@ -1,37 +1,37
1 # Sample localization file for English. Add more files in this directory for other locales.
1 # Sample localization file for English. Add more files in this directory for other locales.
2 # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
2 # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3
3
4 en:
4 en:
5 cancel: 'Cancel'
5 cancel: 'Cancel'
6
6
7 login_label: 'Login'
7 login_label: 'Login'
8 full_name_label: 'Full name'
8 full_name_label: 'Full name'
9 email_label: 'E-mail'
9 email_label: 'E-mail'
10 password_label: 'Password'
10 password_label: 'Password'
11
11
12 - go_ahead_to: "Go ahead to"
12 + go_ahead_to: "Go ahead to "
13 - go_back_to: "Go back to"
13 + go_back_to: "Go back to "
14 login_page: "login page"
14 login_page: "login page"
15 home_page: "home page"
15 home_page: "home page"
16
16
17 menu:
17 menu:
18 main: 'Main'
18 main: 'Main'
19 messages: 'Messages'
19 messages: 'Messages'
20 tasks: 'Tasks'
20 tasks: 'Tasks'
21 submissions: 'Submissions'
21 submissions: 'Submissions'
22 test: 'Test Interface'
22 test: 'Test Interface'
23 hall_of_fame: 'Hall of Fame'
23 hall_of_fame: 'Hall of Fame'
24 help: 'Help'
24 help: 'Help'
25 settings: 'Settings'
25 settings: 'Settings'
26 log_out: 'Log out'
26 log_out: 'Log out'
27
27
28 title_bar:
28 title_bar:
29 current_time: "Current time is"
29 current_time: "Current time is"
30 remaining_time: "Time left: "
30 remaining_time: "Time left: "
31 contest_not_started: "The contest has not started."
31 contest_not_started: "The contest has not started."
32
32
33 login:
33 login:
34 message: 'Please login to see the problem list'
34 message: 'Please login to see the problem list'
35 login_submit: 'Login'
35 login_submit: 'Login'
36 participation: 'Want to participate?'
36 participation: 'Want to participate?'
37 please: 'Please'
37 please: 'Please'
@@ -1,32 +1,34
1 CafeGrader::Application.routes.draw do
1 CafeGrader::Application.routes.draw do
2 get "report/login"
2 get "report/login"
3
3
4 resources :contests
4 resources :contests
5
5
6 resources :announcements
6 resources :announcements
7 resources :sites
7 resources :sites
8
8
9 + resources :grader_configuration, controller: 'configurations'
10 +
9 # The priority is based upon order of creation:
11 # The priority is based upon order of creation:
10 # first created -> highest priority.
12 # first created -> highest priority.
11
13
12 # Sample of regular route:
14 # Sample of regular route:
13 # match 'products/:id' => 'catalog#view'
15 # match 'products/:id' => 'catalog#view'
14 # Keep in mind you can assign values other than :controller and :action
16 # Keep in mind you can assign values other than :controller and :action
15
17
16 # Sample of named route:
18 # Sample of named route:
17 # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
19 # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase
18 # This route can be invoked with purchase_url(:id => product.id)
20 # This route can be invoked with purchase_url(:id => product.id)
19
21
20 # Sample resource route (maps HTTP verbs to controller actions automatically):
22 # Sample resource route (maps HTTP verbs to controller actions automatically):
21 # resources :products
23 # resources :products
22
24
23 # Sample resource route with options:
25 # Sample resource route with options:
24 # resources :products do
26 # resources :products do
25 # member do
27 # member do
26 # get 'short'
28 # get 'short'
27 # post 'toggle'
29 # post 'toggle'
28 # end
30 # end
29 #
31 #
30 # collection do
32 # collection do
31 # get 'sold'
33 # get 'sold'
32 # end
34 # end
@@ -1,38 +1,38
1 # encoding: UTF-8
1 # encoding: UTF-8
2 # This file is auto-generated from the current state of the database. Instead
2 # This file is auto-generated from the current state of the database. Instead
3 # of editing this file, please use the migrations feature of Active Record to
3 # of editing this file, please use the migrations feature of Active Record to
4 # incrementally modify your database, and then regenerate this schema definition.
4 # incrementally modify your database, and then regenerate this schema definition.
5 #
5 #
6 # Note that this schema.rb definition is the authoritative source for your
6 # Note that this schema.rb definition is the authoritative source for your
7 # database schema. If you need to create the application database on another
7 # database schema. If you need to create the application database on another
8 # system, you should be using db:schema:load, not running all the migrations
8 # system, you should be using db:schema:load, not running all the migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 #
11 #
12 # It's strongly recommended to check this file into your version control system.
12 # It's strongly recommended to check this file into your version control system.
13
13
14 - ActiveRecord::Schema.define(:version => 20140917150629) do
14 + ActiveRecord::Schema.define(:version => 20150203153534) do
15
15
16 create_table "announcements", :force => true do |t|
16 create_table "announcements", :force => true do |t|
17 t.string "author"
17 t.string "author"
18 t.text "body"
18 t.text "body"
19 t.boolean "published"
19 t.boolean "published"
20 t.datetime "created_at", :null => false
20 t.datetime "created_at", :null => false
21 t.datetime "updated_at", :null => false
21 t.datetime "updated_at", :null => false
22 t.boolean "frontpage", :default => false
22 t.boolean "frontpage", :default => false
23 t.boolean "contest_only", :default => false
23 t.boolean "contest_only", :default => false
24 t.string "title"
24 t.string "title"
25 t.string "notes"
25 t.string "notes"
26 end
26 end
27
27
28 create_table "contests", :force => true do |t|
28 create_table "contests", :force => true do |t|
29 t.string "title"
29 t.string "title"
30 t.boolean "enabled"
30 t.boolean "enabled"
31 t.datetime "created_at", :null => false
31 t.datetime "created_at", :null => false
32 t.datetime "updated_at", :null => false
32 t.datetime "updated_at", :null => false
33 t.string "name"
33 t.string "name"
34 end
34 end
35
35
36 create_table "contests_problems", :id => false, :force => true do |t|
36 create_table "contests_problems", :id => false, :force => true do |t|
37 t.integer "contest_id"
37 t.integer "contest_id"
38 t.integer "problem_id"
38 t.integer "problem_id"
@@ -218,30 +218,31
218 end
218 end
219
219
220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
221
221
222 create_table "user_contest_stats", :force => true do |t|
222 create_table "user_contest_stats", :force => true do |t|
223 t.integer "user_id"
223 t.integer "user_id"
224 t.datetime "started_at"
224 t.datetime "started_at"
225 t.datetime "created_at", :null => false
225 t.datetime "created_at", :null => false
226 t.datetime "updated_at", :null => false
226 t.datetime "updated_at", :null => false
227 t.boolean "forced_logout"
227 t.boolean "forced_logout"
228 end
228 end
229
229
230 create_table "users", :force => true do |t|
230 create_table "users", :force => true do |t|
231 t.string "login", :limit => 50
231 t.string "login", :limit => 50
232 t.string "full_name"
232 t.string "full_name"
233 t.string "hashed_password"
233 t.string "hashed_password"
234 t.string "salt", :limit => 5
234 t.string "salt", :limit => 5
235 t.string "alias"
235 t.string "alias"
236 t.string "email"
236 t.string "email"
237 t.integer "site_id"
237 t.integer "site_id"
238 t.integer "country_id"
238 t.integer "country_id"
239 t.boolean "activated", :default => false
239 t.boolean "activated", :default => false
240 t.datetime "created_at"
240 t.datetime "created_at"
241 t.datetime "updated_at"
241 t.datetime "updated_at"
242 - t.string "section"
242 + t.boolean "enabled", :default => true
243 + t.string "remark"
243 end
244 end
244
245
245 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
246 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
246
247
247 end
248 end
@@ -79,49 +79,49
79 {
79 {
80 :key => 'system.online_registration.from',
80 :key => 'system.online_registration.from',
81 :value_type => 'string',
81 :value_type => 'string',
82 :default_value => 'your.email@address'
82 :default_value => 'your.email@address'
83 },
83 },
84
84
85 {
85 {
86 :key => 'system.admin_email',
86 :key => 'system.admin_email',
87 :value_type => 'string',
87 :value_type => 'string',
88 :default_value => 'admin@admin.email'
88 :default_value => 'admin@admin.email'
89 },
89 },
90
90
91 {
91 {
92 :key => 'system.user_setting_enabled',
92 :key => 'system.user_setting_enabled',
93 :value_type => 'boolean',
93 :value_type => 'boolean',
94 :default_value => 'true',
94 :default_value => 'true',
95 :description => 'If this option is true, users can change their settings'
95 :description => 'If this option is true, users can change their settings'
96 },
96 },
97
97
98 {
98 {
99 :key => 'system.user_setting_enabled',
99 :key => 'system.user_setting_enabled',
100 :value_type => 'boolean',
100 :value_type => 'boolean',
101 :default_value => 'true',
101 :default_value => 'true',
102 :description => 'If this option is true, users can change their settings'
102 :description => 'If this option is true, users can change their settings'
103 - }
103 + },
104
104
105 # If Configuration['contest.test_request.early_timeout'] is true
105 # If Configuration['contest.test_request.early_timeout'] is true
106 # the user will not be able to use test request at 30 minutes
106 # the user will not be able to use test request at 30 minutes
107 # before the contest ends.
107 # before the contest ends.
108 {
108 {
109 :key => 'contest.test_request.early_timeout',
109 :key => 'contest.test_request.early_timeout',
110 :value_type => 'boolean',
110 :value_type => 'boolean',
111 :default_value => 'false'
111 :default_value => 'false'
112 },
112 },
113
113
114 {
114 {
115 :key => 'system.multicontests',
115 :key => 'system.multicontests',
116 :value_type => 'boolean',
116 :value_type => 'boolean',
117 :default_value => 'false'
117 :default_value => 'false'
118 },
118 },
119
119
120 {
120 {
121 :key => 'contest.confirm_indv_contest_start',
121 :key => 'contest.confirm_indv_contest_start',
122 :value_type => 'boolean',
122 :value_type => 'boolean',
123 :default_value => 'false'
123 :default_value => 'false'
124 },
124 },
125
125
126 {
126 {
127 :key => 'contest.default_contest_name',
127 :key => 'contest.default_contest_name',
@@ -1,30 +1,41
1 module MailHelperMethods
1 module MailHelperMethods
2
2
3 def send_mail(mail_to, mail_subject, mail_body)
3 def send_mail(mail_to, mail_subject, mail_body)
4 mail_from = GraderConfiguration['system.online_registration.from']
4 mail_from = GraderConfiguration['system.online_registration.from']
5 smtp_server = GraderConfiguration['system.online_registration.smtp']
5 smtp_server = GraderConfiguration['system.online_registration.smtp']
6
6
7 if ['fake', 'debug'].include? smtp_server
7 if ['fake', 'debug'].include? smtp_server
8 puts "-------------------------
8 puts "-------------------------
9 To: #{mail_to}
9 To: #{mail_to}
10 From: #{mail_from}
10 From: #{mail_from}
11 Subject: #{mail_subject}
11 Subject: #{mail_subject}
12 #{mail_body}
12 #{mail_body}
13 --------------------------
13 --------------------------
14 "
14 "
15 return true
15 return true
16 end
16 end
17
17
18 mail = Mail.new do
18 mail = Mail.new do
19 from mail_from
19 from mail_from
20 to mail_to
20 to mail_to
21 subject mail_subject
21 subject mail_subject
22 body mail_body
22 body mail_body
23 end
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 mail.deliver
37 mail.deliver
27 end
38 end
28
39
29 end
40 end
30
41
deleted file
You need to be logged in to leave comments. Login now