Description:
merged
Commit status:
[Not Reviewed]
References:
merge java
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r685:101d67319b73 - - 43 files changed: 525 inserted, 159 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,20
1 + %h1 Editing contest
2 + = form_for(@contest) do |f|
3 + = f.error_messages
4 + %table
5 + %tr
6 + %td= f.label :name
7 + %td= f.text_field :name
8 + %tr
9 + %td= f.label :title
10 + %td= f.text_field :title
11 + %tr
12 + %td
13 + %td
14 + = f.check_box :enabled
15 + = f.label :enabled
16 + %p
17 + = f.submit 'Update'
18 + = link_to 'Show', @contest
19 + |
20 + = link_to 'Back', contests_path
@@ -0,0 +1,27
1 + %h1 Listing contests
2 + .infobox
3 + %b Go back to:
4 + [#{link_to 'contest management', :controller => 'contest_management', :action => 'index'}]
5 + %p= link_to 'New contest', new_contest_path, class: 'btn btn-success'
6 + %table.table.table-striped
7 + %tr
8 + %th Name
9 + %th Title
10 + %th Enabled
11 + %th
12 + %th
13 + %th
14 +
15 + - @contests.each do |contest|
16 + - @contest = contest
17 + %tr
18 + -#%td= in_place_editor_field :contest, :name, {}, :rows => 1
19 + -#%td= in_place_editor_field :contest, :title, {}, :rows => 1
20 + -#%td= in_place_editor_field :contest, :enabled, {}, :rows => 1
21 + %td= best_in_place @contest, :name
22 + %td= best_in_place @contest, :title
23 + %td= best_in_place @contest, :enabled
24 + %td= link_to 'Show', contest
25 + %td= link_to 'Edit', edit_contest_path(contest)
26 + %td= link_to 'Destroy', contest, :confirm => 'Are you sure?', :method => :delete
27 + %br/
@@ -0,0 +1,18
1 + %h1 New contest
2 + = form_for(@contest) do |f|
3 + = f.error_messages
4 + %p
5 + = f.label :name
6 + %br/
7 + = f.text_field :name
8 + %p
9 + = f.label :title
10 + %br/
11 + = f.text_field :title
12 + %p
13 + = f.label :enabled
14 + %br/
15 + = f.check_box :enabled
16 + %p
17 + = f.submit 'Create'
18 + = link_to 'Back', contests_path
@@ -0,0 +1,11
1 + %h1
2 + Contest: #{h @contest.title}
3 + .infobox
4 + %b Go back to:
5 + [#{link_to 'contest management', :controller => 'contest_management', :action => 'index'}]
6 + %p
7 + %b Enabled:
8 + = h @contest.enabled
9 + = link_to 'Edit', edit_contest_path(@contest)
10 + |
11 + = link_to 'Back', contests_path
@@ -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,22
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 +
13 + %tbody
14 + - @groups.each do |group|
15 + %tr
16 + %td= group.name
17 + %td= group.description
18 + %td= link_to 'View', group, class: 'btn btn-default'
19 + %td= link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
20 +
21 + %br
22 +
@@ -0,0 +1,5
1 + %h1 New group
2 +
3 + = render 'form'
4 +
5 + = link_to 'Back', groups_path
@@ -0,0 +1,72
1 + %p
2 + %b Name:
3 + = @group.name
4 + %p
5 + %b Description:
6 + = @group.description
7 +
8 + %br
9 + = link_to 'Edit', edit_group_path(@group)
10 + \|
11 + = link_to 'Back', groups_path
12 +
13 + .row
14 + %h1 Group details
15 + .row
16 + .col-md-6
17 + .panel.panel-default
18 + .panel-heading
19 + .panel-title Users in this group
20 + .panel-body
21 + =form_tag add_user_group_path(@group), class: 'form-inline' do
22 + .form-group
23 + =label_tag :user_id, "User"
24 + =select_tag :user_id, options_from_collection_for_select(User.all,'id','full_name'), class: 'select2'
25 + =submit_tag "Add",class: 'btn btn-primary'
26 +
27 +
28 + %table.table.table-hover
29 + %thead
30 + %tr
31 + %th Login
32 + %th Full name
33 + %th Remark
34 + %th
35 +
36 + %tbody
37 + - @group.users.each do |user|
38 + %tr
39 + %td= user.login
40 + %td= user.full_name
41 + %td= user.remark
42 + %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger'
43 + .col-md-6
44 + .panel.panel-default
45 + .panel-heading
46 + .panel-title Problems
47 + .panel-body
48 +
49 + =form_tag add_problem_group_path(@group), class: 'form-inline' do
50 + .form-group
51 + =label_tag :problem_id, "Problem"
52 + =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','full_name'), class: 'select2'
53 + =submit_tag "Add",class: 'btn btn-primary'
54 +
55 +
56 + %table.table.table-hover
57 + %thead
58 + %tr
59 + %th name
60 + %th Full name
61 + %th Full score
62 + %th
63 +
64 + %tbody
65 + - @group.problems.each do |problem|
66 + %tr
67 + %td= problem.name
68 + %td= problem.full_name
69 + %td= problem.full_score
70 + %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger'
71 +
72 +
@@ -0,0 +1,31
1 + = error_messages_for 'user'
2 + / [form:user]
3 + .form-group
4 + %label.col-md-2.control-label{for: :login} Login
5 + .col-md-4
6 + = text_field 'user', 'login', class: 'form-control'
7 + .form-group
8 + %label.col-md-2.control-label{for: :full_name} Full name
9 + .col-md-4
10 + = text_field 'user', 'full_name', class: 'form-control'
11 + .form-group
12 + %label.col-md-2.control-label{for: :password} Password
13 + .col-md-4
14 + = password_field 'user', 'password', class: 'form-control'
15 + .form-group
16 + %label.col-md-2.control-label{for: :password_confirmation} Password (confirm)
17 + .col-md-4
18 + = password_field 'user', 'password_confirmation', class: 'form-control'
19 + .form-group
20 + %label.col-md-2.control-label{for: :email} E-mail
21 + .col-md-4
22 + = email_field 'user', 'email', class: 'form-control'
23 + .form-group
24 + %label.col-md-2.control-label{for: :alias} Alias
25 + .col-md-4
26 + = text_field 'user', 'alias', class: 'form-control'
27 + .form-group
28 + %label.col-md-2.control-label{for: :remark} Remark
29 + .col-md-4
30 + = text_field 'user', 'remark', class: 'form-control'
31 + / [eoform:user]
@@ -0,0 +1,14
1 + %h1 User information
2 + - for column in User.content_columns
3 + %p
4 + %b
5 + = column.human_name
6 + \:
7 + = h @user.send(column.name)
8 + %p
9 + %strong Group
10 + \:
11 + = @user.groups.map{ |x| link_to(x.name,group_path(x)).html_safe}.join(', ').html_safe
12 + = link_to 'Edit', :action => 'edit', :id => @user
13 + |
14 + = link_to 'Back', :action => 'index'
@@ -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
@@ -1,140 +1,138
1 class ApplicationController < ActionController::Base
1 class ApplicationController < ActionController::Base
2 protect_from_forgery
2 protect_from_forgery
3
3
4 before_filter :current_user
4 before_filter :current_user
5
5
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
8
8
9 #report and redirect for unauthorized activities
9 #report and redirect for unauthorized activities
10 def unauthorized_redirect
10 def unauthorized_redirect
11 flash[:notice] = 'You are not authorized to view the page you requested'
11 flash[:notice] = 'You are not authorized to view the page you requested'
12 redirect_to :controller => 'main', :action => 'login'
12 redirect_to :controller => 'main', :action => 'login'
13 end
13 end
14
14
15 # Returns the current logged-in user (if any).
15 # Returns the current logged-in user (if any).
16 def current_user
16 def current_user
17 return nil unless session[:user_id]
17 return nil unless session[:user_id]
18 @current_user ||= User.find(session[:user_id])
18 @current_user ||= User.find(session[:user_id])
19 end
19 end
20
20
21 def admin_authorization
21 def admin_authorization
22 return false unless authenticate
22 return false unless authenticate
23 user = User.includes(:roles).find(session[:user_id])
23 user = User.includes(:roles).find(session[:user_id])
24 unless user.admin?
24 unless user.admin?
25 unauthorized_redirect
25 unauthorized_redirect
26 return false
26 return false
27 end
27 end
28 return true
28 return true
29 end
29 end
30
30
31 def authorization_by_roles(allowed_roles)
31 def authorization_by_roles(allowed_roles)
32 return false unless authenticate
32 return false unless authenticate
33 user = User.find(session[:user_id])
33 user = User.find(session[:user_id])
34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
35 unauthorized_redirect
35 unauthorized_redirect
36 return false
36 return false
37 end
37 end
38 end
38 end
39
39
40 def testcase_authorization
40 def testcase_authorization
41 #admin always has privileged
41 #admin always has privileged
42 - puts "haha"
43 if @current_user.admin?
42 if @current_user.admin?
44 return true
43 return true
45 end
44 end
46
45
47 - puts "hehe"
48 - puts GraderConfiguration["right.view_testcase"]
49 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
46 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
50 end
47 end
51
48
52 protected
49 protected
53
50
54 def authenticate
51 def authenticate
55 unless session[:user_id]
52 unless session[:user_id]
56 flash[:notice] = 'You need to login'
53 flash[:notice] = 'You need to login'
57 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
54 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
58 flash[:notice] = 'You need to login but you cannot log in at this time'
55 flash[:notice] = 'You need to login but you cannot log in at this time'
59 end
56 end
60 redirect_to :controller => 'main', :action => 'login'
57 redirect_to :controller => 'main', :action => 'login'
61 return false
58 return false
62 end
59 end
63
60
61 +
64 # check if run in single user mode
62 # check if run in single user mode
65 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
63 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
66 - user = User.find_by_id(session[:user_id])
64 + if @current_user==nil or (not @current_user.admin?)
67 - if user==nil or (not user.admin?)
68 flash[:notice] = 'You cannot log in at this time'
65 flash[:notice] = 'You cannot log in at this time'
69 redirect_to :controller => 'main', :action => 'login'
66 redirect_to :controller => 'main', :action => 'login'
70 return false
67 return false
71 end
68 end
72 - unless user.enabled?
73 - flash[:notice] = 'Your account is disabled'
74 - redirect_to :controller => 'main', :action => 'login'
75 - return false
76 - end
77 return true
69 return true
78 end
70 end
79
71
72 + # check if the user is enabled
73 + unless @current_user.enabled? or @current_user.admin?
74 + flash[:notice] = 'Your account is disabled'
75 + redirect_to :controller => 'main', :action => 'login'
76 + return false
77 + end
78 +
80 if GraderConfiguration.multicontests?
79 if GraderConfiguration.multicontests?
81 - user = User.find(session[:user_id])
80 + return true if @current_user.admin?
82 - return true if user.admin?
83 begin
81 begin
84 - if user.contest_stat(true).forced_logout
82 + if @current_user.contest_stat(true).forced_logout
85 flash[:notice] = 'You have been automatically logged out.'
83 flash[:notice] = 'You have been automatically logged out.'
86 redirect_to :controller => 'main', :action => 'index'
84 redirect_to :controller => 'main', :action => 'index'
87 end
85 end
88 rescue
86 rescue
89 end
87 end
90 end
88 end
91 return true
89 return true
92 end
90 end
93
91
94 def authenticate_by_ip_address
92 def authenticate_by_ip_address
95 #this assume that we have already authenticate normally
93 #this assume that we have already authenticate normally
96 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
94 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
97 user = User.find(session[:user_id])
95 user = User.find(session[:user_id])
98 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
96 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
99 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
97 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
100 redirect_to :controller => 'main', :action => 'login'
98 redirect_to :controller => 'main', :action => 'login'
101 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
99 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
102 return false
100 return false
103 end
101 end
104 unless user.last_ip
102 unless user.last_ip
105 user.last_ip = request.remote_ip
103 user.last_ip = request.remote_ip
106 user.save
104 user.save
107 end
105 end
108 end
106 end
109 return true
107 return true
110 end
108 end
111
109
112 def authorization
110 def authorization
113 return false unless authenticate
111 return false unless authenticate
114 user = User.find(session[:user_id])
112 user = User.find(session[:user_id])
115 unless user.roles.detect { |role|
113 unless user.roles.detect { |role|
116 role.rights.detect{ |right|
114 role.rights.detect{ |right|
117 right.controller == self.class.controller_name and
115 right.controller == self.class.controller_name and
118 (right.action == 'all' or right.action == action_name)
116 (right.action == 'all' or right.action == action_name)
119 }
117 }
120 }
118 }
121 flash[:notice] = 'You are not authorized to view the page you requested'
119 flash[:notice] = 'You are not authorized to view the page you requested'
122 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
120 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
123 redirect_to :controller => 'main', :action => 'login'
121 redirect_to :controller => 'main', :action => 'login'
124 return false
122 return false
125 end
123 end
126 end
124 end
127
125
128 def verify_time_limit
126 def verify_time_limit
129 return true if session[:user_id]==nil
127 return true if session[:user_id]==nil
130 user = User.find(session[:user_id], :include => :site)
128 user = User.find(session[:user_id], :include => :site)
131 return true if user==nil or user.site == nil
129 return true if user==nil or user.site == nil
132 if user.contest_finished?
130 if user.contest_finished?
133 flash[:notice] = 'Error: the contest you are participating is over.'
131 flash[:notice] = 'Error: the contest you are participating is over.'
134 redirect_to :back
132 redirect_to :back
135 return false
133 return false
136 end
134 end
137 return true
135 return true
138 end
136 end
139
137
140 end
138 end
@@ -6,289 +6,294
6 in_place_edit_for :problem, :name
6 in_place_edit_for :problem, :name
7 in_place_edit_for :problem, :full_name
7 in_place_edit_for :problem, :full_name
8 in_place_edit_for :problem, :full_score
8 in_place_edit_for :problem, :full_score
9
9
10 def index
10 def index
11 @problems = Problem.order(date_added: :desc)
11 @problems = Problem.order(date_added: :desc)
12 end
12 end
13
13
14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
15 verify :method => :post, :only => [ :create, :quick_create,
15 verify :method => :post, :only => [ :create, :quick_create,
16 :do_manage,
16 :do_manage,
17 :do_import,
17 :do_import,
18 ],
18 ],
19 :redirect_to => { :action => :index }
19 :redirect_to => { :action => :index }
20
20
21 def show
21 def show
22 @problem = Problem.find(params[:id])
22 @problem = Problem.find(params[:id])
23 end
23 end
24
24
25 def new
25 def new
26 @problem = Problem.new
26 @problem = Problem.new
27 @description = nil
27 @description = nil
28 end
28 end
29
29
30 def create
30 def create
31 @problem = Problem.new(problem_params)
31 @problem = Problem.new(problem_params)
32 @description = Description.new(params[:description])
32 @description = Description.new(params[:description])
33 if @description.body!=''
33 if @description.body!=''
34 if !@description.save
34 if !@description.save
35 render :action => new and return
35 render :action => new and return
36 end
36 end
37 else
37 else
38 @description = nil
38 @description = nil
39 end
39 end
40 @problem.description = @description
40 @problem.description = @description
41 if @problem.save
41 if @problem.save
42 flash[:notice] = 'Problem was successfully created.'
42 flash[:notice] = 'Problem was successfully created.'
43 redirect_to action: :index
43 redirect_to action: :index
44 else
44 else
45 render :action => 'new'
45 render :action => 'new'
46 end
46 end
47 end
47 end
48
48
49 def quick_create
49 def quick_create
50 @problem = Problem.new(problem_params)
50 @problem = Problem.new(problem_params)
51 @problem.full_name = @problem.name if @problem.full_name == ''
51 @problem.full_name = @problem.name if @problem.full_name == ''
52 @problem.full_score = 100
52 @problem.full_score = 100
53 @problem.available = false
53 @problem.available = false
54 @problem.test_allowed = true
54 @problem.test_allowed = true
55 @problem.output_only = false
55 @problem.output_only = false
56 @problem.date_added = Time.new
56 @problem.date_added = Time.new
57 if @problem.save
57 if @problem.save
58 flash[:notice] = 'Problem was successfully created.'
58 flash[:notice] = 'Problem was successfully created.'
59 redirect_to action: :index
59 redirect_to action: :index
60 else
60 else
61 flash[:notice] = 'Error saving problem'
61 flash[:notice] = 'Error saving problem'
62 redirect_to action: :index
62 redirect_to action: :index
63 end
63 end
64 end
64 end
65
65
66 def edit
66 def edit
67 @problem = Problem.find(params[:id])
67 @problem = Problem.find(params[:id])
68 @description = @problem.description
68 @description = @problem.description
69 end
69 end
70
70
71 def update
71 def update
72 @problem = Problem.find(params[:id])
72 @problem = Problem.find(params[:id])
73 @description = @problem.description
73 @description = @problem.description
74 if @description.nil? and params[:description][:body]!=''
74 if @description.nil? and params[:description][:body]!=''
75 @description = Description.new(params[:description])
75 @description = Description.new(params[:description])
76 if !@description.save
76 if !@description.save
77 flash[:notice] = 'Error saving description'
77 flash[:notice] = 'Error saving description'
78 render :action => 'edit' and return
78 render :action => 'edit' and return
79 end
79 end
80 @problem.description = @description
80 @problem.description = @description
81 elsif @description
81 elsif @description
82 if !@description.update_attributes(params[:description])
82 if !@description.update_attributes(params[:description])
83 flash[:notice] = 'Error saving description'
83 flash[:notice] = 'Error saving description'
84 render :action => 'edit' and return
84 render :action => 'edit' and return
85 end
85 end
86 end
86 end
87 if params[:file] and params[:file].content_type != 'application/pdf'
87 if params[:file] and params[:file].content_type != 'application/pdf'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
89 render :action => 'edit' and return
89 render :action => 'edit' and return
90 end
90 end
91 if @problem.update_attributes(problem_params)
91 if @problem.update_attributes(problem_params)
92 flash[:notice] = 'Problem was successfully updated.'
92 flash[:notice] = 'Problem was successfully updated.'
93 unless params[:file] == nil or params[:file] == ''
93 unless params[:file] == nil or params[:file] == ''
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
96 if not FileTest.exists? out_dirname
96 if not FileTest.exists? out_dirname
97 Dir.mkdir out_dirname
97 Dir.mkdir out_dirname
98 end
98 end
99
99
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
101 if FileTest.exists? out_filename
101 if FileTest.exists? out_filename
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
294 end
299 end
@@ -39,550 +39,557
39 end
39 end
40
40
41 def show
41 def show
42 @user = User.find(params[:id])
42 @user = User.find(params[:id])
43 end
43 end
44
44
45 def new
45 def new
46 @user = User.new
46 @user = User.new
47 end
47 end
48
48
49 def create
49 def create
50 @user = User.new(user_params)
50 @user = User.new(user_params)
51 @user.activated = true
51 @user.activated = true
52 if @user.save
52 if @user.save
53 flash[:notice] = 'User was successfully created.'
53 flash[:notice] = 'User was successfully created.'
54 redirect_to :action => 'index'
54 redirect_to :action => 'index'
55 else
55 else
56 render :action => 'new'
56 render :action => 'new'
57 end
57 end
58 end
58 end
59
59
60 def clear_last_ip
60 def clear_last_ip
61 @user = User.find(params[:id])
61 @user = User.find(params[:id])
62 @user.last_ip = nil
62 @user.last_ip = nil
63 @user.save
63 @user.save
64 redirect_to action: 'index', page: params[:page]
64 redirect_to action: 'index', page: params[:page]
65 end
65 end
66
66
67 def create_from_list
67 def create_from_list
68 lines = params[:user_list]
68 lines = params[:user_list]
69
69
70 note = []
70 note = []
71
71
72 lines.split("\n").each do |line|
72 lines.split("\n").each do |line|
73 items = line.chomp.split(',')
73 items = line.chomp.split(',')
74 if items.length>=2
74 if items.length>=2
75 login = items[0]
75 login = items[0]
76 full_name = items[1]
76 full_name = items[1]
77 remark =''
77 remark =''
78 user_alias = ''
78 user_alias = ''
79
79
80 added_random_password = false
80 added_random_password = false
81 if items.length >= 3 and items[2].chomp(" ").length > 0;
81 if items.length >= 3 and items[2].chomp(" ").length > 0;
82 password = items[2].chomp(" ")
82 password = items[2].chomp(" ")
83 else
83 else
84 password = random_password
84 password = random_password
85 add_random_password=true;
85 add_random_password=true;
86 end
86 end
87
87
88 if items.length>= 4 and items[3].chomp(" ").length > 0;
88 if items.length>= 4 and items[3].chomp(" ").length > 0;
89 user_alias = items[3].chomp(" ")
89 user_alias = items[3].chomp(" ")
90 else
90 else
91 user_alias = login
91 user_alias = login
92 end
92 end
93
93
94 if items.length>=5
94 if items.length>=5
95 remark = items[4].strip;
95 remark = items[4].strip;
96 end
96 end
97
97
98 user = User.find_by_login(login)
98 user = User.find_by_login(login)
99 if (user)
99 if (user)
100 user.full_name = full_name
100 user.full_name = full_name
101 user.password = password
101 user.password = password
102 user.remark = remark
102 user.remark = remark
103 else
103 else
104 user = User.new({:login => login,
104 user = User.new({:login => login,
105 :full_name => full_name,
105 :full_name => full_name,
106 :password => password,
106 :password => password,
107 :password_confirmation => password,
107 :password_confirmation => password,
108 :alias => user_alias,
108 :alias => user_alias,
109 :remark => remark})
109 :remark => remark})
110 end
110 end
111 user.activated = true
111 user.activated = true
112 user.save
112 user.save
113
113
114 if added_random_password
114 if added_random_password
115 note << "'#{login}' (+)"
115 note << "'#{login}' (+)"
116 else
116 else
117 note << login
117 note << login
118 end
118 end
119 end
119 end
120 end
120 end
121 flash[:success] = 'User(s) ' + note.join(', ') +
121 flash[:success] = 'User(s) ' + note.join(', ') +
122 ' were successfully created. ' +
122 ' were successfully created. ' +
123 '( (+) - created with random passwords.)'
123 '( (+) - created with random passwords.)'
124 redirect_to :action => 'index'
124 redirect_to :action => 'index'
125 end
125 end
126
126
127 def edit
127 def edit
128 @user = User.find(params[:id])
128 @user = User.find(params[:id])
129 end
129 end
130
130
131 def update
131 def update
132 @user = User.find(params[:id])
132 @user = User.find(params[:id])
133 if @user.update_attributes(user_params)
133 if @user.update_attributes(user_params)
134 flash[:notice] = 'User was successfully updated.'
134 flash[:notice] = 'User was successfully updated.'
135 redirect_to :action => 'show', :id => @user
135 redirect_to :action => 'show', :id => @user
136 else
136 else
137 render :action => 'edit'
137 render :action => 'edit'
138 end
138 end
139 end
139 end
140
140
141 def destroy
141 def destroy
142 User.find(params[:id]).destroy
142 User.find(params[:id]).destroy
143 redirect_to :action => 'index'
143 redirect_to :action => 'index'
144 end
144 end
145
145
146 def user_stat
146 def user_stat
147 if params[:commit] == 'download csv'
147 if params[:commit] == 'download csv'
148 @problems = Problem.all
148 @problems = Problem.all
149 else
149 else
150 @problems = Problem.available_problems
150 @problems = Problem.available_problems
151 end
151 end
152 @users = User.includes(:contests, :contest_stat).where(enabled: true)
152 @users = User.includes(:contests, :contest_stat).where(enabled: true)
153 @scorearray = Array.new
153 @scorearray = Array.new
154 @users.each do |u|
154 @users.each do |u|
155 ustat = Array.new
155 ustat = Array.new
156 ustat[0] = u
156 ustat[0] = u
157 @problems.each do |p|
157 @problems.each do |p|
158 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
158 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
159 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
159 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
160 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
160 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
161 else
161 else
162 ustat << [0,false]
162 ustat << [0,false]
163 end
163 end
164 end
164 end
165 @scorearray << ustat
165 @scorearray << ustat
166 end
166 end
167 if params[:commit] == 'download csv' then
167 if params[:commit] == 'download csv' then
168 csv = gen_csv_from_scorearray(@scorearray,@problems)
168 csv = gen_csv_from_scorearray(@scorearray,@problems)
169 send_data csv, filename: 'last_score.csv'
169 send_data csv, filename: 'last_score.csv'
170 else
170 else
171 render template: 'user_admin/user_stat'
171 render template: 'user_admin/user_stat'
172 end
172 end
173 end
173 end
174
174
175 def user_stat_max
175 def user_stat_max
176 if params[:commit] == 'download csv'
176 if params[:commit] == 'download csv'
177 @problems = Problem.all
177 @problems = Problem.all
178 else
178 else
179 @problems = Problem.available_problems
179 @problems = Problem.available_problems
180 end
180 end
181 @users = User.includes(:contests).includes(:contest_stat).all
181 @users = User.includes(:contests).includes(:contest_stat).all
182 @scorearray = Array.new
182 @scorearray = Array.new
183 #set up range from param
183 #set up range from param
184 since_id = params.fetch(:since_id, 0).to_i
184 since_id = params.fetch(:since_id, 0).to_i
185 until_id = params.fetch(:until_id, 0).to_i
185 until_id = params.fetch(:until_id, 0).to_i
186 @users.each do |u|
186 @users.each do |u|
187 ustat = Array.new
187 ustat = Array.new
188 ustat[0] = u
188 ustat[0] = u
189 @problems.each do |p|
189 @problems.each do |p|
190 max_points = 0
190 max_points = 0
191 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
191 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
192 max_points = sub.points if sub and sub.points and (sub.points > max_points)
192 max_points = sub.points if sub and sub.points and (sub.points > max_points)
193 end
193 end
194 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
194 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
195 end
195 end
196 @scorearray << ustat
196 @scorearray << ustat
197 end
197 end
198
198
199 if params[:commit] == 'download csv' then
199 if params[:commit] == 'download csv' then
200 csv = gen_csv_from_scorearray(@scorearray,@problems)
200 csv = gen_csv_from_scorearray(@scorearray,@problems)
201 send_data csv, filename: 'max_score.csv'
201 send_data csv, filename: 'max_score.csv'
202 else
202 else
203 render template: 'user_admin/user_stat'
203 render template: 'user_admin/user_stat'
204 end
204 end
205 end
205 end
206
206
207 def import
207 def import
208 if params[:file]==''
208 if params[:file]==''
209 flash[:notice] = 'Error importing no file'
209 flash[:notice] = 'Error importing no file'
210 redirect_to :action => 'index' and return
210 redirect_to :action => 'index' and return
211 end
211 end
212 import_from_file(params[:file])
212 import_from_file(params[:file])
213 end
213 end
214
214
215 def random_all_passwords
215 def random_all_passwords
216 users = User.all
216 users = User.all
217 @prefix = params[:prefix] || ''
217 @prefix = params[:prefix] || ''
218 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
218 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
219 @changed = false
219 @changed = false
220 if request.request_method == 'POST'
220 if request.request_method == 'POST'
221 @non_admin_users.each do |user|
221 @non_admin_users.each do |user|
222 password = random_password
222 password = random_password
223 user.password = password
223 user.password = password
224 user.password_confirmation = password
224 user.password_confirmation = password
225 user.save
225 user.save
226 end
226 end
227 @changed = true
227 @changed = true
228 end
228 end
229 end
229 end
230
230
231 +
231 # contest management
232 # contest management
232
233
233 def contests
234 def contests
234 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
235 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
235 @contests = Contest.enabled
236 @contests = Contest.enabled
236 end
237 end
237
238
238 def assign_from_list
239 def assign_from_list
239 contest_id = params[:users_contest_id]
240 contest_id = params[:users_contest_id]
240 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
241 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
241 contest = Contest.find(params[:new_contest][:id])
242 contest = Contest.find(params[:new_contest][:id])
242 if !contest
243 if !contest
243 flash[:notice] = 'Error: no contest'
244 flash[:notice] = 'Error: no contest'
244 redirect_to :action => 'contests', :id =>contest_id
245 redirect_to :action => 'contests', :id =>contest_id
245 end
246 end
246
247
247 note = []
248 note = []
248 users.each do |u|
249 users.each do |u|
249 u.contests = [contest]
250 u.contests = [contest]
250 note << u.login
251 note << u.login
251 end
252 end
252 flash[:notice] = 'User(s) ' + note.join(', ') +
253 flash[:notice] = 'User(s) ' + note.join(', ') +
253 " were successfully reassigned to #{contest.title}."
254 " were successfully reassigned to #{contest.title}."
254 redirect_to :action => 'contests', :id =>contest.id
255 redirect_to :action => 'contests', :id =>contest.id
255 end
256 end
256
257
257 def add_to_contest
258 def add_to_contest
258 user = User.find(params[:id])
259 user = User.find(params[:id])
259 contest = Contest.find(params[:contest_id])
260 contest = Contest.find(params[:contest_id])
260 if user and contest
261 if user and contest
261 user.contests << contest
262 user.contests << contest
262 end
263 end
263 redirect_to :action => 'index'
264 redirect_to :action => 'index'
264 end
265 end
265
266
266 def remove_from_contest
267 def remove_from_contest
267 user = User.find(params[:id])
268 user = User.find(params[:id])
268 contest = Contest.find(params[:contest_id])
269 contest = Contest.find(params[:contest_id])
269 if user and contest
270 if user and contest
270 user.contests.delete(contest)
271 user.contests.delete(contest)
271 end
272 end
272 redirect_to :action => 'index'
273 redirect_to :action => 'index'
273 end
274 end
274
275
275 def contest_management
276 def contest_management
276 end
277 end
277
278
278 def manage_contest
279 def manage_contest
279 contest = Contest.find(params[:contest][:id])
280 contest = Contest.find(params[:contest][:id])
280 if !contest
281 if !contest
281 flash[:notice] = 'You did not choose the contest.'
282 flash[:notice] = 'You did not choose the contest.'
282 redirect_to :action => 'contest_management' and return
283 redirect_to :action => 'contest_management' and return
283 end
284 end
284
285
285 operation = params[:operation]
286 operation = params[:operation]
286
287
287 if not ['add','remove','assign'].include? operation
288 if not ['add','remove','assign'].include? operation
288 flash[:notice] = 'You did not choose the operation to perform.'
289 flash[:notice] = 'You did not choose the operation to perform.'
289 redirect_to :action => 'contest_management' and return
290 redirect_to :action => 'contest_management' and return
290 end
291 end
291
292
292 lines = params[:login_list]
293 lines = params[:login_list]
293 if !lines or lines.blank?
294 if !lines or lines.blank?
294 flash[:notice] = 'You entered an empty list.'
295 flash[:notice] = 'You entered an empty list.'
295 redirect_to :action => 'contest_management' and return
296 redirect_to :action => 'contest_management' and return
296 end
297 end
297
298
298 note = []
299 note = []
299 users = []
300 users = []
300 lines.split("\n").each do |line|
301 lines.split("\n").each do |line|
301 user = User.find_by_login(line.chomp)
302 user = User.find_by_login(line.chomp)
302 if user
303 if user
303 if operation=='add'
304 if operation=='add'
304 if ! user.contests.include? contest
305 if ! user.contests.include? contest
305 user.contests << contest
306 user.contests << contest
306 end
307 end
307 elsif operation=='remove'
308 elsif operation=='remove'
308 user.contests.delete(contest)
309 user.contests.delete(contest)
309 else
310 else
310 user.contests = [contest]
311 user.contests = [contest]
311 end
312 end
312
313
313 if params[:reset_timer]
314 if params[:reset_timer]
314 user.contest_stat.forced_logout = true
315 user.contest_stat.forced_logout = true
315 user.contest_stat.reset_timer_and_save
316 user.contest_stat.reset_timer_and_save
316 end
317 end
317
318
318 if params[:notification_emails]
319 if params[:notification_emails]
319 send_contest_update_notification_email(user, contest)
320 send_contest_update_notification_email(user, contest)
320 end
321 end
321
322
322 note << user.login
323 note << user.login
323 users << user
324 users << user
324 end
325 end
325 end
326 end
326
327
327 if params[:reset_timer]
328 if params[:reset_timer]
328 logout_users(users)
329 logout_users(users)
329 end
330 end
330
331
331 flash[:notice] = 'User(s) ' + note.join(', ') +
332 flash[:notice] = 'User(s) ' + note.join(', ') +
332 ' were successfully modified. '
333 ' were successfully modified. '
333 redirect_to :action => 'contest_management'
334 redirect_to :action => 'contest_management'
334 end
335 end
335
336
336 # admin management
337 # admin management
337
338
338 def admin
339 def admin
339 @admins = User.all.find_all {|user| user.admin? }
340 @admins = User.all.find_all {|user| user.admin? }
340 end
341 end
341
342
342 def grant_admin
343 def grant_admin
343 login = params[:login]
344 login = params[:login]
344 user = User.find_by_login(login)
345 user = User.find_by_login(login)
345 if user!=nil
346 if user!=nil
346 admin_role = Role.find_by_name('admin')
347 admin_role = Role.find_by_name('admin')
347 user.roles << admin_role
348 user.roles << admin_role
348 else
349 else
349 flash[:notice] = 'Unknown user'
350 flash[:notice] = 'Unknown user'
350 end
351 end
351 flash[:notice] = 'User added as admins'
352 flash[:notice] = 'User added as admins'
352 redirect_to :action => 'admin'
353 redirect_to :action => 'admin'
353 end
354 end
354
355
355 def revoke_admin
356 def revoke_admin
356 user = User.find(params[:id])
357 user = User.find(params[:id])
357 if user==nil
358 if user==nil
358 flash[:notice] = 'Unknown user'
359 flash[:notice] = 'Unknown user'
359 redirect_to :action => 'admin' and return
360 redirect_to :action => 'admin' and return
360 elsif user.login == 'root'
361 elsif user.login == 'root'
361 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
362 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
362 redirect_to :action => 'admin' and return
363 redirect_to :action => 'admin' and return
363 end
364 end
364
365
365 admin_role = Role.find_by_name('admin')
366 admin_role = Role.find_by_name('admin')
366 user.roles.delete(admin_role)
367 user.roles.delete(admin_role)
367 flash[:notice] = 'User permission revoked'
368 flash[:notice] = 'User permission revoked'
368 redirect_to :action => 'admin'
369 redirect_to :action => 'admin'
369 end
370 end
370
371
371 # mass mailing
372 # mass mailing
372
373
373 def mass_mailing
374 def mass_mailing
374 end
375 end
375
376
376 def bulk_mail
377 def bulk_mail
377 lines = params[:login_list]
378 lines = params[:login_list]
378 if !lines or lines.blank?
379 if !lines or lines.blank?
379 flash[:notice] = 'You entered an empty list.'
380 flash[:notice] = 'You entered an empty list.'
380 redirect_to :action => 'mass_mailing' and return
381 redirect_to :action => 'mass_mailing' and return
381 end
382 end
382
383
383 mail_subject = params[:subject]
384 mail_subject = params[:subject]
384 if !mail_subject or mail_subject.blank?
385 if !mail_subject or mail_subject.blank?
385 flash[:notice] = 'You entered an empty mail subject.'
386 flash[:notice] = 'You entered an empty mail subject.'
386 redirect_to :action => 'mass_mailing' and return
387 redirect_to :action => 'mass_mailing' and return
387 end
388 end
388
389
389 mail_body = params[:email_body]
390 mail_body = params[:email_body]
390 if !mail_body or mail_body.blank?
391 if !mail_body or mail_body.blank?
391 flash[:notice] = 'You entered an empty mail body.'
392 flash[:notice] = 'You entered an empty mail body.'
392 redirect_to :action => 'mass_mailing' and return
393 redirect_to :action => 'mass_mailing' and return
393 end
394 end
394
395
395 note = []
396 note = []
396 users = []
397 users = []
397 lines.split("\n").each do |line|
398 lines.split("\n").each do |line|
398 user = User.find_by_login(line.chomp)
399 user = User.find_by_login(line.chomp)
399 if user
400 if user
400 send_mail(user.email, mail_subject, mail_body)
401 send_mail(user.email, mail_subject, mail_body)
401 note << user.login
402 note << user.login
402 end
403 end
403 end
404 end
404
405
405 flash[:notice] = 'User(s) ' + note.join(', ') +
406 flash[:notice] = 'User(s) ' + note.join(', ') +
406 ' were successfully modified. '
407 ' were successfully modified. '
407 redirect_to :action => 'mass_mailing'
408 redirect_to :action => 'mass_mailing'
408 end
409 end
409
410
410 #bulk manage
411 #bulk manage
411 def bulk_manage
412 def bulk_manage
412
413
413 begin
414 begin
414 @users = User.where('login REGEXP ?',params[:regex]) if params[:regex]
415 @users = User.where('login REGEXP ?',params[:regex]) if params[:regex]
415 @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
416 rescue Exception
417 rescue Exception
417 flash[:error] = 'Regular Expression is malformed'
418 flash[:error] = 'Regular Expression is malformed'
418 @users = nil
419 @users = nil
419 end
420 end
420
421
421 if params[:commit]
422 if params[:commit]
422 @action = {}
423 @action = {}
423 @action[:set_enable] = params[:enabled]
424 @action[:set_enable] = params[:enabled]
424 @action[:enabled] = params[:enable] == "1"
425 @action[:enabled] = params[:enable] == "1"
425 @action[:gen_password] = params[:gen_password]
426 @action[:gen_password] = params[:gen_password]
427 + @action[:add_group] = params[:add_group]
428 + @action[:group_name] = params[:group_name]
426 end
429 end
427
430
428 if params[:commit] == "Perform"
431 if params[:commit] == "Perform"
429 if @action[:set_enable]
432 if @action[:set_enable]
430 @users.update_all(enabled: @action[:enabled])
433 @users.update_all(enabled: @action[:enabled])
431 end
434 end
432 if @action[:gen_password]
435 if @action[:gen_password]
433 @users.each do |u|
436 @users.each do |u|
434 password = random_password
437 password = random_password
435 u.password = password
438 u.password = password
436 u.password_confirmation = password
439 u.password_confirmation = password
437 u.save
440 u.save
438 end
441 end
439 end
442 end
443 + if @action[:add_group] and @action[:group_name]
444 + @group = Group.find(@action[:group_name])
445 + @users.each { |user| @group.users << user }
446 + end
440 end
447 end
441 end
448 end
442
449
443 protected
450 protected
444
451
445 def random_password(length=5)
452 def random_password(length=5)
446 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
453 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
447 newpass = ""
454 newpass = ""
448 length.times { newpass << chars[rand(chars.size-1)] }
455 length.times { newpass << chars[rand(chars.size-1)] }
449 return newpass
456 return newpass
450 end
457 end
451
458
452 def import_from_file(f)
459 def import_from_file(f)
453 data_hash = YAML.load(f)
460 data_hash = YAML.load(f)
454 @import_log = ""
461 @import_log = ""
455
462
456 country_data = data_hash[:countries]
463 country_data = data_hash[:countries]
457 site_data = data_hash[:sites]
464 site_data = data_hash[:sites]
458 user_data = data_hash[:users]
465 user_data = data_hash[:users]
459
466
460 # import country
467 # import country
461 countries = {}
468 countries = {}
462 country_data.each_pair do |id,country|
469 country_data.each_pair do |id,country|
463 c = Country.find_by_name(country[:name])
470 c = Country.find_by_name(country[:name])
464 if c!=nil
471 if c!=nil
465 countries[id] = c
472 countries[id] = c
466 @import_log << "Found #{country[:name]}\n"
473 @import_log << "Found #{country[:name]}\n"
467 else
474 else
468 countries[id] = Country.new(:name => country[:name])
475 countries[id] = Country.new(:name => country[:name])
469 countries[id].save
476 countries[id].save
470 @import_log << "Created #{country[:name]}\n"
477 @import_log << "Created #{country[:name]}\n"
471 end
478 end
472 end
479 end
473
480
474 # import sites
481 # import sites
475 sites = {}
482 sites = {}
476 site_data.each_pair do |id,site|
483 site_data.each_pair do |id,site|
477 s = Site.find_by_name(site[:name])
484 s = Site.find_by_name(site[:name])
478 if s!=nil
485 if s!=nil
479 @import_log << "Found #{site[:name]}\n"
486 @import_log << "Found #{site[:name]}\n"
480 else
487 else
481 s = Site.new(:name => site[:name])
488 s = Site.new(:name => site[:name])
482 @import_log << "Created #{site[:name]}\n"
489 @import_log << "Created #{site[:name]}\n"
483 end
490 end
484 s.password = site[:password]
491 s.password = site[:password]
485 s.country = countries[site[:country_id]]
492 s.country = countries[site[:country_id]]
486 s.save
493 s.save
487 sites[id] = s
494 sites[id] = s
488 end
495 end
489
496
490 # import users
497 # import users
491 user_data.each_pair do |id,user|
498 user_data.each_pair do |id,user|
492 u = User.find_by_login(user[:login])
499 u = User.find_by_login(user[:login])
493 if u!=nil
500 if u!=nil
494 @import_log << "Found #{user[:login]}\n"
501 @import_log << "Found #{user[:login]}\n"
495 else
502 else
496 u = User.new(:login => user[:login])
503 u = User.new(:login => user[:login])
497 @import_log << "Created #{user[:login]}\n"
504 @import_log << "Created #{user[:login]}\n"
498 end
505 end
499 u.full_name = user[:name]
506 u.full_name = user[:name]
500 u.password = user[:password]
507 u.password = user[:password]
501 u.country = countries[user[:country_id]]
508 u.country = countries[user[:country_id]]
502 u.site = sites[user[:site_id]]
509 u.site = sites[user[:site_id]]
503 u.activated = true
510 u.activated = true
504 u.email = "empty-#{u.login}@none.com"
511 u.email = "empty-#{u.login}@none.com"
505 if not u.save
512 if not u.save
506 @import_log << "Errors\n"
513 @import_log << "Errors\n"
507 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
514 u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
508 end
515 end
509 end
516 end
510
517
511 end
518 end
512
519
513 def logout_users(users)
520 def logout_users(users)
514 users.each do |user|
521 users.each do |user|
515 contest_stat = user.contest_stat(true)
522 contest_stat = user.contest_stat(true)
516 if contest_stat and !contest_stat.forced_logout
523 if contest_stat and !contest_stat.forced_logout
517 contest_stat.forced_logout = true
524 contest_stat.forced_logout = true
518 contest_stat.save
525 contest_stat.save
519 end
526 end
520 end
527 end
521 end
528 end
522
529
523 def send_contest_update_notification_email(user, contest)
530 def send_contest_update_notification_email(user, contest)
524 contest_title_name = GraderConfiguration['contest.name']
531 contest_title_name = GraderConfiguration['contest.name']
525 contest_name = contest.name
532 contest_name = contest.name
526 mail_subject = t('contest.notification.email_subject', {
533 mail_subject = t('contest.notification.email_subject', {
527 :contest_title_name => contest_title_name,
534 :contest_title_name => contest_title_name,
528 :contest_name => contest_name })
535 :contest_name => contest_name })
529 mail_body = t('contest.notification.email_body', {
536 mail_body = t('contest.notification.email_body', {
530 :full_name => user.full_name,
537 :full_name => user.full_name,
531 :contest_title_name => contest_title_name,
538 :contest_title_name => contest_title_name,
532 :contest_name => contest.name,
539 :contest_name => contest.name,
533 })
540 })
534
541
535 logger.info mail_body
542 logger.info mail_body
536 send_mail(user.email, mail_subject, mail_body)
543 send_mail(user.email, mail_subject, mail_body)
537 end
544 end
538
545
539 def find_contest_and_user_from_contest_id(id)
546 def find_contest_and_user_from_contest_id(id)
540 if id!='none'
547 if id!='none'
541 @contest = Contest.find(id)
548 @contest = Contest.find(id)
542 else
549 else
543 @contest = nil
550 @contest = nil
544 end
551 end
545 if @contest
552 if @contest
546 @users = @contest.users
553 @users = @contest.users
547 else
554 else
548 @users = User.find_users_with_no_contest
555 @users = User.find_users_with_no_contest
549 end
556 end
550 return [@contest, @users]
557 return [@contest, @users]
551 end
558 end
552
559
553 def gen_csv_from_scorearray(scorearray,problem)
560 def gen_csv_from_scorearray(scorearray,problem)
554 CSV.generate do |csv|
561 CSV.generate do |csv|
555 #add header
562 #add header
556 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
563 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
557 problem.each { |p| header << p.name }
564 problem.each { |p| header << p.name }
558 header += ['Total','Passed']
565 header += ['Total','Passed']
559 csv << header
566 csv << header
560 #add data
567 #add data
561 scorearray.each do |sc|
568 scorearray.each do |sc|
562 total = num_passed = 0
569 total = num_passed = 0
563 row = Array.new
570 row = Array.new
564 sc.each_index do |i|
571 sc.each_index do |i|
565 if i == 0
572 if i == 0
566 row << sc[i].login
573 row << sc[i].login
567 row << sc[i].full_name
574 row << sc[i].full_name
568 row << sc[i].activated
575 row << sc[i].activated
569 row << (sc[i].try(:contest_stat).try(:started_at).nil? ? 'no' : 'yes')
576 row << (sc[i].try(:contest_stat).try(:started_at).nil? ? 'no' : 'yes')
570 row << sc[i].contests.collect {|c| c.name}.join(', ')
577 row << sc[i].contests.collect {|c| c.name}.join(', ')
571 else
578 else
572 row << sc[i][0]
579 row << sc[i][0]
573 total += sc[i][0]
580 total += sc[i][0]
574 num_passed += 1 if sc[i][1]
581 num_passed += 1 if sc[i][1]
575 end
582 end
576 end
583 end
577 row << total
584 row << total
578 row << num_passed
585 row << num_passed
579 csv << row
586 csv << row
580 end
587 end
581 end
588 end
582 end
589 end
583
590
584 private
591 private
585 def user_params
592 def user_params
586 params.require(:user).permit(:login,:password,:password_confirmation,:email, :alias, :full_name,:remark)
593 params.require(:user).permit(:login,:password,:password_confirmation,:email, :alias, :full_name,:remark)
587 end
594 end
588 end
595 end
@@ -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,136 +1,137
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.')
101 elsif memory_limit<=0 or memory_limit >512
102 elsif memory_limit<=0 or memory_limit >512
102 problem.errors.add(:base,'Memory limit out of range.')
103 problem.errors.add(:base,'Memory limit out of range.')
103 end
104 end
104
105
105 if params[:file]==nil or params[:file]==''
106 if params[:file]==nil or params[:file]==''
106 problem.errors.add(:base,'No testdata file.')
107 problem.errors.add(:base,'No testdata file.')
107 end
108 end
108
109
109 checker_name = 'text'
110 checker_name = 'text'
110 if ['text','float'].include? params[:checker]
111 if ['text','float'].include? params[:checker]
111 checker_name = params[:checker]
112 checker_name = params[:checker]
112 end
113 end
113
114
114 file = params[:file]
115 file = params[:file]
115
116
116 if !problem.errors.empty?
117 if !problem.errors.empty?
117 return nil, problem
118 return nil, problem
118 end
119 end
119
120
120 problem.name = params[:name]
121 problem.name = params[:name]
121 if params[:full_name]!=''
122 if params[:full_name]!=''
122 problem.full_name = params[:full_name]
123 problem.full_name = params[:full_name]
123 else
124 else
124 problem.full_name = params[:name]
125 problem.full_name = params[:name]
125 end
126 end
126
127
127 return [{
128 return [{
128 :time_limit => time_limit,
129 :time_limit => time_limit,
129 :memory_limit => memory_limit,
130 :memory_limit => memory_limit,
130 :file => file,
131 :file => file,
131 :checker_name => checker_name
132 :checker_name => checker_name
132 },
133 },
133 problem]
134 problem]
134 end
135 end
135
136
136 end
137 end
@@ -1,388 +1,401
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
106 }
107 }
107
108
108 #simple call
109 #simple call
109 begin
110 begin
110 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
111 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
111 http.use_ssl = true
112 http.use_ssl = true
112 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
113 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
113 result = [ ]
114 result = [ ]
114 http.start do |http|
115 http.start do |http|
115 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
116 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
116 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
117 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
117 resp = http.request(req,param)
118 resp = http.request(req,param)
118 result = JSON.parse resp.body
119 result = JSON.parse resp.body
119 end
120 end
120 return true if result["type"] == "beanStudent"
121 return true if result["type"] == "beanStudent"
121 rescue => e
122 rescue => e
122 return false
123 return false
123 end
124 end
124 return false
125 return false
125 end
126 end
126
127
127 def admin?
128 def admin?
128 self.roles.detect {|r| r.name == 'admin' }
129 self.roles.detect {|r| r.name == 'admin' }
129 end
130 end
130
131
131 def email_for_editing
132 def email_for_editing
132 if self.email==nil
133 if self.email==nil
133 "(unknown)"
134 "(unknown)"
134 elsif self.email==''
135 elsif self.email==''
135 "(blank)"
136 "(blank)"
136 else
137 else
137 self.email
138 self.email
138 end
139 end
139 end
140 end
140
141
141 def email_for_editing=(e)
142 def email_for_editing=(e)
142 self.email=e
143 self.email=e
143 end
144 end
144
145
145 def alias_for_editing
146 def alias_for_editing
146 if self.alias==nil
147 if self.alias==nil
147 "(unknown)"
148 "(unknown)"
148 elsif self.alias==''
149 elsif self.alias==''
149 "(blank)"
150 "(blank)"
150 else
151 else
151 self.alias
152 self.alias
152 end
153 end
153 end
154 end
154
155
155 def alias_for_editing=(e)
156 def alias_for_editing=(e)
156 self.alias=e
157 self.alias=e
157 end
158 end
158
159
159 def activation_key
160 def activation_key
160 if self.hashed_password==nil
161 if self.hashed_password==nil
161 encrypt_new_password
162 encrypt_new_password
162 end
163 end
163 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
164 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
164 end
165 end
165
166
166 def verify_activation_key(key)
167 def verify_activation_key(key)
167 key == activation_key
168 key == activation_key
168 end
169 end
169
170
170 def self.random_password(length=5)
171 def self.random_password(length=5)
171 chars = 'abcdefghjkmnopqrstuvwxyz'
172 chars = 'abcdefghjkmnopqrstuvwxyz'
172 password = ''
173 password = ''
173 length.times { password << chars[rand(chars.length - 1)] }
174 length.times { password << chars[rand(chars.length - 1)] }
174 password
175 password
175 end
176 end
176
177
177 def self.find_non_admin_with_prefix(prefix='')
178 def self.find_non_admin_with_prefix(prefix='')
178 users = User.all
179 users = User.all
179 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
180 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
180 end
181 end
181
182
182 # Contest information
183 # Contest information
183
184
184 def self.find_users_with_no_contest()
185 def self.find_users_with_no_contest()
185 users = User.all
186 users = User.all
186 return users.find_all { |u| u.contests.length == 0 }
187 return users.find_all { |u| u.contests.length == 0 }
187 end
188 end
188
189
189
190
190 def contest_time_left
191 def contest_time_left
191 if GraderConfiguration.contest_mode?
192 if GraderConfiguration.contest_mode?
192 return nil if site==nil
193 return nil if site==nil
193 return site.time_left
194 return site.time_left
194 elsif GraderConfiguration.indv_contest_mode?
195 elsif GraderConfiguration.indv_contest_mode?
195 time_limit = GraderConfiguration.contest_time_limit
196 time_limit = GraderConfiguration.contest_time_limit
196 if time_limit == nil
197 if time_limit == nil
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,93 +1,94
1 %header.navbar.navbar-default.navbar-fixed-top
1 %header.navbar.navbar-default.navbar-fixed-top
2 %nav
2 %nav
3 .container-fluid
3 .container-fluid
4 .navbar-header
4 .navbar-header
5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
5 %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
6 %span.sr-only Togggle Navigation
6 %span.sr-only Togggle Navigation
7 %span.icon-bar
7 %span.icon-bar
8 %span.icon-bar
8 %span.icon-bar
9 %span.icon-bar
9 %span.icon-bar
10 %a.navbar-brand{href: main_list_path}
10 %a.navbar-brand{href: main_list_path}
11 %span.glyphicon.glyphicon-home
11 %span.glyphicon.glyphicon-home
12 MAIN
12 MAIN
13 .collapse.navbar-collapse#navbar-collapse
13 .collapse.navbar-collapse#navbar-collapse
14 %ul.nav.navbar-nav
14 %ul.nav.navbar-nav
15 / submission
15 / submission
16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
17 %li.dropdown
17 %li.dropdown
18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
19 = "#{I18n.t 'menu.submissions'}"
19 = "#{I18n.t 'menu.submissions'}"
20 %span.caret
20 %span.caret
21 %ul.dropdown-menu
21 %ul.dropdown-menu
22 = add_menu("View", 'submissions', 'index')
22 = add_menu("View", 'submissions', 'index')
23 = add_menu("Self Test", 'test', 'index')
23 = add_menu("Self Test", 'test', 'index')
24 / hall of fame
24 / hall of fame
25 - if GraderConfiguration['right.user_hall_of_fame']
25 - if GraderConfiguration['right.user_hall_of_fame']
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
27 / display MODE button (with countdown in contest mode)
27 / display MODE button (with countdown in contest mode)
28 - if GraderConfiguration.analysis_mode?
28 - if GraderConfiguration.analysis_mode?
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
30 - elsif GraderConfiguration.time_limit_mode?
30 - elsif GraderConfiguration.time_limit_mode?
31 - if @current_user.contest_finished?
31 - if @current_user.contest_finished?
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
33 - elsif !@current_user.contest_started?
33 - elsif !@current_user.contest_started?
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
35 - else
35 - else
36 %div.navbar-btn.btn.btn-primary#countdown asdf
36 %div.navbar-btn.btn.btn-primary#countdown asdf
37 :javascript
37 :javascript
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
39 / admin section
39 / admin section
40 - if (@current_user!=nil) and (session[:admin])
40 - if (@current_user!=nil) and (session[:admin])
41 / management
41 / management
42 %li.dropdown
42 %li.dropdown
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
44 Manage
44 Manage
45 %span.caret
45 %span.caret
46 %ul.dropdown-menu
46 %ul.dropdown-menu
47 = add_menu( 'Announcements', 'announcements', 'index')
47 = add_menu( 'Announcements', 'announcements', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
48 = add_menu( 'Problems', 'problems', 'index')
49 = add_menu( 'Users', 'user_admin', 'index')
49 = add_menu( 'Users', 'user_admin', 'index')
50 + = add_menu( 'User Groups', 'groups', 'index')
50 = add_menu( 'Graders', 'graders', 'list')
51 = add_menu( 'Graders', 'graders', 'list')
51 = add_menu( 'Message ', 'messages', 'console')
52 = add_menu( 'Message ', 'messages', 'console')
52 %li.divider{role: 'separator'}
53 %li.divider{role: 'separator'}
53 = add_menu( 'System config', 'configurations', 'index')
54 = add_menu( 'System config', 'configurations', 'index')
54 %li.divider{role: 'separator'}
55 %li.divider{role: 'separator'}
55 = add_menu( 'Sites', 'sites', 'index')
56 = add_menu( 'Sites', 'sites', 'index')
56 = add_menu( 'Contests', 'contest_management', 'index')
57 = add_menu( 'Contests', 'contest_management', 'index')
57 / report
58 / report
58 %li.dropdown
59 %li.dropdown
59 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
60 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
60 Report
61 Report
61 %span.caret
62 %span.caret
62 %ul.dropdown-menu
63 %ul.dropdown-menu
63 = add_menu( 'Current Score', 'report', 'current_score')
64 = add_menu( 'Current Score', 'report', 'current_score')
64 = add_menu( 'Score Report', 'report', 'max_score')
65 = add_menu( 'Score Report', 'report', 'max_score')
65 = add_menu( 'Report', 'report', 'multiple_login')
66 = add_menu( 'Report', 'report', 'multiple_login')
66 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
67 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
67 =link_to "#{ungraded} backlogs!",
68 =link_to "#{ungraded} backlogs!",
68 grader_list_path,
69 grader_list_path,
69 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
70 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
70
71
71 %ul.nav.navbar-nav.navbar-right
72 %ul.nav.navbar-nav.navbar-right
72 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
73 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
73 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
74 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
74 - if GraderConfiguration['system.user_setting_enabled']
75 - if GraderConfiguration['system.user_setting_enabled']
75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
77 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
77
78
78 /
79 /
79 - if (@current_user!=nil) and (session[:admin])
80 - if (@current_user!=nil) and (session[:admin])
80 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
81 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
81 .container-fluid
82 .container-fluid
82 .collapse.navbar-collapse
83 .collapse.navbar-collapse
83 %ul.nav.navbar-nav
84 %ul.nav.navbar-nav
84 = add_menu( '[Announcements]', 'announcements', 'index')
85 = add_menu( '[Announcements]', 'announcements', 'index')
85 = add_menu( '[Msg console]', 'messages', 'console')
86 = add_menu( '[Msg console]', 'messages', 'console')
86 = add_menu( '[Problems]', 'problems', 'index')
87 = add_menu( '[Problems]', 'problems', 'index')
87 = add_menu( '[Users]', 'user_admin', 'index')
88 = add_menu( '[Users]', 'user_admin', 'index')
88 = add_menu( '[Results]', 'user_admin', 'user_stat')
89 = add_menu( '[Results]', 'user_admin', 'user_stat')
89 = add_menu( '[Report]', 'report', 'multiple_login')
90 = add_menu( '[Report]', 'report', 'multiple_login')
90 = add_menu( '[Graders]', 'graders', 'list')
91 = add_menu( '[Graders]', 'graders', 'list')
91 = add_menu( '[Contests]', 'contest_management', 'index')
92 = add_menu( '[Contests]', 'contest_management', 'index')
92 = add_menu( '[Sites]', 'sites', 'index')
93 = add_menu( '[Sites]', 'sites', 'index')
93 = add_menu( '[System config]', 'configurations', 'index')
94 = add_menu( '[System config]', 'configurations', 'index')
@@ -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,77 +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
50 + .col-md-4
51 + %label.checkbox-inline
52 + = check_box_tag "add_group", true, params[:add_group]
53 + Add users to group
54 + %label.col-md-3.control-label.text-right Group name
55 + .col-md-5
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 +
49
58
50 .row
59 .row
51 .col-md-12
60 .col-md-12
52 = submit_tag "Preview Result", class: 'btn btn-default'
61 = submit_tag "Preview Result", class: 'btn btn-default'
53 - if @users
62 - if @users
54 .row
63 .row
55 .col-md-4
64 .col-md-4
56 - if @action
65 - if @action
57 %h2 Confirmation
66 %h2 Confirmation
58 - if @action[:set_enable]
67 - if @action[:set_enable]
59 .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')}.
60 - if @action[:gen_password]
69 - if @action[:gen_password]
61 .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.
62 .row
71 .row
63 .col-md-4
72 .col-md-4
64 = submit_tag "Perform", class: 'btn btn-primary'
73 = submit_tag "Perform", class: 'btn btn-primary'
65 .row
74 .row
66 .col-md-12
75 .col-md-12
67 The pattern matches #{@users.count} following users.
76 The pattern matches #{@users.count} following users.
68 %br
77 %br
69 - @users.each do |user|
78 - @users.each do |user|
70 = user.login
79 = user.login
71 = ' '
80 = ' '
72 = user.full_name
81 = user.full_name
73 = ' '
82 = ' '
74 = "(#{user.remark})" if user.remark
83 = "(#{user.remark})" if user.remark
75 %br
84 %br
76
85
77
86
@@ -1,11 +1,13
1 %h1 Editing user
1 %h1 Editing user
2
2
3 - = form_tag :action => 'update', :id => @user do
3 + = form_tag( {:action => 'update', :id => @user}, {class: 'form-horizontal'}) do
4 = error_messages_for 'user'
4 = error_messages_for 'user'
5 = render partial: "form"
5 = render partial: "form"
6 - = submit_tag "Edit"
6 + .form-group
7 + .col-md-offset-2.col-md-4
8 + = submit_tag "Edit", class: 'btn btn-primary'
7
9
8
10
9 = link_to 'Show', :action => 'show', :id => @user
11 = link_to 'Show', :action => 'show', :id => @user
10 |
12 |
11 = link_to 'Back', :action => 'list'
13 = link_to 'Back', :action => 'list'
@@ -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,16 +1,16
1 class AddLanguageExt < ActiveRecord::Migration
1 class AddLanguageExt < ActiveRecord::Migration
2 def self.up
2 def self.up
3 add_column :languages, :ext, :string, :limit => 10
3 add_column :languages, :ext, :string, :limit => 10
4
4
5 Language.reset_column_information
5 Language.reset_column_information
6 - langs = Language.find(:all)
6 + langs = Language.all
7 langs.each do |l|
7 langs.each do |l|
8 l.ext = l.name
8 l.ext = l.name
9 l.save
9 l.save
10 end
10 end
11 end
11 end
12
12
13 def self.down
13 def self.down
14 remove_column :languages, :ext
14 remove_column :languages, :ext
15 end
15 end
16 end
16 end
@@ -1,17 +1,17
1 class AddStatusToTasks < ActiveRecord::Migration
1 class AddStatusToTasks < ActiveRecord::Migration
2 def self.up
2 def self.up
3 add_column :tasks, :status, :integer
3 add_column :tasks, :status, :integer
4 add_column :tasks, :updated_at, :datetime
4 add_column :tasks, :updated_at, :datetime
5
5
6 Task.reset_column_information
6 Task.reset_column_information
7 - Task.find(:all).each do |task|
7 + Task.all.each do |task|
8 task.status_complete
8 task.status_complete
9 task.save
9 task.save
10 end
10 end
11 end
11 end
12
12
13 def self.down
13 def self.down
14 remove_column :tasks, :updated_at
14 remove_column :tasks, :updated_at
15 remove_column :tasks, :status
15 remove_column :tasks, :status
16 end
16 end
17 end
17 end
@@ -1,33 +1,32
1 class AddNumberToSubmissions < ActiveRecord::Migration
1 class AddNumberToSubmissions < ActiveRecord::Migration
2 def self.up
2 def self.up
3 add_column :submissions, :number, :integer
3 add_column :submissions, :number, :integer
4
4
5 # add number field for all records
5 # add number field for all records
6 Submission.reset_column_information
6 Submission.reset_column_information
7
7
8 last_user_id = nil
8 last_user_id = nil
9 last_problem_id = nil
9 last_problem_id = nil
10 current_number = 0
10 current_number = 0
11
11
12 - Submission.find(:all,
12 + Submission.order('user_id, problem_id, submitted_at').each do |submission|
13 - :order => 'user_id, problem_id, submitted_at').each do |submission|
14 if submission.user_id==last_user_id and submission.problem_id==last_problem_id
13 if submission.user_id==last_user_id and submission.problem_id==last_problem_id
15 current_number += 1
14 current_number += 1
16 else
15 else
17 current_number = 1
16 current_number = 1
18 end
17 end
19 submission.number = current_number
18 submission.number = current_number
20 submission.save
19 submission.save
21
20
22 last_user_id = submission.user_id
21 last_user_id = submission.user_id
23 last_problem_id = submission.problem_id
22 last_problem_id = submission.problem_id
24 end
23 end
25
24
26 add_index :submissions, [:user_id, :problem_id, :number], :unique => true
25 add_index :submissions, [:user_id, :problem_id, :number], :unique => true
27 end
26 end
28
27
29 def self.down
28 def self.down
30 remove_index :submissions, :column => [:user_id, :problem_id, :number]
29 remove_index :submissions, :column => [:user_id, :problem_id, :number]
31 remove_column :submissions, :number
30 remove_column :submissions, :number
32 end
31 end
33 end
32 end
@@ -1,29 +1,29
1 class AddSiteToUserAndAddDefaultSite < ActiveRecord::Migration
1 class AddSiteToUserAndAddDefaultSite < ActiveRecord::Migration
2 def self.up
2 def self.up
3 default_site = Site.new({:name => 'default',
3 default_site = Site.new({:name => 'default',
4 :started => false})
4 :started => false})
5 default_site.save!
5 default_site.save!
6
6
7 add_column :users, :site_id, :integer
7 add_column :users, :site_id, :integer
8 User.reset_column_information
8 User.reset_column_information
9
9
10 - User.find(:all).each do |user|
10 + User.all.each do |user|
11
11
12 class << user
12 class << user
13 def valid?
13 def valid?
14 true
14 true
15 end
15 end
16 end
16 end
17
17
18 user.site_id = default_site.id
18 user.site_id = default_site.id
19 user.save
19 user.save
20 end
20 end
21 end
21 end
22
22
23 def self.down
23 def self.down
24 remove_column :users, :site_id
24 remove_column :users, :site_id
25
25
26 default_site = Site.find_by_name('default')
26 default_site = Site.find_by_name('default')
27 default_site.destroy if default_site
27 default_site.destroy if default_site
28 end
28 end
29 end
29 end
@@ -1,33 +1,33
1 class RefactorProblemBodyToDescription < ActiveRecord::Migration
1 class RefactorProblemBodyToDescription < ActiveRecord::Migration
2 def self.up
2 def self.up
3 add_column :problems, :description_id, :integer
3 add_column :problems, :description_id, :integer
4 Problem.reset_column_information
4 Problem.reset_column_information
5
5
6 - Problem.find(:all).each do |problem|
6 + Problem.all.each do |problem|
7 if problem.body!=nil
7 if problem.body!=nil
8 description = Description.new
8 description = Description.new
9 description.body = problem.body
9 description.body = problem.body
10 description.markdowned = false
10 description.markdowned = false
11 description.save
11 description.save
12 problem.description_id = description.id
12 problem.description_id = description.id
13 problem.save
13 problem.save
14 end
14 end
15 end
15 end
16
16
17 remove_column :problems, :body
17 remove_column :problems, :body
18 end
18 end
19
19
20 def self.down
20 def self.down
21 add_column :problems, :body, :text
21 add_column :problems, :body, :text
22 Problem.reset_column_information
22 Problem.reset_column_information
23
23
24 - Problem.find(:all).each do |problem|
24 + Problem.all.each do |problem|
25 if problem.description_id != nil
25 if problem.description_id != nil
26 problem.body = Description.find(problem.description_id).body
26 problem.body = Description.find(problem.description_id).body
27 problem.save
27 problem.save
28 end
28 end
29 end
29 end
30
30
31 remove_column :problems, :description_id
31 remove_column :problems, :description_id
32 end
32 end
33 end
33 end
@@ -1,15 +1,15
1 class AddTestAllowedToProblems < ActiveRecord::Migration
1 class AddTestAllowedToProblems < ActiveRecord::Migration
2 def self.up
2 def self.up
3 add_column :problems, :test_allowed, :boolean
3 add_column :problems, :test_allowed, :boolean
4 Problem.reset_column_information
4 Problem.reset_column_information
5
5
6 - Problem.find(:all).each do |problem|
6 + Problem.all.each do |problem|
7 problem.test_allowed = true
7 problem.test_allowed = true
8 problem.save
8 problem.save
9 end
9 end
10 end
10 end
11
11
12 def self.down
12 def self.down
13 remove_column :problems, :test_allowed
13 remove_column :problems, :test_allowed
14 end
14 end
15 end
15 end
@@ -1,25 +1,25
1 class AddActivatedToUsers < ActiveRecord::Migration
1 class AddActivatedToUsers < ActiveRecord::Migration
2 def self.up
2 def self.up
3 add_column :users, :activated, :boolean, :default => 0
3 add_column :users, :activated, :boolean, :default => 0
4
4
5 User.reset_column_information
5 User.reset_column_information
6
6
7 - User.find(:all).each do |user|
7 + User.all.each do |user|
8
8
9 # disable validation
9 # disable validation
10 class <<user
10 class <<user
11 def valid?
11 def valid?
12 return true
12 return true
13 end
13 end
14 end
14 end
15
15
16 user.activated = true
16 user.activated = true
17 user.save
17 user.save
18 end
18 end
19 end
19 end
20
20
21
21
22 def self.down
22 def self.down
23 remove_column :users, :activated
23 remove_column :users, :activated
24 end
24 end
25 end
25 end
@@ -1,23 +1,23
1 class AddCommonExtToLanguages < ActiveRecord::Migration
1 class AddCommonExtToLanguages < ActiveRecord::Migration
2 def self.up
2 def self.up
3 # language.common_ext is a comma-separated list of common file
3 # language.common_ext is a comma-separated list of common file
4 # extensions.
4 # extensions.
5 add_column :languages, :common_ext, :string
5 add_column :languages, :common_ext, :string
6
6
7 # updating table information
7 # updating table information
8 Language.reset_column_information
8 Language.reset_column_information
9 common_ext = {
9 common_ext = {
10 'c' => 'c',
10 'c' => 'c',
11 'cpp' => 'cpp,cc',
11 'cpp' => 'cpp,cc',
12 'pas' => 'pas'
12 'pas' => 'pas'
13 }
13 }
14 - Language.find(:all).each do |lang|
14 + Language.all.each do |lang|
15 lang.common_ext = common_ext[lang.name]
15 lang.common_ext = common_ext[lang.name]
16 lang.save
16 lang.save
17 end
17 end
18 end
18 end
19
19
20 def self.down
20 def self.down
21 remove_column :languages, :common_ext
21 remove_column :languages, :common_ext
22 end
22 end
23 end
23 end
@@ -1,273 +1,292
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: 16777215
18 t.text "body", limit: 16777215
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: 16777215
53 t.text "body", limit: 16777215
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: 16777215
65 t.text "description", limit: 16777215
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: 16777215
129 t.text "body", limit: 16777215
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: 16777215
175 t.text "data", limit: 16777215
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
178 end
197 end
179
198
180 create_table "submissions", force: :cascade do |t|
199 create_table "submissions", force: :cascade do |t|
181 t.integer "user_id", limit: 4
200 t.integer "user_id", limit: 4
182 t.integer "problem_id", limit: 4
201 t.integer "problem_id", limit: 4
183 t.integer "language_id", limit: 4
202 t.integer "language_id", limit: 4
184 t.text "source", limit: 16777215
203 t.text "source", limit: 16777215
185 t.binary "binary", limit: 65535
204 t.binary "binary", limit: 65535
186 t.datetime "submitted_at"
205 t.datetime "submitted_at"
187 t.datetime "compiled_at"
206 t.datetime "compiled_at"
188 t.text "compiler_message", limit: 16777215
207 t.text "compiler_message", limit: 16777215
189 t.datetime "graded_at"
208 t.datetime "graded_at"
190 t.integer "points", limit: 4
209 t.integer "points", limit: 4
191 t.text "grader_comment", limit: 16777215
210 t.text "grader_comment", limit: 16777215
192 t.integer "number", limit: 4
211 t.integer "number", limit: 4
193 t.string "source_filename", limit: 255
212 t.string "source_filename", limit: 255
194 t.float "max_runtime", limit: 24
213 t.float "max_runtime", limit: 24
195 t.integer "peak_memory", limit: 4
214 t.integer "peak_memory", limit: 4
196 t.integer "effective_code_length", limit: 4
215 t.integer "effective_code_length", limit: 4
197 t.string "ip_address", limit: 255
216 t.string "ip_address", limit: 255
198 end
217 end
199
218
200 add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
219 add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
201 add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
220 add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
202
221
203 create_table "tasks", force: :cascade do |t|
222 create_table "tasks", force: :cascade do |t|
204 t.integer "submission_id", limit: 4
223 t.integer "submission_id", limit: 4
205 t.datetime "created_at"
224 t.datetime "created_at"
206 t.integer "status", limit: 4
225 t.integer "status", limit: 4
207 t.datetime "updated_at"
226 t.datetime "updated_at"
208 end
227 end
209
228
210 add_index "tasks", ["submission_id"], name: "index_tasks_on_submission_id", using: :btree
229 add_index "tasks", ["submission_id"], name: "index_tasks_on_submission_id", using: :btree
211
230
212 create_table "test_pairs", force: :cascade do |t|
231 create_table "test_pairs", force: :cascade do |t|
213 t.integer "problem_id", limit: 4
232 t.integer "problem_id", limit: 4
214 t.text "input", limit: 4294967295
233 t.text "input", limit: 4294967295
215 t.text "solution", limit: 4294967295
234 t.text "solution", limit: 4294967295
216 t.datetime "created_at", null: false
235 t.datetime "created_at", null: false
217 t.datetime "updated_at", null: false
236 t.datetime "updated_at", null: false
218 end
237 end
219
238
220 create_table "test_requests", force: :cascade do |t|
239 create_table "test_requests", force: :cascade do |t|
221 t.integer "user_id", limit: 4
240 t.integer "user_id", limit: 4
222 t.integer "problem_id", limit: 4
241 t.integer "problem_id", limit: 4
223 t.integer "submission_id", limit: 4
242 t.integer "submission_id", limit: 4
224 t.string "input_file_name", limit: 255
243 t.string "input_file_name", limit: 255
225 t.string "output_file_name", limit: 255
244 t.string "output_file_name", limit: 255
226 t.string "running_stat", limit: 255
245 t.string "running_stat", limit: 255
227 t.integer "status", limit: 4
246 t.integer "status", limit: 4
228 t.datetime "updated_at", null: false
247 t.datetime "updated_at", null: false
229 t.datetime "submitted_at"
248 t.datetime "submitted_at"
230 t.datetime "compiled_at"
249 t.datetime "compiled_at"
231 t.text "compiler_message", limit: 16777215
250 t.text "compiler_message", limit: 16777215
232 t.datetime "graded_at"
251 t.datetime "graded_at"
233 t.string "grader_comment", limit: 255
252 t.string "grader_comment", limit: 255
234 t.datetime "created_at", null: false
253 t.datetime "created_at", null: false
235 t.float "running_time", limit: 24
254 t.float "running_time", limit: 24
236 t.string "exit_status", limit: 255
255 t.string "exit_status", limit: 255
237 t.integer "memory_usage", limit: 4
256 t.integer "memory_usage", limit: 4
238 end
257 end
239
258
240 add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
259 add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
241
260
242 create_table "testcases", force: :cascade do |t|
261 create_table "testcases", force: :cascade do |t|
243 t.integer "problem_id", limit: 4
262 t.integer "problem_id", limit: 4
244 t.integer "num", limit: 4
263 t.integer "num", limit: 4
245 t.integer "group", limit: 4
264 t.integer "group", limit: 4
246 t.integer "score", limit: 4
265 t.integer "score", limit: 4
247 t.text "input", limit: 4294967295
266 t.text "input", limit: 4294967295
248 t.text "sol", limit: 4294967295
267 t.text "sol", limit: 4294967295
249 t.datetime "created_at", null: false
268 t.datetime "created_at", null: false
250 t.datetime "updated_at", null: false
269 t.datetime "updated_at", null: false
251 end
270 end
252
271
253 add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
272 add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
254
273
255 create_table "user_contest_stats", force: :cascade do |t|
274 create_table "user_contest_stats", force: :cascade do |t|
256 t.integer "user_id", limit: 4
275 t.integer "user_id", limit: 4
257 t.datetime "started_at"
276 t.datetime "started_at"
258 t.datetime "created_at", null: false
277 t.datetime "created_at", null: false
259 t.datetime "updated_at", null: false
278 t.datetime "updated_at", null: false
260 t.boolean "forced_logout"
279 t.boolean "forced_logout"
261 end
280 end
262
281
263 create_table "users", force: :cascade do |t|
282 create_table "users", force: :cascade do |t|
264 t.string "login", limit: 50
283 t.string "login", limit: 50
265 t.string "full_name", limit: 255
284 t.string "full_name", limit: 255
266 t.string "hashed_password", limit: 255
285 t.string "hashed_password", limit: 255
267 t.string "salt", limit: 5
286 t.string "salt", limit: 5
268 t.string "alias", limit: 255
287 t.string "alias", limit: 255
269 t.string "email", limit: 255
288 t.string "email", limit: 255
270 t.integer "site_id", limit: 4
289 t.integer "site_id", limit: 4
271 t.integer "country_id", limit: 4
290 t.integer "country_id", limit: 4
272 t.boolean "activated", default: false
291 t.boolean "activated", default: false
273 t.datetime "created_at"
292 t.datetime "created_at"
@@ -1,258 +1,267
1 CONFIGURATIONS =
1 CONFIGURATIONS =
2 [
2 [
3 {
3 {
4 :key => 'system.single_user_mode',
4 :key => 'system.single_user_mode',
5 :value_type => 'boolean',
5 :value_type => 'boolean',
6 :default_value => 'false',
6 :default_value => 'false',
7 :description => 'Only admins can log in to the system when running under single user mode.'
7 :description => 'Only admins can log in to the system when running under single user mode.'
8 },
8 },
9
9
10 {
10 {
11 :key => 'ui.front.title',
11 :key => 'ui.front.title',
12 :value_type => 'string',
12 :value_type => 'string',
13 :default_value => 'Grader'
13 :default_value => 'Grader'
14 },
14 },
15
15
16 {
16 {
17 :key => 'ui.front.welcome_message',
17 :key => 'ui.front.welcome_message',
18 :value_type => 'string',
18 :value_type => 'string',
19 :default_value => 'Welcome!'
19 :default_value => 'Welcome!'
20 },
20 },
21
21
22 {
22 {
23 :key => 'ui.show_score',
23 :key => 'ui.show_score',
24 :value_type => 'boolean',
24 :value_type => 'boolean',
25 :default_value => 'true'
25 :default_value => 'true'
26 },
26 },
27
27
28 {
28 {
29 :key => 'contest.time_limit',
29 :key => 'contest.time_limit',
30 :value_type => 'string',
30 :value_type => 'string',
31 :default_value => 'unlimited',
31 :default_value => 'unlimited',
32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
33 },
33 },
34
34
35 {
35 {
36 :key => 'system.mode',
36 :key => 'system.mode',
37 :value_type => 'string',
37 :value_type => 'string',
38 :default_value => 'standard',
38 :default_value => 'standard',
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 },
40 },
41
41
42 {
42 {
43 :key => 'contest.name',
43 :key => 'contest.name',
44 :value_type => 'string',
44 :value_type => 'string',
45 :default_value => 'Grader',
45 :default_value => 'Grader',
46 :description => 'This name will be shown on the user header bar.'
46 :description => 'This name will be shown on the user header bar.'
47 },
47 },
48
48
49 {
49 {
50 :key => 'contest.multisites',
50 :key => 'contest.multisites',
51 :value_type => 'boolean',
51 :value_type => 'boolean',
52 :default_value => 'false',
52 :default_value => 'false',
53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
54 },
54 },
55
55
56 #---------------------------- right --------------------------------
56 #---------------------------- right --------------------------------
57 {
57 {
58 :key => 'right.user_hall_of_fame',
58 :key => 'right.user_hall_of_fame',
59 :value_type => 'boolean',
59 :value_type => 'boolean',
60 :default_value => 'false',
60 :default_value => 'false',
61 :description => 'If true, any user can access hall of fame page.'
61 :description => 'If true, any user can access hall of fame page.'
62 },
62 },
63
63
64 {
64 {
65 :key => 'right.multiple_ip_login',
65 :key => 'right.multiple_ip_login',
66 :value_type => 'boolean',
66 :value_type => 'boolean',
67 :default_value => 'true',
67 :default_value => 'true',
68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
69 },
69 },
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
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
You need to be logged in to leave comments. Login now