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

r834:825a2986c8ea - - 19 files changed: 140 inserted, 89 deleted

@@ -0,0 +1,8
1 + = render partial: 'toggle_button',
2 + locals: {button_id: "#group-enabled-#{@group.id}",button_on: @group.enabled }
3 + :plain
4 + r = $("#group-#{@group.id}");
5 + r.removeClass('success');
6 + r.removeClass('danger');
7 + r.addClass("#{@group.enabled? ? 'success' : 'danger'}");
8 +
@@ -0,0 +1,5
1 + class AddEnabledToGroup < ActiveRecord::Migration[5.2]
2 + def change
3 + add_column :groups, :enabled, :boolean, default: true
4 + end
5 + end
@@ -131,37 +131,38
131 }
131 }
132 }
132 }
133 flash[:notice] = 'You are not authorized to view the page you requested'
133 flash[:notice] = 'You are not authorized to view the page you requested'
134 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
134 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
135 redirect_to :controller => 'main', :action => 'login'
135 redirect_to :controller => 'main', :action => 'login'
136 return false
136 return false
137 end
137 end
138 end
138 end
139
139
140 def verify_time_limit
140 def verify_time_limit
141 return true if session[:user_id]==nil
141 return true if session[:user_id]==nil
142 user = User.find(session[:user_id], :include => :site)
142 user = User.find(session[:user_id], :include => :site)
143 return true if user==nil || user.site == nil
143 return true if user==nil || user.site == nil
144 if user.contest_finished?
144 if user.contest_finished?
145 flash[:notice] = 'Error: the contest you are participating is over.'
145 flash[:notice] = 'Error: the contest you are participating is over.'
146 redirect_to :back
146 redirect_to :back
147 return false
147 return false
148 end
148 end
149 return true
149 return true
150 end
150 end
151
151
152 def is_request_ip_allowed?
152 def is_request_ip_allowed?
153 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
153 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
154 user_ip = IPAddr.new(request.remote_ip)
154 user_ip = IPAddr.new(request.remote_ip)
155 + allowed = GraderConfiguration[WHITELIST_IP_CONF_KEY] || ''
155
156
156 - GraderConfiguration[WHITELIST_IP_CONF_KEY].delete(' ').split(',').each do |ips|
157 + allowed.delete(' ').split(',').each do |ips|
157 allow_ips = IPAddr.new(ips)
158 allow_ips = IPAddr.new(ips)
158 if allow_ips.include?(user_ip)
159 if allow_ips.include?(user_ip)
159 return true
160 return true
160 end
161 end
161 end
162 end
162 return false
163 return false
163 end
164 end
164 return true
165 return true
165 end
166 end
166
167
167 end
168 end
@@ -1,75 +1,81
1 class GroupsController < ApplicationController
1 class GroupsController < ApplicationController
2 before_action :set_group, only: [:show, :edit, :update, :destroy,
2 before_action :set_group, only: [:show, :edit, :update, :destroy,
3 :add_user, :remove_user,:remove_all_user,
3 :add_user, :remove_user,:remove_all_user,
4 :add_problem, :remove_problem,:remove_all_problem,
4 :add_problem, :remove_problem,:remove_all_problem,
5 + :toggle,
5 ]
6 ]
6 before_action :admin_authorization
7 before_action :admin_authorization
7
8
8 # GET /groups
9 # GET /groups
9 def index
10 def index
10 @groups = Group.all
11 @groups = Group.all
11 end
12 end
12
13
13 # GET /groups/1
14 # GET /groups/1
14 def show
15 def show
15 end
16 end
16
17
17 # GET /groups/new
18 # GET /groups/new
18 def new
19 def new
19 @group = Group.new
20 @group = Group.new
20 end
21 end
21
22
22 # GET /groups/1/edit
23 # GET /groups/1/edit
23 def edit
24 def edit
24 end
25 end
25
26
26 # POST /groups
27 # POST /groups
27 def create
28 def create
28 @group = Group.new(group_params)
29 @group = Group.new(group_params)
29
30
30 if @group.save
31 if @group.save
31 redirect_to @group, notice: 'Group was successfully created.'
32 redirect_to @group, notice: 'Group was successfully created.'
32 else
33 else
33 render :new
34 render :new
34 end
35 end
35 end
36 end
36
37
37 # PATCH/PUT /groups/1
38 # PATCH/PUT /groups/1
38 def update
39 def update
39 if @group.update(group_params)
40 if @group.update(group_params)
40 redirect_to @group, notice: 'Group was successfully updated.'
41 redirect_to @group, notice: 'Group was successfully updated.'
41 else
42 else
42 render :edit
43 render :edit
43 end
44 end
44 end
45 end
45
46
46 # DELETE /groups/1
47 # DELETE /groups/1
47 def destroy
48 def destroy
48 @group.destroy
49 @group.destroy
49 redirect_to groups_url, notice: 'Group was successfully destroyed.'
50 redirect_to groups_url, notice: 'Group was successfully destroyed.'
50 end
51 end
51
52
53 + def toggle
54 + @group.enabled = @group.enabled? ? false : true
55 + @group.save
56 + end
57 +
52 def remove_user
58 def remove_user
53 user = User.find(params[:user_id])
59 user = User.find(params[:user_id])
54 @group.users.delete(user)
60 @group.users.delete(user)
55 redirect_to group_path(@group), flash: {success: "User #{user.login} was removed from the group #{@group.name}"}
61 redirect_to group_path(@group), flash: {success: "User #{user.login} was removed from the group #{@group.name}"}
56 end
62 end
57
63
58 def remove_all_user
64 def remove_all_user
59 @group.users.clear
65 @group.users.clear
60 redirect_to group_path(@group), alert: 'All users removed'
66 redirect_to group_path(@group), alert: 'All users removed'
61 end
67 end
62
68
63 def remove_all_problem
69 def remove_all_problem
64 @group.problems.clear
70 @group.problems.clear
65 redirect_to group_path(@group), alert: 'All problems removed'
71 redirect_to group_path(@group), alert: 'All problems removed'
66 end
72 end
67
73
68 def add_user
74 def add_user
69 user = User.find(params[:user_id])
75 user = User.find(params[:user_id])
70 begin
76 begin
71 @group.users << user
77 @group.users << user
72 redirect_to group_path(@group), flash: { success: "User #{user.login} was add to the group #{@group.name}"}
78 redirect_to group_path(@group), flash: { success: "User #{user.login} was add to the group #{@group.name}"}
73 rescue => e
79 rescue => e
74 redirect_to group_path(@group), alert: e.message
80 redirect_to group_path(@group), alert: e.message
75 end
81 end
@@ -78,27 +84,27
78 def remove_problem
84 def remove_problem
79 problem = Problem.find(params[:problem_id])
85 problem = Problem.find(params[:problem_id])
80 @group.problems.delete(problem)
86 @group.problems.delete(problem)
81 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was removed from the group #{@group.name}" }
87 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was removed from the group #{@group.name}" }
82 end
88 end
83
89
84 def add_problem
90 def add_problem
85 problem = Problem.find(params[:problem_id])
91 problem = Problem.find(params[:problem_id])
86 begin
92 begin
87 @group.problems << problem
93 @group.problems << problem
88 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was add to the group #{@group.name}" }
94 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was add to the group #{@group.name}" }
89 rescue => e
95 rescue => e
90 redirect_to group_path(@group), alert: e.message
96 redirect_to group_path(@group), alert: e.message
91 end
97 end
92 end
98 end
93
99
94 private
100 private
95 # Use callbacks to share common setup or constraints between actions.
101 # Use callbacks to share common setup or constraints between actions.
96 def set_group
102 def set_group
97 @group = Group.find(params[:id])
103 @group = Group.find(params[:id])
98 end
104 end
99
105
100 # Only allow a trusted parameter "white list" through.
106 # Only allow a trusted parameter "white list" through.
101 def group_params
107 def group_params
102 - params.require(:group).permit(:name, :description)
108 + params.require(:group).permit(:name, :description, :enabled)
103 end
109 end
104 end
110 end
@@ -1,44 +1,44
1 class SubmissionsController < ApplicationController
1 class SubmissionsController < ApplicationController
2 before_action :check_valid_login
2 before_action :check_valid_login
3 before_action :submission_authorization, only: [:show, :download, :edit]
3 before_action :submission_authorization, only: [:show, :download, :edit]
4 before_action :admin_authorization, only: [:rejudge]
4 before_action :admin_authorization, only: [:rejudge]
5
5
6 # GET /submissions
6 # GET /submissions
7 # GET /submissions.json
7 # GET /submissions.json
8 # Show problem selection and user's submission of that problem
8 # Show problem selection and user's submission of that problem
9 def index
9 def index
10 @user = @current_user
10 @user = @current_user
11 @problems = @user.available_problems
11 @problems = @user.available_problems
12
12
13 if params[:problem_id]==nil
13 if params[:problem_id]==nil
14 @problem = nil
14 @problem = nil
15 @submissions = nil
15 @submissions = nil
16 else
16 else
17 @problem = Problem.find_by_id(params[:problem_id])
17 @problem = Problem.find_by_id(params[:problem_id])
18 if (@problem == nil) or (not @problem.available)
18 if (@problem == nil) or (not @problem.available)
19 - redirect_to main_list_path
19 + redirect_to list_main_path
20 - flash[:notice] = 'Error: submissions for that problem are not viewable.'
20 + flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
21 return
21 return
22 end
22 end
23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
23 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
24 end
24 end
25 end
25 end
26
26
27 # GET /submissions/1
27 # GET /submissions/1
28 # GET /submissions/1.json
28 # GET /submissions/1.json
29 def show
29 def show
30 @submission = Submission.find(params[:id])
30 @submission = Submission.find(params[:id])
31
31
32 #log the viewing
32 #log the viewing
33 user = User.find(session[:user_id])
33 user = User.find(session[:user_id])
34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
35
35
36 @task = @submission.task
36 @task = @submission.task
37 end
37 end
38
38
39 def download
39 def download
40 @submission = Submission.find(params[:id])
40 @submission = Submission.find(params[:id])
41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
41 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
42 end
42 end
43
43
44 def compiler_msg
44 def compiler_msg
@@ -6,59 +6,61
6 redirect_to :action => 'list'
6 redirect_to :action => 'list'
7 end
7 end
8
8
9 def list
9 def list
10 @problems = @user.available_problems
10 @problems = @user.available_problems
11 end
11 end
12
12
13 # this has contest-wide access control
13 # this has contest-wide access control
14 def view
14 def view
15 base_name = params[:file]
15 base_name = params[:file]
16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
18
18
19 if !FileTest.exists?(filename)
19 if !FileTest.exists?(filename)
20 redirect_to :action => 'index' and return
20 redirect_to :action => 'index' and return
21 end
21 end
22
22
23 send_file_to_user(filename, base_filename)
23 send_file_to_user(filename, base_filename)
24 end
24 end
25
25
26 # this has problem-level access control
26 # this has problem-level access control
27 def download
27 def download
28 problem = Problem.find(params[:id])
28 problem = Problem.find(params[:id])
29 unless @current_user.can_view_problem? problem
29 unless @current_user.can_view_problem? problem
30 - flash[:notice] = 'You are not authorized to access this file'
30 + flash[:error] = 'You are not authorized to access this file'
31 - redirect_to :action => 'index' and return
31 + redirect_to list_main_path
32 + return
32 end
33 end
33
34
34 base_name = params[:file]
35 base_name = params[:file]
35 base_filename = File.basename("#{base_name}.#{params[:ext]}")
36 base_filename = File.basename("#{base_name}.#{params[:ext]}")
36 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
37 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
37
38
38 if !FileTest.exists?(filename)
39 if !FileTest.exists?(filename)
39 flash[:notice] = 'File does not exists'
40 flash[:notice] = 'File does not exists'
40 - redirect_to :action => 'index' and return
41 + redirect_to list_main_path
42 + return
41 end
43 end
42
44
43 send_file_to_user(filename, base_filename)
45 send_file_to_user(filename, base_filename)
44 end
46 end
45
47
46 protected
48 protected
47
49
48 def send_file_to_user(filename, base_filename)
50 def send_file_to_user(filename, base_filename)
49 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
51 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
50 response.headers['Content-Type'] = "application/force-download"
52 response.headers['Content-Type'] = "application/force-download"
51 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
53 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
52 response.headers["X-Sendfile"] = filename
54 response.headers["X-Sendfile"] = filename
53 response.headers['Content-length'] = File.size(filename)
55 response.headers['Content-length'] = File.size(filename)
54 render :nothing => true
56 render :nothing => true
55 else
57 else
56 if params[:ext]=='pdf'
58 if params[:ext]=='pdf'
57 content_type = 'application/pdf'
59 content_type = 'application/pdf'
58 else
60 else
59 content_type = 'application/octet-stream'
61 content_type = 'application/octet-stream'
60 end
62 end
61
63
62 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
64 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
63 end
65 end
64 end
66 end
@@ -44,79 +44,89
44 if @user.save
44 if @user.save
45 flash[:notice] = 'User was successfully created.'
45 flash[:notice] = 'User was successfully created.'
46 redirect_to :action => 'index'
46 redirect_to :action => 'index'
47 else
47 else
48 render :action => 'new'
48 render :action => 'new'
49 end
49 end
50 end
50 end
51
51
52 def clear_last_ip
52 def clear_last_ip
53 @user = User.find(params[:id])
53 @user = User.find(params[:id])
54 @user.last_ip = nil
54 @user.last_ip = nil
55 @user.save
55 @user.save
56 redirect_to action: 'index', page: params[:page]
56 redirect_to action: 'index', page: params[:page]
57 end
57 end
58
58
59 def create_from_list
59 def create_from_list
60 lines = params[:user_list]
60 lines = params[:user_list]
61
61
62 note = []
62 note = []
63 error_note = []
63 error_note = []
64 error_msg = nil
64 error_msg = nil
65 ok_user = []
65 ok_user = []
66
66
67 lines.split("\n").each do |line|
67 lines.split("\n").each do |line|
68 - items = line.chomp.split(',')
68 + #split with large limit, this will cause consecutive ',' to be result in a blank
69 + items = line.chomp.split(',',1000)
69 if items.length>=2
70 if items.length>=2
70 login = items[0]
71 login = items[0]
71 full_name = items[1]
72 full_name = items[1]
72 remark =''
73 remark =''
73 user_alias = ''
74 user_alias = ''
74
75
75 added_random_password = false
76 added_random_password = false
76 - if items.length >= 3 and items[2].chomp(" ").length > 0;
77 + added_password = false
78 + if items.length >= 3
79 + if items[2].chomp(" ").length > 0
77 password = items[2].chomp(" ")
80 password = items[2].chomp(" ")
81 + added_password = true
82 + end
78 else
83 else
79 password = random_password
84 password = random_password
80 added_random_password=true;
85 added_random_password=true;
81 end
86 end
82
87
83 if items.length>= 4 and items[3].chomp(" ").length > 0;
88 if items.length>= 4 and items[3].chomp(" ").length > 0;
84 user_alias = items[3].chomp(" ")
89 user_alias = items[3].chomp(" ")
85 else
90 else
86 user_alias = login
91 user_alias = login
87 end
92 end
88
93
94 +
95 + has_remark = false
89 if items.length>=5
96 if items.length>=5
90 remark = items[4].strip;
97 remark = items[4].strip;
98 + has_remark = true
91 end
99 end
92
100
93 user = User.find_by_login(login)
101 user = User.find_by_login(login)
94 if (user)
102 if (user)
95 user.full_name = full_name
103 user.full_name = full_name
96 - user.password = password
104 + user.remark = remark if has_remark
97 - user.remark = remark
105 + user.password = password if added_password || added_random_password
98 else
106 else
107 + #create a random password if none are given
108 + password = random_password unless password
99 user = User.new({:login => login,
109 user = User.new({:login => login,
100 :full_name => full_name,
110 :full_name => full_name,
101 :password => password,
111 :password => password,
102 :password_confirmation => password,
112 :password_confirmation => password,
103 :alias => user_alias,
113 :alias => user_alias,
104 :remark => remark})
114 :remark => remark})
105 end
115 end
106 user.activated = true
116 user.activated = true
107
117
108 if user.save
118 if user.save
109 if added_random_password
119 if added_random_password
110 note << "'#{login}' (+)"
120 note << "'#{login}' (+)"
111 else
121 else
112 note << login
122 note << login
113 end
123 end
114 ok_user << user
124 ok_user << user
115 else
125 else
116 error_note << "'#{login}'"
126 error_note << "'#{login}'"
117 error_msg = user.errors.full_messages.to_sentence unless error_msg
127 error_msg = user.errors.full_messages.to_sentence unless error_msg
118 end
128 end
119
129
120 end
130 end
121 end
131 end
122
132
@@ -92,50 +92,51
92 end
92 end
93 st + time.strftime("%X")
93 st + time.strftime("%X")
94 end
94 end
95
95
96 def format_short_duration(duration)
96 def format_short_duration(duration)
97 return '' if duration==nil
97 return '' if duration==nil
98 d = duration.to_f
98 d = duration.to_f
99 return Time.at(d).gmtime.strftime("%X")
99 return Time.at(d).gmtime.strftime("%X")
100 end
100 end
101
101
102 def format_full_time_ago(time)
102 def format_full_time_ago(time)
103 st = time_ago_in_words(time) + ' ago (' + format_short_time(time) + ')'
103 st = time_ago_in_words(time) + ' ago (' + format_short_time(time) + ')'
104 end
104 end
105
105
106 def read_textfile(fname,max_size=2048)
106 def read_textfile(fname,max_size=2048)
107 begin
107 begin
108 File.open(fname).read(max_size)
108 File.open(fname).read(max_size)
109 rescue
109 rescue
110 nil
110 nil
111 end
111 end
112 end
112 end
113
113
114 def toggle_button(on,toggle_url,id, option={})
114 def toggle_button(on,toggle_url,id, option={})
115 btn_size = option[:size] || 'btn-xs'
115 btn_size = option[:size] || 'btn-xs'
116 + btn_block = option[:block] || 'btn-block'
116 link_to (on ? "Yes" : "No"), toggle_url,
117 link_to (on ? "Yes" : "No"), toggle_url,
117 - {class: "btn btn-block #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
118 + {class: "btn #{btn_block} #{btn_size} btn-#{on ? 'success' : 'default'} ajax-toggle",
118 id: id,
119 id: id,
119 data: {remote: true, method: 'get'}}
120 data: {remote: true, method: 'get'}}
120 end
121 end
121
122
122 def get_ace_mode(language)
123 def get_ace_mode(language)
123 # return ace mode string from Language
124 # return ace mode string from Language
124
125
125 case language.pretty_name
126 case language.pretty_name
126 when 'Pascal'
127 when 'Pascal'
127 'ace/mode/pascal'
128 'ace/mode/pascal'
128 when 'C++','C'
129 when 'C++','C'
129 'ace/mode/c_cpp'
130 'ace/mode/c_cpp'
130 when 'Ruby'
131 when 'Ruby'
131 'ace/mode/ruby'
132 'ace/mode/ruby'
132 when 'Python'
133 when 'Python'
133 'ace/mode/python'
134 'ace/mode/python'
134 when 'Java'
135 when 'Java'
135 'ace/mode/java'
136 'ace/mode/java'
136 else
137 else
137 'ace/mode/c_cpp'
138 'ace/mode/c_cpp'
138 end
139 end
139 end
140 end
140
141
141
142
@@ -160,51 +161,48
160 " #{format_short_duration(user.contest_time_left)}"
161 " #{format_short_duration(user.contest_time_left)}"
161 end
162 end
162 end
163 end
163
164
164 #
165 #
165 # if the contest is in the anaysis mode
166 # if the contest is in the anaysis mode
166 if GraderConfiguration.analysis_mode?
167 if GraderConfiguration.analysis_mode?
167 header = <<ANALYSISMODE
168 header = <<ANALYSISMODE
168 <tr><td colspan="2" align="center">
169 <tr><td colspan="2" align="center">
169 <span class="contest-over-msg">ANALYSIS MODE</span>
170 <span class="contest-over-msg">ANALYSIS MODE</span>
170 </td></tr>
171 </td></tr>
171 ANALYSISMODE
172 ANALYSISMODE
172 end
173 end
173
174
174 contest_name = GraderConfiguration['contest.name']
175 contest_name = GraderConfiguration['contest.name']
175
176
176 #
177 #
177 # build real title bar
178 # build real title bar
178 result = <<TITLEBAR
179 result = <<TITLEBAR
179 <div class="title">
180 <div class="title">
180 <table>
181 <table>
181 #{header}
182 #{header}
182 <tr>
183 <tr>
183 <td class="left-col">
184 <td class="left-col">
184 - #{user.full_name}<br/>
185 - #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
186 - #{time_left}
187 <br/>
185 <br/>
188 </td>
186 </td>
189 <td class="right-col">#{contest_name}</td>
187 <td class="right-col">#{contest_name}</td>
190 </tr>
188 </tr>
191 </table>
189 </table>
192 </div>
190 </div>
193 TITLEBAR
191 TITLEBAR
194 result.html_safe
192 result.html_safe
195 end
193 end
196
194
197 def markdown(text)
195 def markdown(text)
198 markdown = RDiscount.new(text)
196 markdown = RDiscount.new(text)
199 markdown.to_html.html_safe
197 markdown.to_html.html_safe
200 end
198 end
201
199
202
200
203 BOOTSTRAP_FLASH_MSG = {
201 BOOTSTRAP_FLASH_MSG = {
204 success: 'alert-success',
202 success: 'alert-success',
205 error: 'alert-danger',
203 error: 'alert-danger',
206 alert: 'alert-danger',
204 alert: 'alert-danger',
207 notice: 'alert-info'
205 notice: 'alert-info'
208 }
206 }
209
207
210 def bootstrap_class_for(flash_type)
208 def bootstrap_class_for(flash_type)
@@ -1,20 +1,14
1 module MainHelper
1 module MainHelper
2
2
3 - def link_to_description_if_any(name, problem, options={})
3 + def link_to_description_if_any(name, problem)
4 if !problem.url.blank?
4 if !problem.url.blank?
5 - return link_to name, problem.url, options
5 + return link_to name, problem.url
6 elsif !problem.description_filename.blank?
6 elsif !problem.description_filename.blank?
7 - #build a link to a problem (via task controller)
8 basename, ext = problem.description_filename.split('.')
7 basename, ext = problem.description_filename.split('.')
9 - options[:controller] = 'tasks'
8 + return link_to name, download_task_path(problem.id,basename,ext), target: '_blank'
10 - options[:action] = 'download'
11 - options[:id] = problem.id
12 - options[:file] = basename
13 - options[:ext] = ext
14 - return link_to name, options
15 else
9 else
16 return ''
10 return ''
17 end
11 end
18 end
12 end
19
13
20 end
14 end
@@ -133,36 +133,36
133 end
133 end
134 end
134 end
135
135
136 # validation codes
136 # validation codes
137 def must_specify_language
137 def must_specify_language
138 return if self.source==nil
138 return if self.source==nil
139
139
140 # for output_only tasks
140 # for output_only tasks
141 return if self.problem!=nil and self.problem.output_only
141 return if self.problem!=nil and self.problem.output_only
142
142
143 if self.language == nil
143 if self.language == nil
144 errors.add('source',"Cannot detect language. Did you submit a correct source file?")
144 errors.add('source',"Cannot detect language. Did you submit a correct source file?")
145 end
145 end
146 end
146 end
147
147
148 def must_have_valid_problem
148 def must_have_valid_problem
149 return if self.source==nil
149 return if self.source==nil
150 if self.problem==nil
150 if self.problem==nil
151 errors.add('problem',"must be specified.")
151 errors.add('problem',"must be specified.")
152 else
152 else
153 #admin always have right
153 #admin always have right
154 return if self.user.admin?
154 return if self.user.admin?
155
155
156 #check if user has the right to submit the problem
156 #check if user has the right to submit the problem
157 - errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
157 + errors[:base] << "Authorization error: you have no right to submit to this problem" if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
158 end
158 end
159 end
159 end
160
160
161 # callbacks
161 # callbacks
162 def assign_latest_number_if_new_recond
162 def assign_latest_number_if_new_recond
163 return if !self.new_record?
163 return if !self.new_record?
164 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
164 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
165 self.number = (latest==nil) ? 1 : latest.number + 1;
165 self.number = (latest==nil) ? 1 : latest.number + 1;
166 end
166 end
167
167
168 end
168 end
@@ -295,71 +295,74
295 #if this is a normal mode
295 #if this is a normal mode
296 #we show problem based on problem_group, if the config said so
296 #we show problem based on problem_group, if the config said so
297 if GraderConfiguration.use_problem_group?
297 if GraderConfiguration.use_problem_group?
298 return available_problems_in_group
298 return available_problems_in_group
299 else
299 else
300 return Problem.available_problems
300 return Problem.available_problems
301 end
301 end
302 else
302 else
303 #this is multi contest mode
303 #this is multi contest mode
304 contest_problems = []
304 contest_problems = []
305 pin = {}
305 pin = {}
306 contests.enabled.each do |contest|
306 contests.enabled.each do |contest|
307 contest.problems.available.each do |problem|
307 contest.problems.available.each do |problem|
308 if not pin.has_key? problem.id
308 if not pin.has_key? problem.id
309 contest_problems << problem
309 contest_problems << problem
310 end
310 end
311 pin[problem.id] = true
311 pin[problem.id] = true
312 end
312 end
313 end
313 end
314 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
314 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
315 return contest_problems + other_avaiable_problems
315 return contest_problems + other_avaiable_problems
316 end
316 end
317 end
317 end
318
318
319 + # new feature, get list of available problem in all enabled group that the user belongs to
319 def available_problems_in_group
320 def available_problems_in_group
320 problem = []
321 problem = []
321 - self.groups.each do |group|
322 + self.groups.where(enabled: true).each do |group|
322 group.problems.where(available: true).each { |p| problem << p }
323 group.problems.where(available: true).each { |p| problem << p }
323 end
324 end
324 problem.uniq!
325 problem.uniq!
325 if problem
326 if problem
326 problem.sort! do |a,b|
327 problem.sort! do |a,b|
327 case
328 case
328 when a.date_added < b.date_added
329 when a.date_added < b.date_added
329 1
330 1
330 when a.date_added > b.date_added
331 when a.date_added > b.date_added
331 -1
332 -1
332 else
333 else
333 a.name <=> b.name
334 a.name <=> b.name
334 end
335 end
335 end
336 end
336 return problem
337 return problem
337 else
338 else
338 return []
339 return []
339 end
340 end
340 end
341 end
341
342
343 + #check if the user has the right to view that problem
344 + #this also consider group based problem policy
342 def can_view_problem?(problem)
345 def can_view_problem?(problem)
343 return true if admin?
346 return true if admin?
344 return available_problems.include? problem
347 return available_problems.include? problem
345 end
348 end
346
349
347 def self.clear_last_login
350 def self.clear_last_login
348 User.update_all(:last_ip => nil)
351 User.update_all(:last_ip => nil)
349 end
352 end
350
353
351 protected
354 protected
352 def encrypt_new_password
355 def encrypt_new_password
353 return if password.blank?
356 return if password.blank?
354 self.salt = (10+rand(90)).to_s
357 self.salt = (10+rand(90)).to_s
355 self.hashed_password = User.encrypt(self.password,self.salt)
358 self.hashed_password = User.encrypt(self.password,self.salt)
356 end
359 end
357
360
358 def assign_default_site
361 def assign_default_site
359 # have to catch error when migrating (because self.site is not available).
362 # have to catch error when migrating (because self.site is not available).
360 begin
363 begin
361 if self.site==nil
364 if self.site==nil
362 self.site = Site.find_by_name('default')
365 self.site = Site.find_by_name('default')
363 if self.site==nil
366 if self.site==nil
364 self.site = Site.find(1) # when 'default has be renamed'
367 self.site = Site.find(1) # when 'default has be renamed'
365 end
368 end
@@ -1,26 +1,26
1
1
2 %tr
2 %tr
3 %td{:align => "center"}
3 %td{:align => "center"}
4 = submission.number
4 = submission.number
5 %td.text-right
5 %td.text-right
6 = link_to "##{submission.id}", submission_path(submission.id)
6 = link_to "##{submission.id}", submission_path(submission.id)
7 %td
7 %td
8 = l submission.submitted_at, format: :long
8 = l submission.submitted_at, format: :long
9 = "( #{time_ago_in_words(submission.submitted_at)} ago)"
9 = "( #{time_ago_in_words(submission.submitted_at)} ago)"
10 %td
10 %td
11 = submission.source_filename
11 = submission.source_filename
12 = " (#{submission.language.pretty_name}) "
12 = " (#{submission.language.pretty_name}) "
13 - = link_to('[load]',{:action => 'source', :id => submission.id})
13 + = link_to '[load]', download_submission_path(submission)
14 %td
14 %td
15 - if submission.graded_at
15 - if submission.graded_at
16 = "Graded at #{format_short_time(submission.graded_at)}."
16 = "Graded at #{format_short_time(submission.graded_at)}."
17 %br/
17 %br/
18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
19 = " ["
19 = " ["
20 %tt
20 %tt
21 = submission.grader_comment
21 = submission.grader_comment
22 = "]"
22 = "]"
23 %td
23 %td
24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
25 %td
25 %td
26 = link_to 'Edit', edit_submission_path(submission.id), class: 'btn btn-success'
26 = link_to 'Edit', edit_submission_path(submission.id), class: 'btn btn-success'
@@ -1,16 +1,27
1 = form_for @group do |f|
1 = form_for @group do |f|
2 - if @group.errors.any?
2 - if @group.errors.any?
3 #error_explanation
3 #error_explanation
4 %h2= "#{pluralize(@group.errors.count, "error")} prohibited this group from being saved:"
4 %h2= "#{pluralize(@group.errors.count, "error")} prohibited this group from being saved:"
5 %ul
5 %ul
6 - @group.errors.full_messages.each do |msg|
6 - @group.errors.full_messages.each do |msg|
7 %li= msg
7 %li= msg
8 -
8 + .row
9 + .col-md-6
9 .form-group.field
10 .form-group.field
10 = f.label :name
11 = f.label :name
11 = f.text_field :name, class: 'form-control'
12 = f.text_field :name, class: 'form-control'
13 + .row
14 + .col-md-6
12 .form-group.field
15 .form-group.field
13 = f.label :description
16 = f.label :description
14 = f.text_field :description, class: 'form-control'
17 = f.text_field :description, class: 'form-control'
18 + .row
19 + .col-md-6
20 + .checkbox
21 + = f.label :enabled do
22 + = f.check_box :enabled
23 + Enabled
24 + .row
25 + .col-md-6
15 .form-group.actions
26 .form-group.actions
16 = f.submit 'Save', class: 'btn btn-primary'
27 = f.submit 'Save', class: 'btn btn-primary'
@@ -1,22 +1,24
1 %h1 Groups
1 %h1 Groups
2
2
3 %p
3 %p
4 = link_to 'New Group', new_group_path, class: 'btn btn-primary'
4 = link_to 'New Group', new_group_path, class: 'btn btn-primary'
5 %table.table.table-hover
5 %table.table.table-hover
6 %thead
6 %thead
7 %tr
7 %tr
8 %th Name
8 %th Name
9 %th Description
9 %th Description
10 + %th Enabled?
10 %th
11 %th
11 %th
12 %th
12
13
13 %tbody
14 %tbody
14 - @groups.each do |group|
15 - @groups.each do |group|
15 - %tr
16 + %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
16 %td= group.name
17 %td= group.name
17 %td= group.description
18 %td= group.description
19 + %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", size: ' ', block: ' ')
18 %td= link_to 'View', group, class: 'btn btn-default'
20 %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'
21 %td= link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
20
22
21 %br
23 %br
22
24
@@ -22,26 +22,26
22
22
23 %p
23 %p
24 =raw t 'help.accept_only_language_specified'
24 =raw t 'help.accept_only_language_specified'
25
25
26 %p
26 %p
27 =raw t 'help.specifying_task'
27 =raw t 'help.specifying_task'
28
28
29 %p
29 %p
30 =raw t 'help.example_cpp'
30 =raw t 'help.example_cpp'
31
31
32 %table{:border => '1'}
32 %table{:border => '1'}
33 %tr
33 %tr
34 %td{:width => '300px'}
34 %td{:width => '300px'}
35 %tt <tt>/*<br/>LANG: C++<br/>TASK: mobiles<br/>*/</tt>
35 %tt <tt>/*<br/>LANG: C++<br/>TASK: mobiles<br/>*/</tt>
36
36
37 %p
37 %p
38 =raw t 'help.example_pas'
38 =raw t 'help.example_pas'
39
39
40 %table{:border => '1'}
40 %table{:border => '1'}
41 %tr
41 %tr
42 %td{:width => '300px'}
42 %td{:width => '300px'}
43 %tt <tt>{<br/>LANG: Pascal<br/>TASK: mobiles<br/>}</tt>
43 %tt <tt>{<br/>LANG: Pascal<br/>TASK: mobiles<br/>}</tt>
44
44
45 %p
45 %p
46 - = raw(t('help.ask_questions_at_messages',:message_link_name => (t 'menu.messages'),:url => url_for(:controller => 'messages', :action => 'list')))
46 + = raw(t('help.ask_questions_at_messages',:message_link_name => (t 'menu.messages'),url: messages_path ))
47
47
@@ -21,48 +21,49
21 e = ace.edit("editor")
21 e = ace.edit("editor")
22 e.setOptions({ maxLines: Infinity })
22 e.setOptions({ maxLines: Infinity })
23 e.setValue($("#data").text())
23 e.setValue($("#data").text())
24 e.gotoLine(1)
24 e.gotoLine(1)
25 e.getSession().setMode("#{get_ace_mode(@submission.language)}")
25 e.getSession().setMode("#{get_ace_mode(@submission.language)}")
26 e.setReadOnly(true)
26 e.setReadOnly(true)
27 .col-md-5
27 .col-md-5
28 %table.table.table-striped
28 %table.table.table-striped
29 %tr
29 %tr
30 %td.text-right
30 %td.text-right
31 %strong User
31 %strong User
32 %td
32 %td
33 - if @submission.user
33 - if @submission.user
34 = link_to "#{@submission.user.login}", stat_user_path(@submission.user)
34 = link_to "#{@submission.user.login}", stat_user_path(@submission.user)
35 = @submission.user.full_name
35 = @submission.user.full_name
36 - else
36 - else
37 = "(n/a)"
37 = "(n/a)"
38 %tr
38 %tr
39 %td.text-right
39 %td.text-right
40 %strong Task
40 %strong Task
41 %td
41 %td
42 - if @submission.problem!=nil
42 - if @submission.problem!=nil
43 = link_to "[#{@submission.problem.name}]", stat_problem_path(@submission.problem)
43 = link_to "[#{@submission.problem.name}]", stat_problem_path(@submission.problem)
44 = @submission.problem.full_name
44 = @submission.problem.full_name
45 + = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @submission.problem
45 - else
46 - else
46 = "(n/a)"
47 = "(n/a)"
47 %tr
48 %tr
48 %td.text-right
49 %td.text-right
49 %strong Tries
50 %strong Tries
50 %td= @submission.number
51 %td= @submission.number
51 %tr
52 %tr
52 %td.text-right
53 %td.text-right
53 %strong Language
54 %strong Language
54 %td= @submission.language.pretty_name
55 %td= @submission.language.pretty_name
55 %tr
56 %tr
56 %td.text-right
57 %td.text-right
57 %strong Submitted
58 %strong Submitted
58 %td #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
59 %td #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
59 %tr
60 %tr
60 %td.text-right
61 %td.text-right
61 %strong Graded
62 %strong Graded
62 - if @submission.graded_at
63 - if @submission.graded_at
63 %td #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
64 %td #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
64 - else
65 - else
65 %td -
66 %td -
66 %tr
67 %tr
67 %td.text-right
68 %td.text-right
68 %strong Points
69 %strong Points
@@ -5,41 +5,50
5 .row
5 .row
6 .col-md-6
6 .col-md-6
7 .panel.panel-default
7 .panel.panel-default
8 .panel-heading
8 .panel-heading
9 .panel-title Info
9 .panel-title Info
10 .panel-body
10 .panel-body
11 %ul
11 %ul
12 %li
12 %li
13 List of user information in this format:
13 List of user information in this format:
14 %tt user_id,name(,passwd(,alias(,remark)))
14 %tt user_id,name(,passwd(,alias(,remark)))
15 %li
15 %li
16 Note that
16 Note that
17 %tt passwd, alias
17 %tt passwd, alias
18 and
18 and
19 %tt remark
19 %tt remark
20 is optional.
20 is optional.
21 %li
21 %li
22 When
22 When
23 %tt passwd
23 %tt passwd
24 or
24 or
25 %tt alias
25 %tt alias
26 is empty, the original value will be used instead.
26 is empty, the original value will be used instead.
27 %li
27 %li
28 If the users with the same user_id already exists, existing information will be overwritten.
28 If the users with the same user_id already exists, existing information will be overwritten.
29 + Example:
30 + %ol
31 + %li
32 + %pre user1,Somchai Jaidee
33 + will create (or update) a user with login "user1" and setting the fullname to "Somchai Jaidee", also setting a random password.
34 + %li
35 + %pre user1,Somchai Jaidee,
36 + will create (or update) a user with login "user1" and and setting the fullname "Somchai Jaidee". No change is made to the password unless this is a new user. If this is a new user, a random password will be generated.
37 +
29
38
30 .row
39 .row
31 .col-md-6
40 .col-md-6
32 = form_tag :action => 'create_from_list' do
41 = form_tag :action => 'create_from_list' do
33 .form-group
42 .form-group
34 = submit_tag 'Create following users',class: 'btn btn-success'
43 = submit_tag 'Create following users',class: 'btn btn-success'
35 .form-group
44 .form-group
36 .div.checkbox
45 .div.checkbox
37 %label
46 %label
38 = check_box_tag :add_to_group
47 = check_box_tag :add_to_group
39 Also add these users to the following group
48 Also add these users to the following group
40 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
49 = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
41 .form-group
50 .form-group
42 = text_area_tag 'user_list', nil, :rows => 50, :cols => 80
51 = text_area_tag 'user_list', nil, :rows => 50, :cols => 80
43 .col-md-6
52 .col-md-6
44
53
45
54
@@ -33,87 +33,87
33 get 'toggle'
33 get 'toggle'
34 get 'toggle_test'
34 get 'toggle_test'
35 get 'toggle_view_testcase'
35 get 'toggle_view_testcase'
36 get 'stat'
36 get 'stat'
37 end
37 end
38 collection do
38 collection do
39 get 'turn_all_off'
39 get 'turn_all_off'
40 get 'turn_all_on'
40 get 'turn_all_on'
41 get 'import'
41 get 'import'
42 get 'manage'
42 get 'manage'
43 get 'quick_create'
43 get 'quick_create'
44 post 'do_manage'
44 post 'do_manage'
45 post 'do_import'
45 post 'do_import'
46 end
46 end
47 end
47 end
48
48
49 resources :groups do
49 resources :groups do
50 member do
50 member do
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
51 post 'add_user', to: 'groups#add_user', as: 'add_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
52 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
53 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
54 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
55 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
56 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
57 + get 'toggle'
57 end
58 end
58 collection do
59 collection do
59
60
60 end
61 end
61 end
62 end
62
63
63 resources :testcases, only: [] do
64 resources :testcases, only: [] do
64 member do
65 member do
65 get 'download_input'
66 get 'download_input'
66 get 'download_sol'
67 get 'download_sol'
67 end
68 end
68 collection do
69 collection do
69 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
70 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
70 end
71 end
71 end
72 end
72
73
73 resources :grader_configuration, controller: 'configurations' do
74 resources :grader_configuration, controller: 'configurations' do
74 collection do
75 collection do
75 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
76 get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right'
76 end
77 end
77 end
78 end
78
79
79 resources :users do
80 resources :users do
80 member do
81 member do
81 get 'toggle_activate', 'toggle_enable'
82 get 'toggle_activate', 'toggle_enable'
82 get 'stat'
83 get 'stat'
83 end
84 end
84 collection do
85 collection do
85 get 'profile'
86 get 'profile'
86 post 'chg_passwd'
87 post 'chg_passwd'
87 end
88 end
88 end
89 end
89
90
90 resources :submissions do
91 resources :submissions do
91 member do
92 member do
92 get 'download'
93 get 'download'
93 get 'compiler_msg'
94 get 'compiler_msg'
94 get 'rejudge'
95 get 'rejudge'
95 - get 'source'
96 end
96 end
97 collection do
97 collection do
98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
98 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
99 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
100 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
101 end
101 end
102 end
102 end
103
103
104
104
105 #user admin
105 #user admin
106 resources :user_admin do
106 resources :user_admin do
107 collection do
107 collection do
108 match 'bulk_manage', via: [:get, :post]
108 match 'bulk_manage', via: [:get, :post]
109 get 'bulk_mail'
109 get 'bulk_mail'
110 get 'user_stat'
110 get 'user_stat'
111 get 'import'
111 get 'import'
112 get 'new_list'
112 get 'new_list'
113 get 'admin'
113 get 'admin'
114 get 'active'
114 get 'active'
115 get 'mass_mailing'
115 get 'mass_mailing'
116 get 'revoke_admin'
116 get 'revoke_admin'
117 post 'grant_admin'
117 post 'grant_admin'
118 match 'create_from_list', via: [:get, :post]
118 match 'create_from_list', via: [:get, :post]
119 match 'random_all_passwords', via: [:get, :post]
119 match 'random_all_passwords', via: [:get, :post]
@@ -156,49 +156,49
156 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
156 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
157 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
157 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
158 #get "report/login"
158 #get "report/login"
159 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
159 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
160 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
160 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
161
161
162 resource :main, only: [], controller: 'main' do
162 resource :main, only: [], controller: 'main' do
163 get 'login'
163 get 'login'
164 get 'logout'
164 get 'logout'
165 get 'list'
165 get 'list'
166 get 'submission(/:id)', action: 'submission', as: 'main_submission'
166 get 'submission(/:id)', action: 'submission', as: 'main_submission'
167 get 'announcements'
167 get 'announcements'
168 get 'help'
168 get 'help'
169 post 'submit'
169 post 'submit'
170 end
170 end
171 #main
171 #main
172 #get "main/list"
172 #get "main/list"
173 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
173 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
174 #post 'main/submit', to: 'main#submit'
174 #post 'main/submit', to: 'main#submit'
175 #get 'main/announcements', to: 'main#announcements'
175 #get 'main/announcements', to: 'main#announcements'
176
176
177
177
178 #
178 #
179 get 'tasks/view/:file.:ext' => 'tasks#view'
179 get 'tasks/view/:file.:ext' => 'tasks#view'
180 - get 'tasks/download/:id/:file.:ext' => 'tasks#download'
180 + get 'tasks/download/:id/:file.:ext' => 'tasks#download', as: 'download_task'
181 get 'heartbeat/:id/edit' => 'heartbeat#edit'
181 get 'heartbeat/:id/edit' => 'heartbeat#edit'
182
182
183 #grader
183 #grader
184 get 'graders/list', to: 'graders#list', as: 'grader_list'
184 get 'graders/list', to: 'graders#list', as: 'grader_list'
185 namespace :graders do
185 namespace :graders do
186 get 'task/:id/:type', action: 'task', as: 'task'
186 get 'task/:id/:type', action: 'task', as: 'task'
187 get 'view/:id/:type', action: 'view', as: 'view'
187 get 'view/:id/:type', action: 'view', as: 'view'
188 get 'clear/:id', action: 'clear', as: 'clear'
188 get 'clear/:id', action: 'clear', as: 'clear'
189 get 'stop'
189 get 'stop'
190 get 'stop_all'
190 get 'stop_all'
191 get 'clear_all'
191 get 'clear_all'
192 get 'clear_terminated'
192 get 'clear_terminated'
193 get 'start_grading'
193 get 'start_grading'
194 get 'start_exam'
194 get 'start_exam'
195
195
196 end
196 end
197
197
198
198
199 # See how all your routes lay out with "rake routes"
199 # See how all your routes lay out with "rake routes"
200
200
201 # This is a legacy wild controller route that's not recommended for RESTful applications.
201 # This is a legacy wild controller route that's not recommended for RESTful applications.
202 # Note: This route will make all actions in every controller accessible via GET requests.
202 # Note: This route will make all actions in every controller accessible via GET requests.
203 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
203 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
204 end
204 end
@@ -1,307 +1,308
1 # This file is auto-generated from the current state of the database. Instead
1 # This file is auto-generated from the current state of the database. Instead
2 # of editing this file, please use the migrations feature of Active Record to
2 # of editing this file, please use the migrations feature of Active Record to
3 # incrementally modify your database, and then regenerate this schema definition.
3 # incrementally modify your database, and then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your
5 # Note that this schema.rb definition is the authoritative source for your
6 # database schema. If you need to create the application database on another
6 # database schema. If you need to create the application database on another
7 # system, you should be using db:schema:load, not running all the migrations
7 # system, you should be using db:schema:load, not running all the migrations
8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 #
10 #
11 # It's strongly recommended that you check this file into your version control system.
11 # It's strongly recommended that you check this file into your version control system.
12
12
13 - ActiveRecord::Schema.define(version: 2018_06_12_102327) do
13 + ActiveRecord::Schema.define(version: 2020_08_13_083020) do
14
14
15 - create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
15 + create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
16 t.string "author"
16 t.string "author"
17 t.text "body"
17 t.text "body"
18 t.boolean "published"
18 t.boolean "published"
19 - t.datetime "created_at"
19 + t.datetime "created_at", null: false
20 - t.datetime "updated_at"
20 + t.datetime "updated_at", null: false
21 t.boolean "frontpage", default: false
21 t.boolean "frontpage", default: false
22 t.boolean "contest_only", default: false
22 t.boolean "contest_only", default: false
23 t.string "title"
23 t.string "title"
24 t.string "notes"
24 t.string "notes"
25 end
25 end
26
26
27 - create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
27 + create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
28 t.string "title"
28 t.string "title"
29 t.boolean "enabled"
29 t.boolean "enabled"
30 - t.datetime "created_at"
30 + t.datetime "created_at", null: false
31 - t.datetime "updated_at"
31 + t.datetime "updated_at", null: false
32 t.string "name"
32 t.string "name"
33 end
33 end
34
34
35 - create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
35 + create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
36 t.integer "contest_id"
36 t.integer "contest_id"
37 t.integer "problem_id"
37 t.integer "problem_id"
38 end
38 end
39
39
40 - create_table "contests_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
40 + create_table "contests_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
41 t.integer "contest_id"
41 t.integer "contest_id"
42 t.integer "user_id"
42 t.integer "user_id"
43 end
43 end
44
44
45 - create_table "countries", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
45 + create_table "countries", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
46 t.string "name"
46 t.string "name"
47 - t.datetime "created_at"
47 + t.datetime "created_at", null: false
48 - t.datetime "updated_at"
48 + t.datetime "updated_at", null: false
49 end
49 end
50
50
51 - create_table "descriptions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
51 + create_table "descriptions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
52 t.text "body"
52 t.text "body"
53 t.boolean "markdowned"
53 t.boolean "markdowned"
54 - t.datetime "created_at"
54 + t.datetime "created_at", null: false
55 - t.datetime "updated_at"
55 + t.datetime "updated_at", null: false
56 end
56 end
57
57
58 - create_table "grader_configurations", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
58 + create_table "grader_configurations", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
59 t.string "key"
59 t.string "key"
60 t.string "value_type"
60 t.string "value_type"
61 t.string "value"
61 t.string "value"
62 - t.datetime "created_at"
62 + t.datetime "created_at", null: false
63 - t.datetime "updated_at"
63 + t.datetime "updated_at", null: false
64 t.text "description"
64 t.text "description"
65 end
65 end
66
66
67 - create_table "grader_processes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
67 + create_table "grader_processes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
68 t.string "host"
68 t.string "host"
69 t.integer "pid"
69 t.integer "pid"
70 t.string "mode"
70 t.string "mode"
71 t.boolean "active"
71 t.boolean "active"
72 - t.datetime "created_at"
72 + t.datetime "created_at", null: false
73 - t.datetime "updated_at"
73 + t.datetime "updated_at", null: false
74 t.integer "task_id"
74 t.integer "task_id"
75 t.string "task_type"
75 t.string "task_type"
76 t.boolean "terminated"
76 t.boolean "terminated"
77 - t.index ["host", "pid"], name: "index_grader_processes_on_host_and_pid"
77 + t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
78 end
78 end
79
79
80 create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
80 create_table "groups", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
81 t.string "name"
81 t.string "name"
82 t.string "description"
82 t.string "description"
83 + t.boolean "enabled", default: true
83 end
84 end
84
85
85 create_table "groups_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
86 create_table "groups_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
86 t.integer "problem_id", null: false
87 t.integer "problem_id", null: false
87 t.integer "group_id", null: false
88 t.integer "group_id", null: false
88 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
89 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
89 end
90 end
90
91
91 create_table "groups_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
92 create_table "groups_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
92 t.integer "group_id", null: false
93 t.integer "group_id", null: false
93 t.integer "user_id", null: false
94 t.integer "user_id", null: false
94 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
95 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
95 end
96 end
96
97
97 - create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
98 + create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
98 t.integer "user_id"
99 t.integer "user_id"
99 t.string "ip_address"
100 t.string "ip_address"
100 - t.datetime "created_at"
101 + t.datetime "created_at", null: false
101 - t.datetime "updated_at"
102 + t.datetime "updated_at", null: false
102 t.string "status"
103 t.string "status"
103 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
104 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
104 end
105 end
105
106
106 - create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
107 + create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
107 t.string "name", limit: 10
108 t.string "name", limit: 10
108 t.string "pretty_name"
109 t.string "pretty_name"
109 t.string "ext", limit: 10
110 t.string "ext", limit: 10
110 t.string "common_ext"
111 t.string "common_ext"
111 end
112 end
112
113
113 - create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
114 + create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
114 t.integer "user_id"
115 t.integer "user_id"
115 t.string "ip_address"
116 t.string "ip_address"
116 - t.datetime "created_at"
117 + t.datetime "created_at", null: false
117 - t.datetime "updated_at"
118 + t.datetime "updated_at", null: false
118 end
119 end
119
120
120 - create_table "messages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
121 + create_table "messages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
121 t.integer "sender_id"
122 t.integer "sender_id"
122 t.integer "receiver_id"
123 t.integer "receiver_id"
123 t.integer "replying_message_id"
124 t.integer "replying_message_id"
124 t.text "body"
125 t.text "body"
125 t.boolean "replied"
126 t.boolean "replied"
126 - t.datetime "created_at"
127 + t.datetime "created_at", null: false
127 - t.datetime "updated_at"
128 + t.datetime "updated_at", null: false
128 end
129 end
129
130
130 - create_table "problems", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
131 + create_table "problems", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
131 t.string "name", limit: 30
132 t.string "name", limit: 30
132 t.string "full_name"
133 t.string "full_name"
133 t.integer "full_score"
134 t.integer "full_score"
134 t.date "date_added"
135 t.date "date_added"
135 t.boolean "available"
136 t.boolean "available"
136 t.string "url"
137 t.string "url"
137 t.integer "description_id"
138 t.integer "description_id"
138 t.boolean "test_allowed"
139 t.boolean "test_allowed"
139 t.boolean "output_only"
140 t.boolean "output_only"
140 t.string "description_filename"
141 t.string "description_filename"
141 t.boolean "view_testcase"
142 t.boolean "view_testcase"
142 end
143 end
143
144
144 create_table "problems_tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
145 create_table "problems_tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
145 t.integer "problem_id"
146 t.integer "problem_id"
146 t.integer "tag_id"
147 t.integer "tag_id"
147 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
148 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
148 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
149 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
149 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
150 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
150 end
151 end
151
152
152 - create_table "rights", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
153 + create_table "rights", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
153 t.string "name"
154 t.string "name"
154 t.string "controller"
155 t.string "controller"
155 t.string "action"
156 t.string "action"
156 end
157 end
157
158
158 - create_table "rights_roles", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
159 + create_table "rights_roles", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
159 t.integer "right_id"
160 t.integer "right_id"
160 t.integer "role_id"
161 t.integer "role_id"
161 t.index ["role_id"], name: "index_rights_roles_on_role_id"
162 t.index ["role_id"], name: "index_rights_roles_on_role_id"
162 end
163 end
163
164
164 - create_table "roles", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
165 + create_table "roles", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
165 t.string "name"
166 t.string "name"
166 end
167 end
167
168
168 - create_table "roles_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
169 + create_table "roles_users", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
169 t.integer "role_id"
170 t.integer "role_id"
170 t.integer "user_id"
171 t.integer "user_id"
171 t.index ["user_id"], name: "index_roles_users_on_user_id"
172 t.index ["user_id"], name: "index_roles_users_on_user_id"
172 end
173 end
173
174
174 - create_table "sessions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
175 + create_table "sessions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
175 t.string "session_id"
176 t.string "session_id"
176 t.text "data"
177 t.text "data"
177 t.datetime "updated_at"
178 t.datetime "updated_at"
178 t.index ["session_id"], name: "index_sessions_on_session_id"
179 t.index ["session_id"], name: "index_sessions_on_session_id"
179 t.index ["updated_at"], name: "index_sessions_on_updated_at"
180 t.index ["updated_at"], name: "index_sessions_on_updated_at"
180 end
181 end
181
182
182 - create_table "sites", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
183 + create_table "sites", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
183 t.string "name"
184 t.string "name"
184 t.boolean "started"
185 t.boolean "started"
185 t.datetime "start_time"
186 t.datetime "start_time"
186 - t.datetime "created_at"
187 + t.datetime "created_at", null: false
187 - t.datetime "updated_at"
188 + t.datetime "updated_at", null: false
188 t.integer "country_id"
189 t.integer "country_id"
189 t.string "password"
190 t.string "password"
190 end
191 end
191
192
192 - create_table "submission_view_logs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
193 + create_table "submission_view_logs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
193 t.integer "user_id"
194 t.integer "user_id"
194 t.integer "submission_id"
195 t.integer "submission_id"
195 - t.datetime "created_at"
196 + t.datetime "created_at", null: false
196 - t.datetime "updated_at"
197 + t.datetime "updated_at", null: false
197 end
198 end
198
199
199 - create_table "submissions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
200 + create_table "submissions", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
200 t.integer "user_id"
201 t.integer "user_id"
201 t.integer "problem_id"
202 t.integer "problem_id"
202 t.integer "language_id"
203 t.integer "language_id"
203 t.text "source", limit: 16777215
204 t.text "source", limit: 16777215
204 t.binary "binary"
205 t.binary "binary"
205 t.datetime "submitted_at"
206 t.datetime "submitted_at"
206 t.datetime "compiled_at"
207 t.datetime "compiled_at"
207 t.text "compiler_message"
208 t.text "compiler_message"
208 t.datetime "graded_at"
209 t.datetime "graded_at"
209 t.integer "points"
210 t.integer "points"
210 t.text "grader_comment"
211 t.text "grader_comment"
211 t.integer "number"
212 t.integer "number"
212 t.string "source_filename"
213 t.string "source_filename"
213 t.float "max_runtime"
214 t.float "max_runtime"
214 t.integer "peak_memory"
215 t.integer "peak_memory"
215 t.integer "effective_code_length"
216 t.integer "effective_code_length"
216 t.string "ip_address"
217 t.string "ip_address"
217 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
218 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
218 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
219 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
219 end
220 end
220
221
221 create_table "tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
222 create_table "tags", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
222 t.string "name", null: false
223 t.string "name", null: false
223 t.text "description"
224 t.text "description"
224 t.boolean "public"
225 t.boolean "public"
225 t.datetime "created_at", null: false
226 t.datetime "created_at", null: false
226 t.datetime "updated_at", null: false
227 t.datetime "updated_at", null: false
227 end
228 end
228
229
229 - create_table "tasks", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
230 + create_table "tasks", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
230 t.integer "submission_id"
231 t.integer "submission_id"
231 t.datetime "created_at"
232 t.datetime "created_at"
232 t.integer "status"
233 t.integer "status"
233 t.datetime "updated_at"
234 t.datetime "updated_at"
234 t.index ["submission_id"], name: "index_tasks_on_submission_id"
235 t.index ["submission_id"], name: "index_tasks_on_submission_id"
235 end
236 end
236
237
237 - create_table "test_pairs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
238 + create_table "test_pairs", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
238 t.integer "problem_id"
239 t.integer "problem_id"
239 t.text "input", limit: 16777215
240 t.text "input", limit: 16777215
240 t.text "solution", limit: 16777215
241 t.text "solution", limit: 16777215
241 - t.datetime "created_at"
242 + t.datetime "created_at", null: false
242 - t.datetime "updated_at"
243 + t.datetime "updated_at", null: false
243 end
244 end
244
245
245 - create_table "test_requests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
246 + create_table "test_requests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
246 t.integer "user_id"
247 t.integer "user_id"
247 t.integer "problem_id"
248 t.integer "problem_id"
248 t.integer "submission_id"
249 t.integer "submission_id"
249 t.string "input_file_name"
250 t.string "input_file_name"
250 t.string "output_file_name"
251 t.string "output_file_name"
251 t.string "running_stat"
252 t.string "running_stat"
252 t.integer "status"
253 t.integer "status"
253 - t.datetime "updated_at"
254 + t.datetime "updated_at", null: false
254 t.datetime "submitted_at"
255 t.datetime "submitted_at"
255 t.datetime "compiled_at"
256 t.datetime "compiled_at"
256 t.text "compiler_message"
257 t.text "compiler_message"
257 t.datetime "graded_at"
258 t.datetime "graded_at"
258 t.string "grader_comment"
259 t.string "grader_comment"
259 - t.datetime "created_at"
260 + t.datetime "created_at", null: false
260 t.float "running_time"
261 t.float "running_time"
261 t.string "exit_status"
262 t.string "exit_status"
262 t.integer "memory_usage"
263 t.integer "memory_usage"
263 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
264 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
264 end
265 end
265
266
266 create_table "testcases", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
267 create_table "testcases", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
267 t.integer "problem_id"
268 t.integer "problem_id"
268 t.integer "num"
269 t.integer "num"
269 t.integer "group"
270 t.integer "group"
270 t.integer "score"
271 t.integer "score"
271 t.text "input", limit: 4294967295
272 t.text "input", limit: 4294967295
272 t.text "sol", limit: 4294967295
273 t.text "sol", limit: 4294967295
273 t.datetime "created_at"
274 t.datetime "created_at"
274 t.datetime "updated_at"
275 t.datetime "updated_at"
275 t.index ["problem_id"], name: "index_testcases_on_problem_id"
276 t.index ["problem_id"], name: "index_testcases_on_problem_id"
276 end
277 end
277
278
278 - create_table "user_contest_stats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
279 + create_table "user_contest_stats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
279 t.integer "user_id"
280 t.integer "user_id"
280 t.datetime "started_at"
281 t.datetime "started_at"
281 - t.datetime "created_at"
282 + t.datetime "created_at", null: false
282 - t.datetime "updated_at"
283 + t.datetime "updated_at", null: false
283 t.boolean "forced_logout"
284 t.boolean "forced_logout"
284 end
285 end
285
286
286 - create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
287 + create_table "users", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci", force: :cascade do |t|
287 t.string "login", limit: 50
288 t.string "login", limit: 50
288 t.string "full_name"
289 t.string "full_name"
289 t.string "hashed_password"
290 t.string "hashed_password"
290 t.string "salt", limit: 5
291 t.string "salt", limit: 5
291 t.string "alias"
292 t.string "alias"
292 t.string "email"
293 t.string "email"
293 t.integer "site_id"
294 t.integer "site_id"
294 t.integer "country_id"
295 t.integer "country_id"
295 t.boolean "activated", default: false
296 t.boolean "activated", default: false
296 t.datetime "created_at"
297 t.datetime "created_at"
297 t.datetime "updated_at"
298 t.datetime "updated_at"
298 - t.string "section"
299 t.boolean "enabled", default: true
299 t.boolean "enabled", default: true
300 t.string "remark"
300 t.string "remark"
301 t.string "last_ip"
301 t.string "last_ip"
302 + t.string "section"
302 t.index ["login"], name: "index_users_on_login", unique: true
303 t.index ["login"], name: "index_users_on_login", unique: true
303 end
304 end
304
305
305 add_foreign_key "problems_tags", "problems"
306 add_foreign_key "problems_tags", "problems"
306 add_foreign_key "problems_tags", "tags"
307 add_foreign_key "problems_tags", "tags"
307 end
308 end
You need to be logged in to leave comments. Login now