Description:
add problem group
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r672:d41325ea3a15 - - 20 files changed: 364 inserted, 9 deleted

@@ -0,0 +1,86
1 + class GroupsController < ApplicationController
2 + before_action :set_group, only: [:show, :edit, :update, :destroy,
3 + :add_user, :remove_user,
4 + :add_problem, :remove_problem,
5 + ]
6 + before_action :authenticate, :admin_authorization
7 +
8 + # GET /groups
9 + def index
10 + @groups = Group.all
11 + end
12 +
13 + # GET /groups/1
14 + def show
15 + end
16 +
17 + # GET /groups/new
18 + def new
19 + @group = Group.new
20 + end
21 +
22 + # GET /groups/1/edit
23 + def edit
24 + end
25 +
26 + # POST /groups
27 + def create
28 + @group = Group.new(group_params)
29 +
30 + if @group.save
31 + redirect_to @group, notice: 'Group was successfully created.'
32 + else
33 + render :new
34 + end
35 + end
36 +
37 + # PATCH/PUT /groups/1
38 + def update
39 + if @group.update(group_params)
40 + redirect_to @group, notice: 'Group was successfully updated.'
41 + else
42 + render :edit
43 + end
44 + end
45 +
46 + # DELETE /groups/1
47 + def destroy
48 + @group.destroy
49 + redirect_to groups_url, notice: 'Group was successfully destroyed.'
50 + end
51 +
52 + def remove_user
53 + user = User.find(params[:user_id])
54 + @group.users.delete(user)
55 + redirect_to group_path(@group), notice: "User #{user.login} was removed from the group #{@group.name}"
56 + end
57 +
58 + def add_user
59 + user = User.find(params[:user_id])
60 + @group.users << user
61 + redirect_to group_path(@group), notice: "User #{user.login} was add to the group #{@group.name}"
62 + end
63 +
64 + def remove_problem
65 + problem = Problem.find(params[:problem_id])
66 + @group.problems.delete(problem)
67 + redirect_to group_path(@group), notice: "Problem #{problem.name} was removed from the group #{@group.name}"
68 + end
69 +
70 + def add_problem
71 + problem = Problem.find(params[:problem_id])
72 + @group.problems << problem
73 + redirect_to group_path(@group), notice: "Problem #{problem.name} was add to the group #{@group.name}"
74 + end
75 +
76 + private
77 + # Use callbacks to share common setup or constraints between actions.
78 + def set_group
79 + @group = Group.find(params[:id])
80 + end
81 +
82 + # Only allow a trusted parameter "white list" through.
83 + def group_params
84 + params.require(:group).permit(:name, :description)
85 + end
86 + end
@@ -0,0 +1,2
1 + module GroupsHelper
2 + end
@@ -0,0 +1,5
1 + class Group < ActiveRecord::Base
2 + has_and_belongs_to_many :problems
3 + has_and_belongs_to_many :users
4 + end
5 +
@@ -0,0 +1,16
1 + = form_for @group do |f|
2 + - if @group.errors.any?
3 + #error_explanation
4 + %h2= "#{pluralize(@group.errors.count, "error")} prohibited this group from being saved:"
5 + %ul
6 + - @group.errors.full_messages.each do |msg|
7 + %li= msg
8 +
9 + .form-group.field
10 + = f.label :name
11 + = f.text_field :name, class: 'form-control'
12 + .form-group.field
13 + = f.label :description
14 + = f.text_field :description, class: 'form-control'
15 + .form-group.actions
16 + = f.submit 'Save', class: 'btn btn-primary'
@@ -0,0 +1,7
1 + %h1 Editing group
2 +
3 + = render 'form'
4 +
5 + = link_to 'Show', @group
6 + \|
7 + = link_to 'Back', groups_path
@@ -0,0 +1,24
1 + %h1 Groups
2 +
3 + %p
4 + = link_to 'New Group', new_group_path, class: 'btn btn-primary'
5 + %table.table.table-hover
6 + %thead
7 + %tr
8 + %th Name
9 + %th Description
10 + %th
11 + %th
12 + %th
13 +
14 + %tbody
15 + - @groups.each do |group|
16 + %tr
17 + %td= group.name
18 + %td= group.description
19 + %td= link_to 'Show', group, class: 'btn btn-default'
20 + %td= link_to 'Edit', edit_group_path(group), class: 'btn btn-default'
21 + %td= link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
22 +
23 + %br
24 +
@@ -0,0 +1,5
1 + %h1 New group
2 +
3 + = render 'form'
4 +
5 + = link_to 'Back', groups_path
@@ -0,0 +1,67
1 + %p#notice= notice
2 +
3 + %p
4 + %b Name:
5 + = @group.name
6 + %p
7 + %b Description:
8 + = @group.description
9 +
10 + %br
11 + = link_to 'Edit', edit_group_path(@group)
12 + \|
13 + = link_to 'Back', groups_path
14 +
15 + .row
16 + .col-md-6
17 + %h1 Users in this group
18 +
19 + =form_tag add_user_group_path(@group), class: 'form-inline' do
20 + .form-group
21 + =label_tag :user_id, "User"
22 + =select_tag :user_id, options_from_collection_for_select(User.all,'id','full_name'), class: 'select2'
23 + =submit_tag "Add",class: 'btn btn-primary'
24 +
25 +
26 + %table.table.table-hover
27 + %thead
28 + %tr
29 + %th Login
30 + %th Full name
31 + %th Remark
32 + %th
33 +
34 + %tbody
35 + - @group.users.each do |user|
36 + %tr
37 + %td= user.login
38 + %td= user.full_name
39 + %td= user.remark
40 + %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger'
41 + .col-md-6
42 + %h1 Problems in this group
43 +
44 + =form_tag add_problem_group_path(@group), class: 'form-inline' do
45 + .form-group
46 + =label_tag :problem_id, "Problem"
47 + =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','full_name'), class: 'select2'
48 + =submit_tag "Add",class: 'btn btn-primary'
49 +
50 +
51 + %table.table.table-hover
52 + %thead
53 + %tr
54 + %th name
55 + %th Full name
56 + %th Full score
57 + %th
58 +
59 + %tbody
60 + - @group.problems.each do |problem|
61 + %tr
62 + %td= problem.name
63 + %td= problem.full_name
64 + %td= problem.full_score
65 + %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger'
66 +
67 +
@@ -0,0 +1,30
1 + class CreateGroups < ActiveRecord::Migration
2 +
3 + def change
4 + create_table :groups do |t|
5 + t.string :name
6 + t.string :description
7 + end
8 +
9 + create_join_table :groups, :users do |t|
10 + # t.index [:group_id, :user_id]
11 + t.index [:user_id, :group_id]
12 + end
13 +
14 + create_join_table :problems, :groups do |t|
15 + # t.index [:problem_id, :group_id]
16 + t.index [:group_id, :problem_id]
17 + end
18 +
19 + reversible do |change|
20 + change.up do
21 + GraderConfiguration.where(key: 'system.use_problem_group').first_or_create(value_type: 'boolean', value: 'false',
22 + description: 'If true, available problem to the user will be only ones associated with the group of the user');
23 + end
24 +
25 + change.down do
26 + GraderConfiguration.where(key: 'system.use_problem_group').destroy_all
27 + end
28 + end
29 + end
30 + end
@@ -0,0 +1,49
1 + require 'test_helper'
2 +
3 + class GroupsControllerTest < ActionController::TestCase
4 + setup do
5 + @group = groups(:one)
6 + end
7 +
8 + test "should get index" do
9 + get :index
10 + assert_response :success
11 + assert_not_nil assigns(:groups)
12 + end
13 +
14 + test "should get new" do
15 + get :new
16 + assert_response :success
17 + end
18 +
19 + test "should create group" do
20 + assert_difference('Group.count') do
21 + post :create, group: { description: @group.description, name: @group.name }
22 + end
23 +
24 + assert_redirected_to group_path(assigns(:group))
25 + end
26 +
27 + test "should show group" do
28 + get :show, id: @group
29 + assert_response :success
30 + end
31 +
32 + test "should get edit" do
33 + get :edit, id: @group
34 + assert_response :success
35 + end
36 +
37 + test "should update group" do
38 + patch :update, id: @group, group: { description: @group.description, name: @group.name }
39 + assert_redirected_to group_path(assigns(:group))
40 + end
41 +
42 + test "should destroy group" do
43 + assert_difference('Group.count', -1) do
44 + delete :destroy, id: @group
45 + end
46 +
47 + assert_redirected_to groups_path
48 + end
49 + end
@@ -102,192 +102,197
102 File.delete out_filename
102 File.delete out_filename
103 end
103 end
104
104
105 File.open(out_filename,"wb") do |file|
105 File.open(out_filename,"wb") do |file|
106 file.write(params[:file].read)
106 file.write(params[:file].read)
107 end
107 end
108 @problem.description_filename = "#{@problem.name}.pdf"
108 @problem.description_filename = "#{@problem.name}.pdf"
109 @problem.save
109 @problem.save
110 end
110 end
111 redirect_to :action => 'show', :id => @problem
111 redirect_to :action => 'show', :id => @problem
112 else
112 else
113 render :action => 'edit'
113 render :action => 'edit'
114 end
114 end
115 end
115 end
116
116
117 def destroy
117 def destroy
118 p = Problem.find(params[:id]).destroy
118 p = Problem.find(params[:id]).destroy
119 redirect_to action: :index
119 redirect_to action: :index
120 end
120 end
121
121
122 def toggle
122 def toggle
123 @problem = Problem.find(params[:id])
123 @problem = Problem.find(params[:id])
124 @problem.update_attributes(available: !(@problem.available) )
124 @problem.update_attributes(available: !(@problem.available) )
125 respond_to do |format|
125 respond_to do |format|
126 format.js { }
126 format.js { }
127 end
127 end
128 end
128 end
129
129
130 def toggle_test
130 def toggle_test
131 @problem = Problem.find(params[:id])
131 @problem = Problem.find(params[:id])
132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
133 respond_to do |format|
133 respond_to do |format|
134 format.js { }
134 format.js { }
135 end
135 end
136 end
136 end
137
137
138 def toggle_view_testcase
138 def toggle_view_testcase
139 @problem = Problem.find(params[:id])
139 @problem = Problem.find(params[:id])
140 @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
140 @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
141 respond_to do |format|
141 respond_to do |format|
142 format.js { }
142 format.js { }
143 end
143 end
144 end
144 end
145
145
146 def turn_all_off
146 def turn_all_off
147 Problem.available.all.each do |problem|
147 Problem.available.all.each do |problem|
148 problem.available = false
148 problem.available = false
149 problem.save
149 problem.save
150 end
150 end
151 redirect_to action: :index
151 redirect_to action: :index
152 end
152 end
153
153
154 def turn_all_on
154 def turn_all_on
155 Problem.where.not(available: true).each do |problem|
155 Problem.where.not(available: true).each do |problem|
156 problem.available = true
156 problem.available = true
157 problem.save
157 problem.save
158 end
158 end
159 redirect_to action: :index
159 redirect_to action: :index
160 end
160 end
161
161
162 def stat
162 def stat
163 @problem = Problem.find(params[:id])
163 @problem = Problem.find(params[:id])
164 unless @problem.available or session[:admin]
164 unless @problem.available or session[:admin]
165 redirect_to :controller => 'main', :action => 'list'
165 redirect_to :controller => 'main', :action => 'list'
166 return
166 return
167 end
167 end
168 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
168 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
169
169
170 #stat summary
170 #stat summary
171 range =65
171 range =65
172 @histogram = { data: Array.new(range,0), summary: {} }
172 @histogram = { data: Array.new(range,0), summary: {} }
173 user = Hash.new(0)
173 user = Hash.new(0)
174 @submissions.find_each do |sub|
174 @submissions.find_each do |sub|
175 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
175 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
176 @histogram[:data][d.to_i] += 1 if d < range
176 @histogram[:data][d.to_i] += 1 if d < range
177 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
177 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
178 end
178 end
179 @histogram[:summary][:max] = [@histogram[:data].max,1].max
179 @histogram[:summary][:max] = [@histogram[:data].max,1].max
180
180
181 @summary = { attempt: user.count, solve: 0 }
181 @summary = { attempt: user.count, solve: 0 }
182 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
182 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
183 end
183 end
184
184
185 def manage
185 def manage
186 @problems = Problem.order(date_added: :desc)
186 @problems = Problem.order(date_added: :desc)
187 end
187 end
188
188
189 def do_manage
189 def do_manage
190 if params.has_key? 'change_date_added'
190 if params.has_key? 'change_date_added'
191 change_date_added
191 change_date_added
192 elsif params.has_key? 'add_to_contest'
192 elsif params.has_key? 'add_to_contest'
193 add_to_contest
193 add_to_contest
194 elsif params.has_key? 'enable_problem'
194 elsif params.has_key? 'enable_problem'
195 set_available(true)
195 set_available(true)
196 elsif params.has_key? 'disable_problem'
196 elsif params.has_key? 'disable_problem'
197 set_available(false)
197 set_available(false)
198 + elsif params.has_key? 'add_group'
199 + group = Group.find(params[:group_id])
200 + get_problems_from_params.each do |p|
201 + group.problems << p
202 + end
198 end
203 end
199 redirect_to :action => 'manage'
204 redirect_to :action => 'manage'
200 end
205 end
201
206
202 def import
207 def import
203 @allow_test_pair_import = allow_test_pair_import?
208 @allow_test_pair_import = allow_test_pair_import?
204 end
209 end
205
210
206 def do_import
211 def do_import
207 old_problem = Problem.find_by_name(params[:name])
212 old_problem = Problem.find_by_name(params[:name])
208 if !allow_test_pair_import? and params.has_key? :import_to_db
213 if !allow_test_pair_import? and params.has_key? :import_to_db
209 params.delete :import_to_db
214 params.delete :import_to_db
210 end
215 end
211 @problem, import_log = Problem.create_from_import_form_params(params,
216 @problem, import_log = Problem.create_from_import_form_params(params,
212 old_problem)
217 old_problem)
213
218
214 if !@problem.errors.empty?
219 if !@problem.errors.empty?
215 render :action => 'import' and return
220 render :action => 'import' and return
216 end
221 end
217
222
218 if old_problem!=nil
223 if old_problem!=nil
219 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
224 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
220 end
225 end
221 @log = import_log
226 @log = import_log
222 end
227 end
223
228
224 def remove_contest
229 def remove_contest
225 problem = Problem.find(params[:id])
230 problem = Problem.find(params[:id])
226 contest = Contest.find(params[:contest_id])
231 contest = Contest.find(params[:contest_id])
227 if problem!=nil and contest!=nil
232 if problem!=nil and contest!=nil
228 problem.contests.delete(contest)
233 problem.contests.delete(contest)
229 end
234 end
230 redirect_to :action => 'manage'
235 redirect_to :action => 'manage'
231 end
236 end
232
237
233 ##################################
238 ##################################
234 protected
239 protected
235
240
236 def allow_test_pair_import?
241 def allow_test_pair_import?
237 if defined? ALLOW_TEST_PAIR_IMPORT
242 if defined? ALLOW_TEST_PAIR_IMPORT
238 return ALLOW_TEST_PAIR_IMPORT
243 return ALLOW_TEST_PAIR_IMPORT
239 else
244 else
240 return false
245 return false
241 end
246 end
242 end
247 end
243
248
244 def change_date_added
249 def change_date_added
245 problems = get_problems_from_params
250 problems = get_problems_from_params
246 year = params[:date_added][:year].to_i
251 year = params[:date_added][:year].to_i
247 month = params[:date_added][:month].to_i
252 month = params[:date_added][:month].to_i
248 day = params[:date_added][:day].to_i
253 day = params[:date_added][:day].to_i
249 date = Date.new(year,month,day)
254 date = Date.new(year,month,day)
250 problems.each do |p|
255 problems.each do |p|
251 p.date_added = date
256 p.date_added = date
252 p.save
257 p.save
253 end
258 end
254 end
259 end
255
260
256 def add_to_contest
261 def add_to_contest
257 problems = get_problems_from_params
262 problems = get_problems_from_params
258 contest = Contest.find(params[:contest][:id])
263 contest = Contest.find(params[:contest][:id])
259 if contest!=nil and contest.enabled
264 if contest!=nil and contest.enabled
260 problems.each do |p|
265 problems.each do |p|
261 p.contests << contest
266 p.contests << contest
262 end
267 end
263 end
268 end
264 end
269 end
265
270
266 def set_available(avail)
271 def set_available(avail)
267 problems = get_problems_from_params
272 problems = get_problems_from_params
268 problems.each do |p|
273 problems.each do |p|
269 p.available = avail
274 p.available = avail
270 p.save
275 p.save
271 end
276 end
272 end
277 end
273
278
274 def get_problems_from_params
279 def get_problems_from_params
275 problems = []
280 problems = []
276 params.keys.each do |k|
281 params.keys.each do |k|
277 if k.index('prob-')==0
282 if k.index('prob-')==0
278 name, id, order = k.split('-')
283 name, id, order = k.split('-')
279 problems << Problem.find(id)
284 problems << Problem.find(id)
280 end
285 end
281 end
286 end
282 problems
287 problems
283 end
288 end
284
289
285 def get_problems_stat
290 def get_problems_stat
286 end
291 end
287
292
288 private
293 private
289
294
290 def problem_params
295 def problem_params
291 params.require(:problem).permit(:name, :full_name, :full_score, :date_added, :available, :test_allowed,:output_only, :url, :description)
296 params.require(:problem).permit(:name, :full_name, :full_score, :date_added, :available, :test_allowed,:output_only, :url, :description)
292 end
297 end
293
298
@@ -347,196 +347,195
347 admin_role = Role.find_by_name('admin')
347 admin_role = Role.find_by_name('admin')
348 user.roles << admin_role
348 user.roles << admin_role
349 else
349 else
350 flash[:notice] = 'Unknown user'
350 flash[:notice] = 'Unknown user'
351 end
351 end
352 flash[:notice] = 'User added as admins'
352 flash[:notice] = 'User added as admins'
353 redirect_to :action => 'admin'
353 redirect_to :action => 'admin'
354 end
354 end
355
355
356 def revoke_admin
356 def revoke_admin
357 user = User.find(params[:id])
357 user = User.find(params[:id])
358 if user==nil
358 if user==nil
359 flash[:notice] = 'Unknown user'
359 flash[:notice] = 'Unknown user'
360 redirect_to :action => 'admin' and return
360 redirect_to :action => 'admin' and return
361 elsif user.login == 'root'
361 elsif user.login == 'root'
362 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
362 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
363 redirect_to :action => 'admin' and return
363 redirect_to :action => 'admin' and return
364 end
364 end
365
365
366 admin_role = Role.find_by_name('admin')
366 admin_role = Role.find_by_name('admin')
367 user.roles.delete(admin_role)
367 user.roles.delete(admin_role)
368 flash[:notice] = 'User permission revoked'
368 flash[:notice] = 'User permission revoked'
369 redirect_to :action => 'admin'
369 redirect_to :action => 'admin'
370 end
370 end
371
371
372 # mass mailing
372 # mass mailing
373
373
374 def mass_mailing
374 def mass_mailing
375 end
375 end
376
376
377 def bulk_mail
377 def bulk_mail
378 lines = params[:login_list]
378 lines = params[:login_list]
379 if !lines or lines.blank?
379 if !lines or lines.blank?
380 flash[:notice] = 'You entered an empty list.'
380 flash[:notice] = 'You entered an empty list.'
381 redirect_to :action => 'mass_mailing' and return
381 redirect_to :action => 'mass_mailing' and return
382 end
382 end
383
383
384 mail_subject = params[:subject]
384 mail_subject = params[:subject]
385 if !mail_subject or mail_subject.blank?
385 if !mail_subject or mail_subject.blank?
386 flash[:notice] = 'You entered an empty mail subject.'
386 flash[:notice] = 'You entered an empty mail subject.'
387 redirect_to :action => 'mass_mailing' and return
387 redirect_to :action => 'mass_mailing' and return
388 end
388 end
389
389
390 mail_body = params[:email_body]
390 mail_body = params[:email_body]
391 if !mail_body or mail_body.blank?
391 if !mail_body or mail_body.blank?
392 flash[:notice] = 'You entered an empty mail body.'
392 flash[:notice] = 'You entered an empty mail body.'
393 redirect_to :action => 'mass_mailing' and return
393 redirect_to :action => 'mass_mailing' and return
394 end
394 end
395
395
396 note = []
396 note = []
397 users = []
397 users = []
398 lines.split("\n").each do |line|
398 lines.split("\n").each do |line|
399 user = User.find_by_login(line.chomp)
399 user = User.find_by_login(line.chomp)
400 if user
400 if user
401 send_mail(user.email, mail_subject, mail_body)
401 send_mail(user.email, mail_subject, mail_body)
402 note << user.login
402 note << user.login
403 end
403 end
404 end
404 end
405
405
406 flash[:notice] = 'User(s) ' + note.join(', ') +
406 flash[:notice] = 'User(s) ' + note.join(', ') +
407 ' were successfully modified. '
407 ' were successfully modified. '
408 redirect_to :action => 'mass_mailing'
408 redirect_to :action => 'mass_mailing'
409 end
409 end
410
410
411 #bulk manage
411 #bulk manage
412 def bulk_manage
412 def bulk_manage
413
413
414 begin
414 begin
415 @users = User.where('login REGEXP ?',params[:regex]) if params[:regex]
415 @users = User.where('login REGEXP ?',params[:regex]) if params[:regex]
416 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
416 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
417 rescue Exception
417 rescue Exception
418 flash[:error] = 'Regular Expression is malformed'
418 flash[:error] = 'Regular Expression is malformed'
419 @users = nil
419 @users = nil
420 end
420 end
421
421
422 if params[:commit]
422 if params[:commit]
423 @action = {}
423 @action = {}
424 @action[:set_enable] = params[:enabled]
424 @action[:set_enable] = params[:enabled]
425 @action[:enabled] = params[:enable] == "1"
425 @action[:enabled] = params[:enable] == "1"
426 @action[:gen_password] = params[:gen_password]
426 @action[:gen_password] = params[:gen_password]
427 @action[:add_group] = params[:add_group]
427 @action[:add_group] = params[:add_group]
428 @action[:group_name] = params[:group_name]
428 @action[:group_name] = params[:group_name]
429 end
429 end
430
430
431 if params[:commit] == "Perform"
431 if params[:commit] == "Perform"
432 if @action[:set_enable]
432 if @action[:set_enable]
433 @users.update_all(enabled: @action[:enabled])
433 @users.update_all(enabled: @action[:enabled])
434 end
434 end
435 if @action[:gen_password]
435 if @action[:gen_password]
436 @users.each do |u|
436 @users.each do |u|
437 password = random_password
437 password = random_password
438 u.password = password
438 u.password = password
439 u.password_confirmation = password
439 u.password_confirmation = password
440 u.save
440 u.save
441 end
441 end
442 end
442 end
443 - if @action[:add_group]
443 + if @action[:add_group] and @action[:group_name]
444 - @uses.each do |u|
444 + @group = Group.find(@action[:group_name])
445 -
445 + @users.each { |user| @group.users << user }
446 - end
447 end
446 end
448 end
447 end
449 end
448 end
450
449
451 protected
450 protected
452
451
453 def random_password(length=5)
452 def random_password(length=5)
454 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
453 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
455 newpass = ""
454 newpass = ""
456 length.times { newpass << chars[rand(chars.size-1)] }
455 length.times { newpass << chars[rand(chars.size-1)] }
457 return newpass
456 return newpass
458 end
457 end
459
458
460 def import_from_file(f)
459 def import_from_file(f)
461 data_hash = YAML.load(f)
460 data_hash = YAML.load(f)
462 @import_log = ""
461 @import_log = ""
463
462
464 country_data = data_hash[:countries]
463 country_data = data_hash[:countries]
465 site_data = data_hash[:sites]
464 site_data = data_hash[:sites]
466 user_data = data_hash[:users]
465 user_data = data_hash[:users]
467
466
468 # import country
467 # import country
469 countries = {}
468 countries = {}
470 country_data.each_pair do |id,country|
469 country_data.each_pair do |id,country|
471 c = Country.find_by_name(country[:name])
470 c = Country.find_by_name(country[:name])
472 if c!=nil
471 if c!=nil
473 countries[id] = c
472 countries[id] = c
474 @import_log << "Found #{country[:name]}\n"
473 @import_log << "Found #{country[:name]}\n"
475 else
474 else
476 countries[id] = Country.new(:name => country[:name])
475 countries[id] = Country.new(:name => country[:name])
477 countries[id].save
476 countries[id].save
478 @import_log << "Created #{country[:name]}\n"
477 @import_log << "Created #{country[:name]}\n"
479 end
478 end
480 end
479 end
481
480
482 # import sites
481 # import sites
483 sites = {}
482 sites = {}
484 site_data.each_pair do |id,site|
483 site_data.each_pair do |id,site|
485 s = Site.find_by_name(site[:name])
484 s = Site.find_by_name(site[:name])
486 if s!=nil
485 if s!=nil
487 @import_log << "Found #{site[:name]}\n"
486 @import_log << "Found #{site[:name]}\n"
488 else
487 else
489 s = Site.new(:name => site[:name])
488 s = Site.new(:name => site[:name])
490 @import_log << "Created #{site[:name]}\n"
489 @import_log << "Created #{site[:name]}\n"
491 end
490 end
492 s.password = site[:password]
491 s.password = site[:password]
493 s.country = countries[site[:country_id]]
492 s.country = countries[site[:country_id]]
494 s.save
493 s.save
495 sites[id] = s
494 sites[id] = s
496 end
495 end
497
496
498 # import users
497 # import users
499 user_data.each_pair do |id,user|
498 user_data.each_pair do |id,user|
500 u = User.find_by_login(user[:login])
499 u = User.find_by_login(user[:login])
501 if u!=nil
500 if u!=nil
502 @import_log << "Found #{user[:login]}\n"
501 @import_log << "Found #{user[:login]}\n"
503 else
502 else
504 u = User.new(:login => user[:login])
503 u = User.new(:login => user[:login])
505 @import_log << "Created #{user[:login]}\n"
504 @import_log << "Created #{user[:login]}\n"
506 end
505 end
507 u.full_name = user[:name]
506 u.full_name = user[:name]
508 u.password = user[:password]
507 u.password = user[:password]
509 u.country = countries[user[:country_id]]
508 u.country = countries[user[:country_id]]
510 u.site = sites[user[:site_id]]
509 u.site = sites[user[:site_id]]
511 u.activated = true
510 u.activated = true
512 u.email = "empty-#{u.login}@none.com"
511 u.email = "empty-#{u.login}@none.com"
513 if not u.save
512 if not u.save
514 @import_log << "Errors\n"
513 @import_log << "Errors\n"
515 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
514 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
516 end
515 end
517 end
516 end
518
517
519 end
518 end
520
519
521 def logout_users(users)
520 def logout_users(users)
522 users.each do |user|
521 users.each do |user|
523 contest_stat = user.contest_stat(true)
522 contest_stat = user.contest_stat(true)
524 if contest_stat and !contest_stat.forced_logout
523 if contest_stat and !contest_stat.forced_logout
525 contest_stat.forced_logout = true
524 contest_stat.forced_logout = true
526 contest_stat.save
525 contest_stat.save
527 end
526 end
528 end
527 end
529 end
528 end
530
529
531 def send_contest_update_notification_email(user, contest)
530 def send_contest_update_notification_email(user, contest)
532 contest_title_name = GraderConfiguration['contest.name']
531 contest_title_name = GraderConfiguration['contest.name']
533 contest_name = contest.name
532 contest_name = contest.name
534 mail_subject = t('contest.notification.email_subject', {
533 mail_subject = t('contest.notification.email_subject', {
535 :contest_title_name => contest_title_name,
534 :contest_title_name => contest_title_name,
536 :contest_name => contest_name })
535 :contest_name => contest_name })
537 mail_body = t('contest.notification.email_body', {
536 mail_body = t('contest.notification.email_body', {
538 :full_name => user.full_name,
537 :full_name => user.full_name,
539 :contest_title_name => contest_title_name,
538 :contest_title_name => contest_title_name,
540 :contest_name => contest.name,
539 :contest_name => contest.name,
541 })
540 })
542
541
@@ -1,183 +1,188
1 require 'yaml'
1 require 'yaml'
2
2
3 #
3 #
4 # This class also contains various login of the system.
4 # This class also contains various login of the system.
5 #
5 #
6 class GraderConfiguration < ActiveRecord::Base
6 class GraderConfiguration < ActiveRecord::Base
7
7
8 SYSTEM_MODE_CONF_KEY = 'system.mode'
8 SYSTEM_MODE_CONF_KEY = 'system.mode'
9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
10 MULTICONTESTS_KEY = 'system.multicontests'
10 MULTICONTESTS_KEY = 'system.multicontests'
11 CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
11 CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
12 MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login'
12 MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login'
13 VIEW_TESTCASE = 'right.view_testcase'
13 VIEW_TESTCASE = 'right.view_testcase'
14 SINGLE_USER_KEY = 'system.single_user_mode'
14 SINGLE_USER_KEY = 'system.single_user_mode'
15 + SYSTEM_USE_PROBLEM_GROUP = 'system.use_problem_group'
15
16
16 cattr_accessor :config_cache
17 cattr_accessor :config_cache
17 cattr_accessor :task_grading_info_cache
18 cattr_accessor :task_grading_info_cache
18 cattr_accessor :contest_time_str
19 cattr_accessor :contest_time_str
19 cattr_accessor :contest_time
20 cattr_accessor :contest_time
20
21
21 GraderConfiguration.config_cache = nil
22 GraderConfiguration.config_cache = nil
22 GraderConfiguration.task_grading_info_cache = nil
23 GraderConfiguration.task_grading_info_cache = nil
23
24
24 def self.config_cached?
25 def self.config_cached?
25 (defined? CONFIGURATION_CACHE_ENABLED) and (CONFIGURATION_CACHE_ENABLED)
26 (defined? CONFIGURATION_CACHE_ENABLED) and (CONFIGURATION_CACHE_ENABLED)
26 end
27 end
27
28
28 def self.get(key)
29 def self.get(key)
29 if GraderConfiguration.config_cached?
30 if GraderConfiguration.config_cached?
30 if GraderConfiguration.config_cache == nil
31 if GraderConfiguration.config_cache == nil
31 self.read_config
32 self.read_config
32 end
33 end
33 return GraderConfiguration.config_cache[key]
34 return GraderConfiguration.config_cache[key]
34 else
35 else
35 return GraderConfiguration.read_one_key(key)
36 return GraderConfiguration.read_one_key(key)
36 end
37 end
37 end
38 end
38
39
39 def self.[](key)
40 def self.[](key)
40 self.get(key)
41 self.get(key)
41 end
42 end
42
43
43 def self.reload
44 def self.reload
44 self.read_config
45 self.read_config
45 end
46 end
46
47
47 def self.clear
48 def self.clear
48 GraderConfiguration.config_cache = nil
49 GraderConfiguration.config_cache = nil
49 end
50 end
50
51
51 #
52 #
52 # View decision
53 # View decision
53 #
54 #
54 def self.show_submitbox_to?(user)
55 def self.show_submitbox_to?(user)
55 mode = get(SYSTEM_MODE_CONF_KEY)
56 mode = get(SYSTEM_MODE_CONF_KEY)
56 return false if mode=='analysis'
57 return false if mode=='analysis'
57 if (mode=='contest')
58 if (mode=='contest')
58 return false if (user.site!=nil) and
59 return false if (user.site!=nil) and
59 ((user.site.started!=true) or (user.site.finished?))
60 ((user.site.started!=true) or (user.site.finished?))
60 end
61 end
61 return true
62 return true
62 end
63 end
63
64
64 def self.show_tasks_to?(user)
65 def self.show_tasks_to?(user)
65 if time_limit_mode?
66 if time_limit_mode?
66 return false if not user.contest_started?
67 return false if not user.contest_started?
67 end
68 end
68 return true
69 return true
69 end
70 end
70
71
71 def self.show_grading_result
72 def self.show_grading_result
72 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
73 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
73 end
74 end
74
75
75 def self.show_testcase
76 def self.show_testcase
76 return get(VIEW_TESTCASE)
77 return get(VIEW_TESTCASE)
77 end
78 end
78
79
79 def self.allow_test_request(user)
80 def self.allow_test_request(user)
80 mode = get(SYSTEM_MODE_CONF_KEY)
81 mode = get(SYSTEM_MODE_CONF_KEY)
81 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
82 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
82 if (mode=='contest')
83 if (mode=='contest')
83 return false if ((user.site!=nil) and
84 return false if ((user.site!=nil) and
84 ((user.site.started!=true) or
85 ((user.site.started!=true) or
85 (early_timeout and (user.site.time_left < 30.minutes))))
86 (early_timeout and (user.site.time_left < 30.minutes))))
86 end
87 end
87 return false if mode=='analysis'
88 return false if mode=='analysis'
88 return true
89 return true
89 end
90 end
90
91
91 def self.task_grading_info
92 def self.task_grading_info
92 if GraderConfiguration.task_grading_info_cache==nil
93 if GraderConfiguration.task_grading_info_cache==nil
93 read_grading_info
94 read_grading_info
94 end
95 end
95 return GraderConfiguration.task_grading_info_cache
96 return GraderConfiguration.task_grading_info_cache
96 end
97 end
97
98
98 def self.standard_mode?
99 def self.standard_mode?
99 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
100 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
100 end
101 end
101
102
102 def self.contest_mode?
103 def self.contest_mode?
103 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
104 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
104 end
105 end
105
106
106 def self.indv_contest_mode?
107 def self.indv_contest_mode?
107 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
108 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
108 end
109 end
109
110
110 def self.multicontests?
111 def self.multicontests?
111 return get(MULTICONTESTS_KEY) == true
112 return get(MULTICONTESTS_KEY) == true
112 end
113 end
113
114
114 def self.time_limit_mode?
115 def self.time_limit_mode?
115 mode = get(SYSTEM_MODE_CONF_KEY)
116 mode = get(SYSTEM_MODE_CONF_KEY)
116 return ((mode == 'contest') or (mode == 'indv-contest'))
117 return ((mode == 'contest') or (mode == 'indv-contest'))
117 end
118 end
118
119
119 def self.analysis_mode?
120 def self.analysis_mode?
120 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
121 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
121 end
122 end
122
123
124 + def self.use_problem_group?
125 + return get(SYSTEM_USE_PROBLEM_GROUP)
126 + end
127 +
123 def self.contest_time_limit
128 def self.contest_time_limit
124 contest_time_str = GraderConfiguration[CONTEST_TIME_LIMIT_KEY]
129 contest_time_str = GraderConfiguration[CONTEST_TIME_LIMIT_KEY]
125
130
126 if not defined? GraderConfiguration.contest_time_str
131 if not defined? GraderConfiguration.contest_time_str
127 GraderConfiguration.contest_time_str = nil
132 GraderConfiguration.contest_time_str = nil
128 end
133 end
129
134
130 if GraderConfiguration.contest_time_str != contest_time_str
135 if GraderConfiguration.contest_time_str != contest_time_str
131 GraderConfiguration.contest_time_str = contest_time_str
136 GraderConfiguration.contest_time_str = contest_time_str
132 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
137 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
133 h = tmatch[1].to_i
138 h = tmatch[1].to_i
134 m = tmatch[2].to_i
139 m = tmatch[2].to_i
135
140
136 GraderConfiguration.contest_time = h.hour + m.minute
141 GraderConfiguration.contest_time = h.hour + m.minute
137 else
142 else
138 GraderConfiguration.contest_time = nil
143 GraderConfiguration.contest_time = nil
139 end
144 end
140 end
145 end
141 return GraderConfiguration.contest_time
146 return GraderConfiguration.contest_time
142 end
147 end
143
148
144 protected
149 protected
145
150
146 def self.convert_type(val,type)
151 def self.convert_type(val,type)
147 case type
152 case type
148 when 'string'
153 when 'string'
149 return val
154 return val
150
155
151 when 'integer'
156 when 'integer'
152 return val.to_i
157 return val.to_i
153
158
154 when 'boolean'
159 when 'boolean'
155 return (val=='true')
160 return (val=='true')
156 end
161 end
157 end
162 end
158
163
159 def self.read_config
164 def self.read_config
160 GraderConfiguration.config_cache = {}
165 GraderConfiguration.config_cache = {}
161 GraderConfiguration.all.each do |conf|
166 GraderConfiguration.all.each do |conf|
162 key = conf.key
167 key = conf.key
163 val = conf.value
168 val = conf.value
164 GraderConfiguration.config_cache[key] = GraderConfiguration.convert_type(val,conf.value_type)
169 GraderConfiguration.config_cache[key] = GraderConfiguration.convert_type(val,conf.value_type)
165 end
170 end
166 end
171 end
167
172
168 def self.read_one_key(key)
173 def self.read_one_key(key)
169 conf = GraderConfiguration.find_by_key(key)
174 conf = GraderConfiguration.find_by_key(key)
170 if conf
175 if conf
171 return GraderConfiguration.convert_type(conf.value,conf.value_type)
176 return GraderConfiguration.convert_type(conf.value,conf.value_type)
172 else
177 else
173 return nil
178 return nil
174 end
179 end
175 end
180 end
176
181
177 def self.read_grading_info
182 def self.read_grading_info
178 f = File.open(TASK_GRADING_INFO_FILENAME)
183 f = File.open(TASK_GRADING_INFO_FILENAME)
179 GraderConfiguration.task_grading_info_cache = YAML.load(f)
184 GraderConfiguration.task_grading_info_cache = YAML.load(f)
180 f.close
185 f.close
181 end
186 end
182
187
183 end
188 end
@@ -1,100 +1,101
1 class Problem < ActiveRecord::Base
1 class Problem < ActiveRecord::Base
2
2
3 belongs_to :description
3 belongs_to :description
4 has_and_belongs_to_many :contests, :uniq => true
4 has_and_belongs_to_many :contests, :uniq => true
5 + has_and_belongs_to_many :groups
5 has_many :test_pairs, :dependent => :delete_all
6 has_many :test_pairs, :dependent => :delete_all
6 has_many :testcases, :dependent => :destroy
7 has_many :testcases, :dependent => :destroy
7
8
8 validates_presence_of :name
9 validates_presence_of :name
9 validates_format_of :name, :with => /\A\w+\z/
10 validates_format_of :name, :with => /\A\w+\z/
10 validates_presence_of :full_name
11 validates_presence_of :full_name
11
12
12 scope :available, -> { where(available: true) }
13 scope :available, -> { where(available: true) }
13
14
14 DEFAULT_TIME_LIMIT = 1
15 DEFAULT_TIME_LIMIT = 1
15 DEFAULT_MEMORY_LIMIT = 32
16 DEFAULT_MEMORY_LIMIT = 32
16
17
17 def self.available_problems
18 def self.available_problems
18 available.order(date_added: :desc).order(:name)
19 available.order(date_added: :desc).order(:name)
19 #Problem.available.all(:order => "date_added DESC, name ASC")
20 #Problem.available.all(:order => "date_added DESC, name ASC")
20 end
21 end
21
22
22 def self.create_from_import_form_params(params, old_problem=nil)
23 def self.create_from_import_form_params(params, old_problem=nil)
23 org_problem = old_problem || Problem.new
24 org_problem = old_problem || Problem.new
24 import_params, problem = Problem.extract_params_and_check(params,
25 import_params, problem = Problem.extract_params_and_check(params,
25 org_problem)
26 org_problem)
26
27
27 if !problem.errors.empty?
28 if !problem.errors.empty?
28 return problem, 'Error importing'
29 return problem, 'Error importing'
29 end
30 end
30
31
31 problem.full_score = 100
32 problem.full_score = 100
32 problem.date_added = Time.new
33 problem.date_added = Time.new
33 problem.test_allowed = true
34 problem.test_allowed = true
34 problem.output_only = false
35 problem.output_only = false
35 problem.available = false
36 problem.available = false
36
37
37 if not problem.save
38 if not problem.save
38 return problem, 'Error importing'
39 return problem, 'Error importing'
39 end
40 end
40
41
41 import_to_db = params.has_key? :import_to_db
42 import_to_db = params.has_key? :import_to_db
42
43
43 importer = TestdataImporter.new(problem)
44 importer = TestdataImporter.new(problem)
44
45
45 if not importer.import_from_file(import_params[:file],
46 if not importer.import_from_file(import_params[:file],
46 import_params[:time_limit],
47 import_params[:time_limit],
47 import_params[:memory_limit],
48 import_params[:memory_limit],
48 import_params[:checker_name],
49 import_params[:checker_name],
49 import_to_db)
50 import_to_db)
50 problem.errors.add(:base,'Import error.')
51 problem.errors.add(:base,'Import error.')
51 end
52 end
52
53
53 return problem, importer.log_msg
54 return problem, importer.log_msg
54 end
55 end
55
56
56 def self.download_file_basedir
57 def self.download_file_basedir
57 return "#{Rails.root}/data/tasks"
58 return "#{Rails.root}/data/tasks"
58 end
59 end
59
60
60 def get_submission_stat
61 def get_submission_stat
61 result = Hash.new
62 result = Hash.new
62 #total number of submission
63 #total number of submission
63 result[:total_sub] = Submission.where(problem_id: self.id).count
64 result[:total_sub] = Submission.where(problem_id: self.id).count
64 result[:attempted_user] = Submission.where(problem_id: self.id).group(:user_id)
65 result[:attempted_user] = Submission.where(problem_id: self.id).group(:user_id)
65 result[:pass] = Submission.where(problem_id: self.id).where("points >= ?",self.full_score).count
66 result[:pass] = Submission.where(problem_id: self.id).where("points >= ?",self.full_score).count
66 return result
67 return result
67 end
68 end
68
69
69 def long_name
70 def long_name
70 "[#{name}] #{full_name}"
71 "[#{name}] #{full_name}"
71 end
72 end
72
73
73 protected
74 protected
74
75
75 def self.to_i_or_default(st, default)
76 def self.to_i_or_default(st, default)
76 if st!=''
77 if st!=''
77 result = st.to_i
78 result = st.to_i
78 end
79 end
79 result ||= default
80 result ||= default
80 end
81 end
81
82
82 def self.to_f_or_default(st, default)
83 def self.to_f_or_default(st, default)
83 if st!=''
84 if st!=''
84 result = st.to_f
85 result = st.to_f
85 end
86 end
86 result ||= default
87 result ||= default
87 end
88 end
88
89
89 def self.extract_params_and_check(params, problem)
90 def self.extract_params_and_check(params, problem)
90 time_limit = Problem.to_f_or_default(params[:time_limit],
91 time_limit = Problem.to_f_or_default(params[:time_limit],
91 DEFAULT_TIME_LIMIT)
92 DEFAULT_TIME_LIMIT)
92 memory_limit = Problem.to_i_or_default(params[:memory_limit],
93 memory_limit = Problem.to_i_or_default(params[:memory_limit],
93 DEFAULT_MEMORY_LIMIT)
94 DEFAULT_MEMORY_LIMIT)
94
95
95 if time_limit<=0 or time_limit >60
96 if time_limit<=0 or time_limit >60
96 problem.errors.add(:base,'Time limit out of range.')
97 problem.errors.add(:base,'Time limit out of range.')
97 end
98 end
98
99
99 if memory_limit==0 and params[:memory_limit]!='0'
100 if memory_limit==0 and params[:memory_limit]!='0'
100 problem.errors.add(:base,'Memory limit format errors.')
101 problem.errors.add(:base,'Memory limit format errors.')
@@ -1,105 +1,106
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 require 'net/https'
3 require 'net/https'
4 require 'net/http'
4 require 'net/http'
5 require 'json'
5 require 'json'
6
6
7 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
8
8
9 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
10 + has_and_belongs_to_many :groups
10
11
11 has_many :test_requests, -> {order(submitted_at: DESC)}
12 has_many :test_requests, -> {order(submitted_at: DESC)}
12
13
13 has_many :messages, -> { order(created_at: DESC) },
14 has_many :messages, -> { order(created_at: DESC) },
14 :class_name => "Message",
15 :class_name => "Message",
15 :foreign_key => "sender_id"
16 :foreign_key => "sender_id"
16
17
17 has_many :replied_messages, -> { order(created_at: DESC) },
18 has_many :replied_messages, -> { order(created_at: DESC) },
18 :class_name => "Message",
19 :class_name => "Message",
19 :foreign_key => "receiver_id"
20 :foreign_key => "receiver_id"
20
21
21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
22 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
22
23
23 belongs_to :site
24 belongs_to :site
24 belongs_to :country
25 belongs_to :country
25
26
26 has_and_belongs_to_many :contests, -> { order(:name); uniq}
27 has_and_belongs_to_many :contests, -> { order(:name); uniq}
27
28
28 scope :activated_users, -> {where activated: true}
29 scope :activated_users, -> {where activated: true}
29
30
30 validates_presence_of :login
31 validates_presence_of :login
31 validates_uniqueness_of :login
32 validates_uniqueness_of :login
32 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
33 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
33 validates_length_of :login, :within => 3..30
34 validates_length_of :login, :within => 3..30
34
35
35 validates_presence_of :full_name
36 validates_presence_of :full_name
36 validates_length_of :full_name, :minimum => 1
37 validates_length_of :full_name, :minimum => 1
37
38
38 validates_presence_of :password, :if => :password_required?
39 validates_presence_of :password, :if => :password_required?
39 validates_length_of :password, :within => 4..20, :if => :password_required?
40 validates_length_of :password, :within => 4..20, :if => :password_required?
40 validates_confirmation_of :password, :if => :password_required?
41 validates_confirmation_of :password, :if => :password_required?
41
42
42 validates_format_of :email,
43 validates_format_of :email,
43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
44 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
44 :if => :email_validation?
45 :if => :email_validation?
45 validate :uniqueness_of_email_from_activated_users,
46 validate :uniqueness_of_email_from_activated_users,
46 :if => :email_validation?
47 :if => :email_validation?
47 validate :enough_time_interval_between_same_email_registrations,
48 validate :enough_time_interval_between_same_email_registrations,
48 :if => :email_validation?
49 :if => :email_validation?
49
50
50 # these are for ytopc
51 # these are for ytopc
51 # disable for now
52 # disable for now
52 #validates_presence_of :province
53 #validates_presence_of :province
53
54
54 attr_accessor :password
55 attr_accessor :password
55
56
56 before_save :encrypt_new_password
57 before_save :encrypt_new_password
57 before_save :assign_default_site
58 before_save :assign_default_site
58 before_save :assign_default_contest
59 before_save :assign_default_contest
59
60
60 # this is for will_paginate
61 # this is for will_paginate
61 cattr_reader :per_page
62 cattr_reader :per_page
62 @@per_page = 50
63 @@per_page = 50
63
64
64 def self.authenticate(login, password)
65 def self.authenticate(login, password)
65 user = find_by_login(login)
66 user = find_by_login(login)
66 if user
67 if user
67 return user if user.authenticated?(password)
68 return user if user.authenticated?(password)
68 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
69 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
69 user.password = password
70 user.password = password
70 user.save
71 user.save
71 return user
72 return user
72 end
73 end
73 end
74 end
74 end
75 end
75
76
76 def authenticated?(password)
77 def authenticated?(password)
77 if self.activated
78 if self.activated
78 hashed_password == User.encrypt(password,self.salt)
79 hashed_password == User.encrypt(password,self.salt)
79 else
80 else
80 false
81 false
81 end
82 end
82 end
83 end
83
84
84 def authenticated_by_pop3?(password)
85 def authenticated_by_pop3?(password)
85 Net::POP3.enable_ssl
86 Net::POP3.enable_ssl
86 pop = Net::POP3.new('pops.it.chula.ac.th')
87 pop = Net::POP3.new('pops.it.chula.ac.th')
87 authen = true
88 authen = true
88 begin
89 begin
89 pop.start(login, password)
90 pop.start(login, password)
90 pop.finish
91 pop.finish
91 return true
92 return true
92 rescue
93 rescue
93 return false
94 return false
94 end
95 end
95 end
96 end
96
97
97 def authenticated_by_cucas?(password)
98 def authenticated_by_cucas?(password)
98 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
99 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
99 appid = '41508763e340d5858c00f8c1a0f5a2bb'
100 appid = '41508763e340d5858c00f8c1a0f5a2bb'
100 appsecret ='d9cbb5863091dbe186fded85722a1e31'
101 appsecret ='d9cbb5863091dbe186fded85722a1e31'
101 post_args = {
102 post_args = {
102 'appid' => appid,
103 'appid' => appid,
103 'appsecret' => appsecret,
104 'appsecret' => appsecret,
104 'username' => login,
105 'username' => login,
105 'password' => password
106 'password' => password
@@ -197,192 +198,204
197 return nil
198 return nil
198 end
199 end
199 if contest_stat==nil or contest_stat.started_at==nil
200 if contest_stat==nil or contest_stat.started_at==nil
200 return (Time.now.gmtime + time_limit) - Time.now.gmtime
201 return (Time.now.gmtime + time_limit) - Time.now.gmtime
201 else
202 else
202 finish_time = contest_stat.started_at + time_limit
203 finish_time = contest_stat.started_at + time_limit
203 current_time = Time.now.gmtime
204 current_time = Time.now.gmtime
204 if current_time > finish_time
205 if current_time > finish_time
205 return 0
206 return 0
206 else
207 else
207 return finish_time - current_time
208 return finish_time - current_time
208 end
209 end
209 end
210 end
210 else
211 else
211 return nil
212 return nil
212 end
213 end
213 end
214 end
214
215
215 def contest_finished?
216 def contest_finished?
216 if GraderConfiguration.contest_mode?
217 if GraderConfiguration.contest_mode?
217 return false if site==nil
218 return false if site==nil
218 return site.finished?
219 return site.finished?
219 elsif GraderConfiguration.indv_contest_mode?
220 elsif GraderConfiguration.indv_contest_mode?
220 return false if self.contest_stat(true)==nil
221 return false if self.contest_stat(true)==nil
221 return contest_time_left == 0
222 return contest_time_left == 0
222 else
223 else
223 return false
224 return false
224 end
225 end
225 end
226 end
226
227
227 def contest_started?
228 def contest_started?
228 if GraderConfiguration.indv_contest_mode?
229 if GraderConfiguration.indv_contest_mode?
229 stat = self.contest_stat
230 stat = self.contest_stat
230 return ((stat != nil) and (stat.started_at != nil))
231 return ((stat != nil) and (stat.started_at != nil))
231 elsif GraderConfiguration.contest_mode?
232 elsif GraderConfiguration.contest_mode?
232 return true if site==nil
233 return true if site==nil
233 return site.started
234 return site.started
234 else
235 else
235 return true
236 return true
236 end
237 end
237 end
238 end
238
239
239 def update_start_time
240 def update_start_time
240 stat = self.contest_stat
241 stat = self.contest_stat
241 if stat.nil? or stat.started_at.nil?
242 if stat.nil? or stat.started_at.nil?
242 stat ||= UserContestStat.new(:user => self)
243 stat ||= UserContestStat.new(:user => self)
243 stat.started_at = Time.now.gmtime
244 stat.started_at = Time.now.gmtime
244 stat.save
245 stat.save
245 end
246 end
246 end
247 end
247
248
248 def problem_in_user_contests?(problem)
249 def problem_in_user_contests?(problem)
249 problem_contests = problem.contests.all
250 problem_contests = problem.contests.all
250
251
251 if problem_contests.length == 0 # this is public contest
252 if problem_contests.length == 0 # this is public contest
252 return true
253 return true
253 end
254 end
254
255
255 contests.each do |contest|
256 contests.each do |contest|
256 if problem_contests.find {|c| c.id == contest.id }
257 if problem_contests.find {|c| c.id == contest.id }
257 return true
258 return true
258 end
259 end
259 end
260 end
260 return false
261 return false
261 end
262 end
262
263
263 def available_problems_group_by_contests
264 def available_problems_group_by_contests
264 contest_problems = []
265 contest_problems = []
265 pin = {}
266 pin = {}
266 contests.enabled.each do |contest|
267 contests.enabled.each do |contest|
267 available_problems = contest.problems.available
268 available_problems = contest.problems.available
268 contest_problems << {
269 contest_problems << {
269 :contest => contest,
270 :contest => contest,
270 :problems => available_problems
271 :problems => available_problems
271 }
272 }
272 available_problems.each {|p| pin[p.id] = true}
273 available_problems.each {|p| pin[p.id] = true}
273 end
274 end
274 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
275 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
275 contest_problems << {
276 contest_problems << {
276 :contest => nil,
277 :contest => nil,
277 :problems => other_avaiable_problems
278 :problems => other_avaiable_problems
278 }
279 }
279 return contest_problems
280 return contest_problems
280 end
281 end
281
282
282 def solve_all_available_problems?
283 def solve_all_available_problems?
283 available_problems.each do |p|
284 available_problems.each do |p|
284 u = self
285 u = self
285 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
286 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
286 return false if !p or !sub or sub.points < p.full_score
287 return false if !p or !sub or sub.points < p.full_score
287 end
288 end
288 return true
289 return true
289 end
290 end
290
291
291 def available_problems
292 def available_problems
292 if not GraderConfiguration.multicontests?
293 if not GraderConfiguration.multicontests?
294 + if GraderConfiguration.use_problem_group?
295 + return available_problems_in_group
296 + else
293 return Problem.available_problems
297 return Problem.available_problems
298 + end
294 else
299 else
295 contest_problems = []
300 contest_problems = []
296 pin = {}
301 pin = {}
297 contests.enabled.each do |contest|
302 contests.enabled.each do |contest|
298 contest.problems.available.each do |problem|
303 contest.problems.available.each do |problem|
299 if not pin.has_key? problem.id
304 if not pin.has_key? problem.id
300 contest_problems << problem
305 contest_problems << problem
301 end
306 end
302 pin[problem.id] = true
307 pin[problem.id] = true
303 end
308 end
304 end
309 end
305 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
310 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
306 return contest_problems + other_avaiable_problems
311 return contest_problems + other_avaiable_problems
307 end
312 end
308 end
313 end
309
314
315 + def available_problems_in_group
316 + problem = []
317 + self.groups.each do |group|
318 + group.problems.where(available: true).each { |p| problem << p }
319 + end
320 + return problem.uniq
321 + end
322 +
310 def can_view_problem?(problem)
323 def can_view_problem?(problem)
311 if not GraderConfiguration.multicontests?
324 if not GraderConfiguration.multicontests?
312 return problem.available
325 return problem.available
313 else
326 else
314 return problem_in_user_contests? problem
327 return problem_in_user_contests? problem
315 end
328 end
316 end
329 end
317
330
318 def self.clear_last_login
331 def self.clear_last_login
319 User.update_all(:last_ip => nil)
332 User.update_all(:last_ip => nil)
320 end
333 end
321
334
322 protected
335 protected
323 def encrypt_new_password
336 def encrypt_new_password
324 return if password.blank?
337 return if password.blank?
325 self.salt = (10+rand(90)).to_s
338 self.salt = (10+rand(90)).to_s
326 self.hashed_password = User.encrypt(self.password,self.salt)
339 self.hashed_password = User.encrypt(self.password,self.salt)
327 end
340 end
328
341
329 def assign_default_site
342 def assign_default_site
330 # have to catch error when migrating (because self.site is not available).
343 # have to catch error when migrating (because self.site is not available).
331 begin
344 begin
332 if self.site==nil
345 if self.site==nil
333 self.site = Site.find_by_name('default')
346 self.site = Site.find_by_name('default')
334 if self.site==nil
347 if self.site==nil
335 self.site = Site.find(1) # when 'default has be renamed'
348 self.site = Site.find(1) # when 'default has be renamed'
336 end
349 end
337 end
350 end
338 rescue
351 rescue
339 end
352 end
340 end
353 end
341
354
342 def assign_default_contest
355 def assign_default_contest
343 # have to catch error when migrating (because self.site is not available).
356 # have to catch error when migrating (because self.site is not available).
344 begin
357 begin
345 if self.contests.length == 0
358 if self.contests.length == 0
346 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
359 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
347 if default_contest
360 if default_contest
348 self.contests = [default_contest]
361 self.contests = [default_contest]
349 end
362 end
350 end
363 end
351 rescue
364 rescue
352 end
365 end
353 end
366 end
354
367
355 def password_required?
368 def password_required?
356 self.hashed_password.blank? || !self.password.blank?
369 self.hashed_password.blank? || !self.password.blank?
357 end
370 end
358
371
359 def self.encrypt(string,salt)
372 def self.encrypt(string,salt)
360 Digest::SHA1.hexdigest(salt + string)
373 Digest::SHA1.hexdigest(salt + string)
361 end
374 end
362
375
363 def uniqueness_of_email_from_activated_users
376 def uniqueness_of_email_from_activated_users
364 user = User.activated_users.find_by_email(self.email)
377 user = User.activated_users.find_by_email(self.email)
365 if user and (user.login != self.login)
378 if user and (user.login != self.login)
366 self.errors.add(:base,"Email has already been taken")
379 self.errors.add(:base,"Email has already been taken")
367 end
380 end
368 end
381 end
369
382
370 def enough_time_interval_between_same_email_registrations
383 def enough_time_interval_between_same_email_registrations
371 return if !self.new_record?
384 return if !self.new_record?
372 return if self.activated
385 return if self.activated
373 open_user = User.find_by_email(self.email,
386 open_user = User.find_by_email(self.email,
374 :order => 'created_at DESC')
387 :order => 'created_at DESC')
375 if open_user and open_user.created_at and
388 if open_user and open_user.created_at and
376 (open_user.created_at > Time.now.gmtime - 5.minutes)
389 (open_user.created_at > Time.now.gmtime - 5.minutes)
377 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
390 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
378 end
391 end
379 end
392 end
380
393
381 def email_validation?
394 def email_validation?
382 begin
395 begin
383 return VALIDATE_USER_EMAILS
396 return VALIDATE_USER_EMAILS
384 rescue
397 rescue
385 return false
398 return false
386 end
399 end
387 end
400 end
388 end
401 end
@@ -1,85 +1,90
1 - content_for :head do
1 - content_for :head do
2 = stylesheet_link_tag 'problems'
2 = stylesheet_link_tag 'problems'
3 = javascript_include_tag 'local_jquery'
3 = javascript_include_tag 'local_jquery'
4
4
5 :javascript
5 :javascript
6 $(document).ready( function() {
6 $(document).ready( function() {
7 function shiftclick(start,stop,value) {
7 function shiftclick(start,stop,value) {
8 $('tr input').each( function(id,input) {
8 $('tr input').each( function(id,input) {
9 var $input=$(input);
9 var $input=$(input);
10 var iid=parseInt($input.attr('id').split('-')[2]);
10 var iid=parseInt($input.attr('id').split('-')[2]);
11 if(iid>=start&&iid<=stop){
11 if(iid>=start&&iid<=stop){
12 $input.prop('checked',value)
12 $input.prop('checked',value)
13 }
13 }
14 });
14 });
15 }
15 }
16
16
17 $('tr input').click( function(e) {
17 $('tr input').click( function(e) {
18 if (e.shiftKey) {
18 if (e.shiftKey) {
19 stop = parseInt($(this).attr('id').split('-')[2]);
19 stop = parseInt($(this).attr('id').split('-')[2]);
20 var orig_stop = stop
20 var orig_stop = stop
21 if (typeof start !== 'undefined') {
21 if (typeof start !== 'undefined') {
22 if (start > stop) {
22 if (start > stop) {
23 var tmp = start;
23 var tmp = start;
24 start = stop;
24 start = stop;
25 stop = tmp;
25 stop = tmp;
26 }
26 }
27 shiftclick(start,stop,$(this).is(':checked') )
27 shiftclick(start,stop,$(this).is(':checked') )
28 }
28 }
29 start = orig_stop
29 start = orig_stop
30 } else {
30 } else {
31 start = parseInt($(this).attr('id').split('-')[2]);
31 start = parseInt($(this).attr('id').split('-')[2]);
32 }
32 }
33 });
33 });
34 });
34 });
35
35
36
36
37 %h1 Manage problems
37 %h1 Manage problems
38
38
39 %p= link_to '[Back to problem list]', :action => 'list'
39 %p= link_to '[Back to problem list]', :action => 'list'
40
40
41 = form_tag :action=>'do_manage' do
41 = form_tag :action=>'do_manage' do
42 - .submitbox
42 + .submitbox.panel
43 What do you want to do to the selected problem?
43 What do you want to do to the selected problem?
44 %br/
44 %br/
45 (You can shift-click to select a range of problems)
45 (You can shift-click to select a range of problems)
46 %ul
46 %ul
47 %li
47 %li
48 Change date added to
48 Change date added to
49 = select_date Date.current, :prefix => 'date_added'
49 = select_date Date.current, :prefix => 'date_added'
50 &nbsp;&nbsp;&nbsp;
50 &nbsp;&nbsp;&nbsp;
51 = submit_tag 'Change', :name => 'change_date_added'
51 = submit_tag 'Change', :name => 'change_date_added'
52 %li
52 %li
53 Set available to
53 Set available to
54 = submit_tag 'True', :name => 'enable_problem'
54 = submit_tag 'True', :name => 'enable_problem'
55 = submit_tag 'False', :name => 'disable_problem'
55 = submit_tag 'False', :name => 'disable_problem'
56
56
57 - if GraderConfiguration.multicontests?
57 - if GraderConfiguration.multicontests?
58 %li
58 %li
59 Add to
59 Add to
60 = select("contest","id",Contest.all.collect {|c| [c.title, c.id]})
60 = select("contest","id",Contest.all.collect {|c| [c.title, c.id]})
61 = submit_tag 'Add', :name => 'add_to_contest'
61 = submit_tag 'Add', :name => 'add_to_contest'
62 + %li
63 + Add problems to group
64 + = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
65 + = submit_tag 'Add', name: 'add_group'
62
66
63 - %table
67 +
68 + %table.table.table-hover
64 %tr{style: "text-align: left;"}
69 %tr{style: "text-align: left;"}
65 %th= check_box_tag 'select_all'
70 %th= check_box_tag 'select_all'
66 %th Name
71 %th Name
67 %th Full name
72 %th Full name
68 %th Available
73 %th Available
69 %th Date added
74 %th Date added
70 - if GraderConfiguration.multicontests?
75 - if GraderConfiguration.multicontests?
71 %th Contests
76 %th Contests
72
77
73 - num = 0
78 - num = 0
74 - for problem in @problems
79 - for problem in @problems
75 - num += 1
80 - num += 1
76 %tr{:id => "row-prob-#{problem.id}", :name=> "prob-#{problem.id}"}
81 %tr{:id => "row-prob-#{problem.id}", :name=> "prob-#{problem.id}"}
77 %td= check_box_tag "prob-#{problem.id}-#{num}"
82 %td= check_box_tag "prob-#{problem.id}-#{num}"
78 %td= problem.name
83 %td= problem.name
79 %td= problem.full_name
84 %td= problem.full_name
80 %td= problem.available
85 %td= problem.available
81 %td= problem.date_added
86 %td= problem.date_added
82 - if GraderConfiguration.multicontests?
87 - if GraderConfiguration.multicontests?
83 %td
88 %td
84 - problem.contests.each do |contest|
89 - problem.contests.each do |contest|
85 = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])"
90 = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])"
@@ -1,86 +1,86
1 %h1 Bulk Manage User
1 %h1 Bulk Manage User
2
2
3 = form_tag bulk_manage_user_admin_path
3 = form_tag bulk_manage_user_admin_path
4 .row
4 .row
5 .col-md-6
5 .col-md-6
6 .panel.panel-primary
6 .panel.panel-primary
7 .panel-title.panel-heading
7 .panel-title.panel-heading
8 Filter User
8 Filter User
9 .panel-body
9 .panel-body
10 Filtering users whose login match the following MySQL regex
10 Filtering users whose login match the following MySQL regex
11 .form-group
11 .form-group
12 = label_tag "regex", 'Regex Pattern'
12 = label_tag "regex", 'Regex Pattern'
13 = text_field_tag "regex", params[:regex], class: 'form-control'
13 = text_field_tag "regex", params[:regex], class: 'form-control'
14 %p
14 %p
15 Example
15 Example
16 %ul
16 %ul
17 %li
17 %li
18 %code root
18 %code root
19 matches every user whose login contains "root"
19 matches every user whose login contains "root"
20 %li
20 %li
21 %code ^56
21 %code ^56
22 matches every user whose login starts with "56"
22 matches every user whose login starts with "56"
23 %li
23 %li
24 %code 21$
24 %code 21$
25 matches every user whose login ends with "21"
25 matches every user whose login ends with "21"
26 .col-md-6
26 .col-md-6
27 .panel.panel-primary
27 .panel.panel-primary
28 .panel-title.panel-heading
28 .panel-title.panel-heading
29 Action
29 Action
30 .panel-body
30 .panel-body
31 .row.form-group
31 .row.form-group
32 .col-md-6
32 .col-md-6
33 %label.checkbox-inline
33 %label.checkbox-inline
34 = check_box_tag "enabled", true, params[:enabled]
34 = check_box_tag "enabled", true, params[:enabled]
35 Change "Enabled" to
35 Change "Enabled" to
36 .col-md-3
36 .col-md-3
37 %label.radio-inline
37 %label.radio-inline
38 = radio_button_tag "enable", 1, params[:enable] == '1', id: 'enable-yes'
38 = radio_button_tag "enable", 1, params[:enable] == '1', id: 'enable-yes'
39 Yes
39 Yes
40 .col-md-3
40 .col-md-3
41 %label.radio-inline
41 %label.radio-inline
42 = radio_button_tag "enable", 0, params[:enable] == '0', id: 'enable-no'
42 = radio_button_tag "enable", 0, params[:enable] == '0', id: 'enable-no'
43 No
43 No
44 .row.form-group
44 .row.form-group
45 .col-md-6
45 .col-md-6
46 %label.checkbox-inline
46 %label.checkbox-inline
47 = check_box_tag "gen_password", true, params[:gen_password]
47 = check_box_tag "gen_password", true, params[:gen_password]
48 Generate new random password
48 Generate new random password
49 .row.form-group
49 .row.form-group
50 .col-md-4
50 .col-md-4
51 %label.checkbox-inline
51 %label.checkbox-inline
52 = check_box_tag "add_group", true, params[:add_group]
52 = check_box_tag "add_group", true, params[:add_group]
53 Add users to group
53 Add users to group
54 %label.col-md-3.control-label.text-right Group name
54 %label.col-md-3.control-label.text-right Group name
55 .col-md-5
55 .col-md-5
56 - = text_field_tag "group_name", params[:group_name], id: 'group_name',class: 'form-control select2'
56 + = select_tag "group_name", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'form-control select2'
57
57
58
58
59 .row
59 .row
60 .col-md-12
60 .col-md-12
61 = submit_tag "Preview Result", class: 'btn btn-default'
61 = submit_tag "Preview Result", class: 'btn btn-default'
62 - if @users
62 - if @users
63 .row
63 .row
64 .col-md-4
64 .col-md-4
65 - if @action
65 - if @action
66 %h2 Confirmation
66 %h2 Confirmation
67 - if @action[:set_enable]
67 - if @action[:set_enable]
68 .alert.alert-info The following users will be set #{(@action[:enabled] ? 'enable' : 'disable')}.
68 .alert.alert-info The following users will be set #{(@action[:enabled] ? 'enable' : 'disable')}.
69 - if @action[:gen_password]
69 - if @action[:gen_password]
70 .alert.alert-info The password of the following users will be randomly generated.
70 .alert.alert-info The password of the following users will be randomly generated.
71 .row
71 .row
72 .col-md-4
72 .col-md-4
73 = submit_tag "Perform", class: 'btn btn-primary'
73 = submit_tag "Perform", class: 'btn btn-primary'
74 .row
74 .row
75 .col-md-12
75 .col-md-12
76 The pattern matches #{@users.count} following users.
76 The pattern matches #{@users.count} following users.
77 %br
77 %br
78 - @users.each do |user|
78 - @users.each do |user|
79 = user.login
79 = user.login
80 = ' '
80 = ' '
81 = user.full_name
81 = user.full_name
82 = ' '
82 = ' '
83 = "(#{user.remark})" if user.remark
83 = "(#{user.remark})" if user.remark
84 %br
84 %br
85
85
86
86
@@ -1,98 +1,106
1 CafeGrader::Application.routes.draw do
1 CafeGrader::Application.routes.draw do
2 get "sources/direct_edit"
2 get "sources/direct_edit"
3
3
4 root :to => 'main#login'
4 root :to => 'main#login'
5
5
6 #logins
6 #logins
7 get 'login/login', to: 'login#login'
7 get 'login/login', to: 'login#login'
8
8
9 resources :contests
9 resources :contests
10
10
11 resources :sites
11 resources :sites
12
12
13 resources :announcements do
13 resources :announcements do
14 member do
14 member do
15 get 'toggle','toggle_front'
15 get 'toggle','toggle_front'
16 end
16 end
17 end
17 end
18
18
19 resources :problems do
19 resources :problems do
20 member do
20 member do
21 get 'toggle'
21 get 'toggle'
22 get 'toggle_test'
22 get 'toggle_test'
23 get 'toggle_view_testcase'
23 get 'toggle_view_testcase'
24 get 'stat'
24 get 'stat'
25 end
25 end
26 collection do
26 collection do
27 get 'turn_all_off'
27 get 'turn_all_off'
28 get 'turn_all_on'
28 get 'turn_all_on'
29 get 'import'
29 get 'import'
30 get 'manage'
30 get 'manage'
31 end
31 end
32 + end
32
33
34 + resources :groups do
35 + member do
36 + post 'add_user', to: 'groups#add_user', as: 'add_user'
37 + delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
38 + post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
39 + delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
40 + end
33 end
41 end
34
42
35 resources :testcases, only: [] do
43 resources :testcases, only: [] do
36 member do
44 member do
37 get 'download_input'
45 get 'download_input'
38 get 'download_sol'
46 get 'download_sol'
39 end
47 end
40 collection do
48 collection do
41 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
49 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
42 end
50 end
43 end
51 end
44
52
45 resources :grader_configuration, controller: 'configurations'
53 resources :grader_configuration, controller: 'configurations'
46
54
47 resources :users do
55 resources :users do
48 member do
56 member do
49 get 'toggle_activate', 'toggle_enable'
57 get 'toggle_activate', 'toggle_enable'
50 get 'stat'
58 get 'stat'
51 end
59 end
52 end
60 end
53
61
54 resources :submissions do
62 resources :submissions do
55 member do
63 member do
56 get 'download'
64 get 'download'
57 get 'compiler_msg'
65 get 'compiler_msg'
58 get 'rejudge'
66 get 'rejudge'
59 end
67 end
60 collection do
68 collection do
61 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
69 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
62 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
70 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
63 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
71 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
64 end
72 end
65 end
73 end
66
74
67
75
68
76
69 #main
77 #main
70 get "main/list"
78 get "main/list"
71 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
79 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
72
80
73 #user admin
81 #user admin
74 get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
82 get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
75
83
76 #report
84 #report
77 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
85 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
78 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
86 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
79 get "report/login"
87 get "report/login"
80 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
88 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
81 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
89 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
82
90
83
91
84 #
92 #
85 get 'tasks/view/:file.:ext' => 'tasks#view'
93 get 'tasks/view/:file.:ext' => 'tasks#view'
86 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
94 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
87 get 'heartbeat/:id/edit' => 'heartbeat#edit'
95 get 'heartbeat/:id/edit' => 'heartbeat#edit'
88
96
89 #grader
97 #grader
90 get 'graders/list', to: 'graders#list', as: 'grader_list'
98 get 'graders/list', to: 'graders#list', as: 'grader_list'
91
99
92
100
93 # See how all your routes lay out with "rake routes"
101 # See how all your routes lay out with "rake routes"
94
102
95 # This is a legacy wild controller route that's not recommended for RESTful applications.
103 # This is a legacy wild controller route that's not recommended for RESTful applications.
96 # Note: This route will make all actions in every controller accessible via GET requests.
104 # Note: This route will make all actions in every controller accessible via GET requests.
97 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
105 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
98 end
106 end
@@ -1,177 +1,196
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 that you check this file into your version control system.
12 # It's strongly recommended that you check this file into your version control system.
13
13
14 - ActiveRecord::Schema.define(version: 20170427070345) do
14 + ActiveRecord::Schema.define(version: 20170911091143) do
15
15
16 create_table "announcements", force: :cascade do |t|
16 create_table "announcements", force: :cascade do |t|
17 t.string "author", limit: 255
17 t.string "author", limit: 255
18 t.text "body", limit: 65535
18 t.text "body", limit: 65535
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", limit: 255
24 t.string "title", limit: 255
25 t.string "notes", limit: 255
25 t.string "notes", limit: 255
26 end
26 end
27
27
28 create_table "contests", force: :cascade do |t|
28 create_table "contests", force: :cascade do |t|
29 t.string "title", limit: 255
29 t.string "title", limit: 255
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", limit: 255
33 t.string "name", limit: 255
34 end
34 end
35
35
36 create_table "contests_problems", id: false, force: :cascade do |t|
36 create_table "contests_problems", id: false, force: :cascade do |t|
37 t.integer "contest_id", limit: 4
37 t.integer "contest_id", limit: 4
38 t.integer "problem_id", limit: 4
38 t.integer "problem_id", limit: 4
39 end
39 end
40
40
41 create_table "contests_users", id: false, force: :cascade do |t|
41 create_table "contests_users", id: false, force: :cascade do |t|
42 t.integer "contest_id", limit: 4
42 t.integer "contest_id", limit: 4
43 t.integer "user_id", limit: 4
43 t.integer "user_id", limit: 4
44 end
44 end
45
45
46 create_table "countries", force: :cascade do |t|
46 create_table "countries", force: :cascade do |t|
47 t.string "name", limit: 255
47 t.string "name", limit: 255
48 t.datetime "created_at", null: false
48 t.datetime "created_at", null: false
49 t.datetime "updated_at", null: false
49 t.datetime "updated_at", null: false
50 end
50 end
51
51
52 create_table "descriptions", force: :cascade do |t|
52 create_table "descriptions", force: :cascade do |t|
53 t.text "body", limit: 65535
53 t.text "body", limit: 65535
54 t.boolean "markdowned"
54 t.boolean "markdowned"
55 t.datetime "created_at", null: false
55 t.datetime "created_at", null: false
56 t.datetime "updated_at", null: false
56 t.datetime "updated_at", null: false
57 end
57 end
58
58
59 create_table "grader_configurations", force: :cascade do |t|
59 create_table "grader_configurations", force: :cascade do |t|
60 t.string "key", limit: 255
60 t.string "key", limit: 255
61 t.string "value_type", limit: 255
61 t.string "value_type", limit: 255
62 t.string "value", limit: 255
62 t.string "value", limit: 255
63 t.datetime "created_at", null: false
63 t.datetime "created_at", null: false
64 t.datetime "updated_at", null: false
64 t.datetime "updated_at", null: false
65 t.text "description", limit: 65535
65 t.text "description", limit: 65535
66 end
66 end
67
67
68 create_table "grader_processes", force: :cascade do |t|
68 create_table "grader_processes", force: :cascade do |t|
69 t.string "host", limit: 255
69 t.string "host", limit: 255
70 t.integer "pid", limit: 4
70 t.integer "pid", limit: 4
71 t.string "mode", limit: 255
71 t.string "mode", limit: 255
72 t.boolean "active"
72 t.boolean "active"
73 t.datetime "created_at", null: false
73 t.datetime "created_at", null: false
74 t.datetime "updated_at", null: false
74 t.datetime "updated_at", null: false
75 t.integer "task_id", limit: 4
75 t.integer "task_id", limit: 4
76 t.string "task_type", limit: 255
76 t.string "task_type", limit: 255
77 t.boolean "terminated"
77 t.boolean "terminated"
78 end
78 end
79
79
80 add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
80 add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
81
81
82 + create_table "groups", force: :cascade do |t|
83 + t.string "name", limit: 255
84 + t.string "description", limit: 255
85 + end
86 +
87 + create_table "groups_problems", id: false, force: :cascade do |t|
88 + t.integer "problem_id", limit: 4, null: false
89 + t.integer "group_id", limit: 4, null: false
90 + end
91 +
92 + add_index "groups_problems", ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id", using: :btree
93 +
94 + create_table "groups_users", id: false, force: :cascade do |t|
95 + t.integer "group_id", limit: 4, null: false
96 + t.integer "user_id", limit: 4, null: false
97 + end
98 +
99 + add_index "groups_users", ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id", using: :btree
100 +
82 create_table "heart_beats", force: :cascade do |t|
101 create_table "heart_beats", force: :cascade do |t|
83 t.integer "user_id", limit: 4
102 t.integer "user_id", limit: 4
84 t.string "ip_address", limit: 255
103 t.string "ip_address", limit: 255
85 t.datetime "created_at", null: false
104 t.datetime "created_at", null: false
86 t.datetime "updated_at", null: false
105 t.datetime "updated_at", null: false
87 t.string "status", limit: 255
106 t.string "status", limit: 255
88 end
107 end
89
108
90 add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
109 add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
91
110
92 create_table "languages", force: :cascade do |t|
111 create_table "languages", force: :cascade do |t|
93 t.string "name", limit: 10
112 t.string "name", limit: 10
94 t.string "pretty_name", limit: 255
113 t.string "pretty_name", limit: 255
95 t.string "ext", limit: 10
114 t.string "ext", limit: 10
96 t.string "common_ext", limit: 255
115 t.string "common_ext", limit: 255
97 end
116 end
98
117
99 create_table "logins", force: :cascade do |t|
118 create_table "logins", force: :cascade do |t|
100 t.integer "user_id", limit: 4
119 t.integer "user_id", limit: 4
101 t.string "ip_address", limit: 255
120 t.string "ip_address", limit: 255
102 t.datetime "created_at", null: false
121 t.datetime "created_at", null: false
103 t.datetime "updated_at", null: false
122 t.datetime "updated_at", null: false
104 end
123 end
105
124
106 create_table "messages", force: :cascade do |t|
125 create_table "messages", force: :cascade do |t|
107 t.integer "sender_id", limit: 4
126 t.integer "sender_id", limit: 4
108 t.integer "receiver_id", limit: 4
127 t.integer "receiver_id", limit: 4
109 t.integer "replying_message_id", limit: 4
128 t.integer "replying_message_id", limit: 4
110 t.text "body", limit: 65535
129 t.text "body", limit: 65535
111 t.boolean "replied"
130 t.boolean "replied"
112 t.datetime "created_at", null: false
131 t.datetime "created_at", null: false
113 t.datetime "updated_at", null: false
132 t.datetime "updated_at", null: false
114 end
133 end
115
134
116 create_table "problems", force: :cascade do |t|
135 create_table "problems", force: :cascade do |t|
117 t.string "name", limit: 30
136 t.string "name", limit: 30
118 t.string "full_name", limit: 255
137 t.string "full_name", limit: 255
119 t.integer "full_score", limit: 4
138 t.integer "full_score", limit: 4
120 t.date "date_added"
139 t.date "date_added"
121 t.boolean "available"
140 t.boolean "available"
122 t.string "url", limit: 255
141 t.string "url", limit: 255
123 t.integer "description_id", limit: 4
142 t.integer "description_id", limit: 4
124 t.boolean "test_allowed"
143 t.boolean "test_allowed"
125 t.boolean "output_only"
144 t.boolean "output_only"
126 t.string "description_filename", limit: 255
145 t.string "description_filename", limit: 255
127 t.boolean "view_testcase"
146 t.boolean "view_testcase"
128 end
147 end
129
148
130 create_table "rights", force: :cascade do |t|
149 create_table "rights", force: :cascade do |t|
131 t.string "name", limit: 255
150 t.string "name", limit: 255
132 t.string "controller", limit: 255
151 t.string "controller", limit: 255
133 t.string "action", limit: 255
152 t.string "action", limit: 255
134 end
153 end
135
154
136 create_table "rights_roles", id: false, force: :cascade do |t|
155 create_table "rights_roles", id: false, force: :cascade do |t|
137 t.integer "right_id", limit: 4
156 t.integer "right_id", limit: 4
138 t.integer "role_id", limit: 4
157 t.integer "role_id", limit: 4
139 end
158 end
140
159
141 add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
160 add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
142
161
143 create_table "roles", force: :cascade do |t|
162 create_table "roles", force: :cascade do |t|
144 t.string "name", limit: 255
163 t.string "name", limit: 255
145 end
164 end
146
165
147 create_table "roles_users", id: false, force: :cascade do |t|
166 create_table "roles_users", id: false, force: :cascade do |t|
148 t.integer "role_id", limit: 4
167 t.integer "role_id", limit: 4
149 t.integer "user_id", limit: 4
168 t.integer "user_id", limit: 4
150 end
169 end
151
170
152 add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
171 add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
153
172
154 create_table "sessions", force: :cascade do |t|
173 create_table "sessions", force: :cascade do |t|
155 t.string "session_id", limit: 255
174 t.string "session_id", limit: 255
156 t.text "data", limit: 65535
175 t.text "data", limit: 65535
157 t.datetime "updated_at"
176 t.datetime "updated_at"
158 end
177 end
159
178
160 add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
179 add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
161 add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
180 add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
162
181
163 create_table "sites", force: :cascade do |t|
182 create_table "sites", force: :cascade do |t|
164 t.string "name", limit: 255
183 t.string "name", limit: 255
165 t.boolean "started"
184 t.boolean "started"
166 t.datetime "start_time"
185 t.datetime "start_time"
167 t.datetime "created_at", null: false
186 t.datetime "created_at", null: false
168 t.datetime "updated_at", null: false
187 t.datetime "updated_at", null: false
169 t.integer "country_id", limit: 4
188 t.integer "country_id", limit: 4
170 t.string "password", limit: 255
189 t.string "password", limit: 255
171 end
190 end
172
191
173 create_table "submission_view_logs", force: :cascade do |t|
192 create_table "submission_view_logs", force: :cascade do |t|
174 t.integer "user_id", limit: 4
193 t.integer "user_id", limit: 4
175 t.integer "submission_id", limit: 4
194 t.integer "submission_id", limit: 4
176 t.datetime "created_at", null: false
195 t.datetime "created_at", null: false
177 t.datetime "updated_at", null: false
196 t.datetime "updated_at", null: false
@@ -70,189 +70,198
70
70
71 {
71 {
72 :key => 'right.user_view_submission',
72 :key => 'right.user_view_submission',
73 :value_type => 'boolean',
73 :value_type => 'boolean',
74 :default_value => 'false',
74 :default_value => 'false',
75 :description => 'If true, any user can view submissions of every one.'
75 :description => 'If true, any user can view submissions of every one.'
76 },
76 },
77
77
78 {
78 {
79 :key => 'right.bypass_agreement',
79 :key => 'right.bypass_agreement',
80 :value_type => 'boolean',
80 :value_type => 'boolean',
81 :default_value => 'true',
81 :default_value => 'true',
82 :description => 'When false, a user must accept usage agreement before login'
82 :description => 'When false, a user must accept usage agreement before login'
83 },
83 },
84
84
85 {
85 {
86 :key => 'right.heartbeat_response',
86 :key => 'right.heartbeat_response',
87 :value_type => 'string',
87 :value_type => 'string',
88 :default_value => 'OK',
88 :default_value => 'OK',
89 :description => 'Heart beat response text'
89 :description => 'Heart beat response text'
90 },
90 },
91
91
92 {
92 {
93 :key => 'right.heartbeat_response_full',
93 :key => 'right.heartbeat_response_full',
94 :value_type => 'string',
94 :value_type => 'string',
95 :default_value => 'OK',
95 :default_value => 'OK',
96 :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
96 :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
97 },
97 },
98
98
99 {
99 {
100 :key => 'right.view_testcase',
100 :key => 'right.view_testcase',
101 :value_type => 'boolean',
101 :value_type => 'boolean',
102 :default_value => 'false',
102 :default_value => 'false',
103 :description => 'When true, any user can view/download test data'
103 :description => 'When true, any user can view/download test data'
104 },
104 },
105 # If Configuration['system.online_registration'] is true, the
105 # If Configuration['system.online_registration'] is true, the
106 # system allows online registration, and will use these
106 # system allows online registration, and will use these
107 # information for sending confirmation emails.
107 # information for sending confirmation emails.
108 {
108 {
109 :key => 'system.online_registration.smtp',
109 :key => 'system.online_registration.smtp',
110 :value_type => 'string',
110 :value_type => 'string',
111 :default_value => 'smtp.somehost.com'
111 :default_value => 'smtp.somehost.com'
112 },
112 },
113
113
114 {
114 {
115 :key => 'system.online_registration.from',
115 :key => 'system.online_registration.from',
116 :value_type => 'string',
116 :value_type => 'string',
117 :default_value => 'your.email@address'
117 :default_value => 'your.email@address'
118 },
118 },
119
119
120 {
120 {
121 :key => 'system.admin_email',
121 :key => 'system.admin_email',
122 :value_type => 'string',
122 :value_type => 'string',
123 :default_value => 'admin@admin.email'
123 :default_value => 'admin@admin.email'
124 },
124 },
125
125
126 {
126 {
127 :key => 'system.user_setting_enabled',
127 :key => 'system.user_setting_enabled',
128 :value_type => 'boolean',
128 :value_type => 'boolean',
129 :default_value => 'true',
129 :default_value => 'true',
130 :description => 'If this option is true, users can change their settings'
130 :description => 'If this option is true, users can change their settings'
131 },
131 },
132
132
133 {
133 {
134 :key => 'system.user_setting_enabled',
134 :key => 'system.user_setting_enabled',
135 :value_type => 'boolean',
135 :value_type => 'boolean',
136 :default_value => 'true',
136 :default_value => 'true',
137 :description => 'If this option is true, users can change their settings'
137 :description => 'If this option is true, users can change their settings'
138 },
138 },
139
139
140 # If Configuration['contest.test_request.early_timeout'] is true
140 # If Configuration['contest.test_request.early_timeout'] is true
141 # the user will not be able to use test request at 30 minutes
141 # the user will not be able to use test request at 30 minutes
142 # before the contest ends.
142 # before the contest ends.
143 {
143 {
144 :key => 'contest.test_request.early_timeout',
144 :key => 'contest.test_request.early_timeout',
145 :value_type => 'boolean',
145 :value_type => 'boolean',
146 :default_value => 'false'
146 :default_value => 'false'
147 },
147 },
148
148
149 {
149 {
150 :key => 'system.multicontests',
150 :key => 'system.multicontests',
151 :value_type => 'boolean',
151 :value_type => 'boolean',
152 :default_value => 'false'
152 :default_value => 'false'
153 },
153 },
154
154
155 {
155 {
156 :key => 'contest.confirm_indv_contest_start',
156 :key => 'contest.confirm_indv_contest_start',
157 :value_type => 'boolean',
157 :value_type => 'boolean',
158 :default_value => 'false'
158 :default_value => 'false'
159 },
159 },
160
160
161 {
161 {
162 :key => 'contest.default_contest_name',
162 :key => 'contest.default_contest_name',
163 :value_type => 'string',
163 :value_type => 'string',
164 :default_value => 'none',
164 :default_value => 'none',
165 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
165 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
166 - }
166 + },
167 +
168 + {
169 + :key => 'system.use_problem_group',
170 + :value_type => 'boolean',
171 + :default_value => 'false',
172 + :description => "If true, available problem to the user will be only ones associated with the group of the user."
173 + },
174 +
175 +
167
176
168 ]
177 ]
169
178
170
179
171 def create_configuration_key(key,
180 def create_configuration_key(key,
172 value_type,
181 value_type,
173 default_value,
182 default_value,
174 description='')
183 description='')
175 conf = (GraderConfiguration.find_by_key(key) ||
184 conf = (GraderConfiguration.find_by_key(key) ||
176 GraderConfiguration.new(:key => key,
185 GraderConfiguration.new(:key => key,
177 :value_type => value_type,
186 :value_type => value_type,
178 :value => default_value))
187 :value => default_value))
179 conf.description = description
188 conf.description = description
180 conf.save
189 conf.save
181 end
190 end
182
191
183 def seed_config
192 def seed_config
184 CONFIGURATIONS.each do |conf|
193 CONFIGURATIONS.each do |conf|
185 if conf.has_key? :description
194 if conf.has_key? :description
186 desc = conf[:description]
195 desc = conf[:description]
187 else
196 else
188 desc = ''
197 desc = ''
189 end
198 end
190 create_configuration_key(conf[:key],
199 create_configuration_key(conf[:key],
191 conf[:value_type],
200 conf[:value_type],
192 conf[:default_value],
201 conf[:default_value],
193 desc)
202 desc)
194 end
203 end
195 end
204 end
196
205
197 def seed_roles
206 def seed_roles
198 return if Role.find_by_name('admin')
207 return if Role.find_by_name('admin')
199
208
200 role = Role.create(:name => 'admin')
209 role = Role.create(:name => 'admin')
201 user_admin_right = Right.create(:name => 'user_admin',
210 user_admin_right = Right.create(:name => 'user_admin',
202 :controller => 'user_admin',
211 :controller => 'user_admin',
203 :action => 'all')
212 :action => 'all')
204 problem_admin_right = Right.create(:name=> 'problem_admin',
213 problem_admin_right = Right.create(:name=> 'problem_admin',
205 :controller => 'problems',
214 :controller => 'problems',
206 :action => 'all')
215 :action => 'all')
207
216
208 graders_right = Right.create(:name => 'graders_admin',
217 graders_right = Right.create(:name => 'graders_admin',
209 :controller => 'graders',
218 :controller => 'graders',
210 :action => 'all')
219 :action => 'all')
211
220
212 role.rights << user_admin_right;
221 role.rights << user_admin_right;
213 role.rights << problem_admin_right;
222 role.rights << problem_admin_right;
214 role.rights << graders_right;
223 role.rights << graders_right;
215 role.save
224 role.save
216 end
225 end
217
226
218 def seed_root
227 def seed_root
219 return if User.find_by_login('root')
228 return if User.find_by_login('root')
220
229
221 root = User.new(:login => 'root',
230 root = User.new(:login => 'root',
222 :full_name => 'Administrator',
231 :full_name => 'Administrator',
223 :alias => 'root')
232 :alias => 'root')
224 root.password = 'ioionrails';
233 root.password = 'ioionrails';
225
234
226 class << root
235 class << root
227 public :encrypt_new_password
236 public :encrypt_new_password
228 def valid?(context=nil)
237 def valid?(context=nil)
229 true
238 true
230 end
239 end
231 end
240 end
232
241
233 root.encrypt_new_password
242 root.encrypt_new_password
234
243
235 root.roles << Role.find_by_name('admin')
244 root.roles << Role.find_by_name('admin')
236
245
237 root.activated = true
246 root.activated = true
238 root.save
247 root.save
239 end
248 end
240
249
241 def seed_users_and_roles
250 def seed_users_and_roles
242 seed_roles
251 seed_roles
243 seed_root
252 seed_root
244 end
253 end
245
254
246 def seed_more_languages
255 def seed_more_languages
247 Language.delete_all
256 Language.delete_all
248 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
257 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
249 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
258 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
250 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
259 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
251 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
260 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
252 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
261 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
253 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
262 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
254 end
263 end
255
264
256 seed_config
265 seed_config
257 seed_users_and_roles
266 seed_users_and_roles
258 seed_more_languages
267 seed_more_languages
You need to be logged in to leave comments. Login now