Description:
add remove_all in groups consolidate submissions viewing from grader/task
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r680:4ce0b8696d06 - - 9 files changed: 34 inserted, 137 deleted

@@ -1,128 +1,93
1 1 class GradersController < ApplicationController
2 2
3 - before_filter :admin_authorization, except: [ :submission ]
4 - before_filter(only: [:submission]) {
5 - #check if authenticated
6 - return false unless authenticate
7 -
8 - #admin always has privileged
9 - if @current_user.admin?
10 - return true
11 - end
12 -
13 - if GraderConfiguration["right.user_view_submission"] and Submission.find(params[:id]).problem.available?
14 - return true
15 - else
16 - unauthorized_redirect
17 - return false
18 - end
19 - }
3 + before_filter :admin_authorization
20 4
21 5 verify :method => :post, :only => ['clear_all',
22 6 'start_exam',
23 7 'start_grading',
24 8 'stop_all',
25 9 'clear_terminated'],
26 10 :redirect_to => {:action => 'index'}
27 11
28 12 def index
29 13 redirect_to :action => 'list'
30 14 end
31 15
32 16 def list
33 17 @grader_processes = GraderProcess.find_running_graders
34 18 @stalled_processes = GraderProcess.find_stalled_process
35 19
36 20 @terminated_processes = GraderProcess.find_terminated_graders
37 21
38 22 @last_task = Task.last
39 23 @last_test_request = TestRequest.last
40 24 @submission = Submission.order("id desc").limit(20)
41 25 @backlog_submission = Submission.where('graded_at is null')
42 26 end
43 27
44 28 def clear
45 29 grader_proc = GraderProcess.find(params[:id])
46 30 grader_proc.destroy if grader_proc!=nil
47 31 redirect_to :action => 'list'
48 32 end
49 33
50 34 def clear_terminated
51 35 GraderProcess.find_terminated_graders.each do |p|
52 36 p.destroy
53 37 end
54 38 redirect_to :action => 'list'
55 39 end
56 40
57 41 def clear_all
58 42 GraderProcess.all.each do |p|
59 43 p.destroy
60 44 end
61 45 redirect_to :action => 'list'
62 46 end
63 47
64 48 def view
65 49 if params[:type]=='Task'
66 50 redirect_to :action => 'task', :id => params[:id]
67 51 else
68 52 redirect_to :action => 'test_request', :id => params[:id]
69 53 end
70 54 end
71 55
72 56 def test_request
73 57 @test_request = TestRequest.find(params[:id])
74 58 end
75 59
76 60 def task
77 61 @task = Task.find(params[:id])
78 62 end
79 63
80 - def submission
81 - @submission = Submission.find(params[:id])
82 - formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', line_numbers: true )
83 - lexer = case @submission.language.name
84 - when "c" then Rouge::Lexers::C.new
85 - when "cpp" then Rouge::Lexers::Cpp.new
86 - when "pas" then Rouge::Lexers::Pas.new
87 - when "ruby" then Rouge::Lexers::Ruby.new
88 - when "python" then Rouge::Lexers::Python.new
89 - when "java" then Rouge::Lexers::Java.new
90 - when "php" then Rouge::Lexers::PHP.new
91 - end
92 - @formatted_code = formatter.format(lexer.lex(@submission.source))
93 - @css_style = Rouge::Themes::ThankfulEyes.render(scope: '.highlight')
94 -
95 - user = User.find(session[:user_id])
96 - SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
97 -
98 - end
99 64
100 65 # various grader controls
101 66
102 67 def stop
103 68 grader_proc = GraderProcess.find(params[:id])
104 69 GraderScript.stop_grader(grader_proc.pid)
105 70 flash[:notice] = 'Grader stopped. It may not disappear now, but it should disappear shortly.'
106 71 redirect_to :action => 'list'
107 72 end
108 73
109 74 def stop_all
110 75 GraderScript.stop_graders(GraderProcess.find_running_graders +
111 76 GraderProcess.find_stalled_process)
112 77 flash[:notice] = 'Graders stopped. They may not disappear now, but they should disappear shortly.'
113 78 redirect_to :action => 'list'
114 79 end
115 80
116 81 def start_grading
117 82 GraderScript.start_grader('grading')
118 83 flash[:notice] = '2 graders in grading env started, one for grading queue tasks, another for grading test request'
119 84 redirect_to :action => 'list'
120 85 end
121 86
122 87 def start_exam
123 88 GraderScript.start_grader('exam')
124 89 flash[:notice] = '2 graders in grading env started, one for grading queue tasks, another for grading test request'
125 90 redirect_to :action => 'list'
126 91 end
127 92
128 93 end
@@ -1,94 +1,104
1 1 class GroupsController < ApplicationController
2 2 before_action :set_group, only: [:show, :edit, :update, :destroy,
3 - :add_user, :remove_user,
4 - :add_problem, :remove_problem,
3 + :add_user, :remove_user,:remove_all_user,
4 + :add_problem, :remove_problem,:remove_all_problem,
5 5 ]
6 6 before_action :authenticate, :admin_authorization
7 7
8 8 # GET /groups
9 9 def index
10 10 @groups = Group.all
11 11 end
12 12
13 13 # GET /groups/1
14 14 def show
15 15 end
16 16
17 17 # GET /groups/new
18 18 def new
19 19 @group = Group.new
20 20 end
21 21
22 22 # GET /groups/1/edit
23 23 def edit
24 24 end
25 25
26 26 # POST /groups
27 27 def create
28 28 @group = Group.new(group_params)
29 29
30 30 if @group.save
31 31 redirect_to @group, notice: 'Group was successfully created.'
32 32 else
33 33 render :new
34 34 end
35 35 end
36 36
37 37 # PATCH/PUT /groups/1
38 38 def update
39 39 if @group.update(group_params)
40 40 redirect_to @group, notice: 'Group was successfully updated.'
41 41 else
42 42 render :edit
43 43 end
44 44 end
45 45
46 46 # DELETE /groups/1
47 47 def destroy
48 48 @group.destroy
49 49 redirect_to groups_url, notice: 'Group was successfully destroyed.'
50 50 end
51 51
52 52 def remove_user
53 53 user = User.find(params[:user_id])
54 54 @group.users.delete(user)
55 55 redirect_to group_path(@group), flash: {success: "User #{user.login} was removed from the group #{@group.name}"}
56 56 end
57 57
58 + def remove_all_user
59 + @group.users.clear
60 + redirect_to group_path(@group), alert: 'All users removed'
61 + end
62 +
63 + def remove_all_problem
64 + @group.problems.clear
65 + redirect_to group_path(@group), alert: 'All problems removed'
66 + end
67 +
58 68 def add_user
59 69 user = User.find(params[:user_id])
60 70 begin
61 71 @group.users << user
62 72 redirect_to group_path(@group), flash: { success: "User #{user.login} was add to the group #{@group.name}"}
63 73 rescue => e
64 74 redirect_to group_path(@group), alert: e.message
65 75 end
66 76 end
67 77
68 78 def remove_problem
69 79 problem = Problem.find(params[:problem_id])
70 80 @group.problems.delete(problem)
71 81 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was removed from the group #{@group.name}" }
72 82 end
73 83
74 84 def add_problem
75 85 problem = Problem.find(params[:problem_id])
76 86 begin
77 87 @group.problems << problem
78 88 redirect_to group_path(@group), flash: {success: "Problem #{problem.name} was add to the group #{@group.name}" }
79 89 rescue => e
80 90 redirect_to group_path(@group), alert: e.message
81 91 end
82 92 end
83 93
84 94 private
85 95 # Use callbacks to share common setup or constraints between actions.
86 96 def set_group
87 97 @group = Group.find(params[:id])
88 98 end
89 99
90 100 # Only allow a trusted parameter "white list" through.
91 101 def group_params
92 102 params.require(:group).permit(:name, :description)
93 103 end
94 104 end
@@ -1,75 +1,75
1 1 class TasksController < ApplicationController
2 2
3 3 before_filter :authenticate, :check_viewability
4 4
5 5 def index
6 6 redirect_to :action => 'list'
7 7 end
8 8
9 9 def list
10 10 @problems = @user.available_problems
11 11 end
12 12
13 13 # this has contest-wide access control
14 14 def view
15 15 base_name = params[:file]
16 16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
17 17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
18 18
19 19 if !FileTest.exists?(filename)
20 20 redirect_to :action => 'index' and return
21 21 end
22 22
23 23 send_file_to_user(filename, base_filename)
24 24 end
25 25
26 26 # this has problem-level access control
27 27 def download
28 28 problem = Problem.find(params[:id])
29 - if !problem or !problem.available or !@user.can_view_problem? problem
29 + unless @current_user.can_view_problem? problem
30 30 redirect_to :action => 'index' and return
31 31 end
32 32
33 33 base_name = params[:file]
34 34 base_filename = File.basename("#{base_name}.#{params[:ext]}")
35 35 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
36 36 puts "SENDING: #{filename}"
37 37
38 38 if !FileTest.exists?(filename)
39 39 redirect_to :action => 'index' and return
40 40 end
41 41
42 42 puts "SENDING: #{filename}"
43 43
44 44 send_file_to_user(filename, base_filename)
45 45 end
46 46
47 47 protected
48 48
49 49 def send_file_to_user(filename, base_filename)
50 50 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
51 51 response.headers['Content-Type'] = "application/force-download"
52 52 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
53 53 response.headers["X-Sendfile"] = filename
54 54 response.headers['Content-length'] = File.size(filename)
55 55 render :nothing => true
56 56 else
57 57 if params[:ext]=='pdf'
58 58 content_type = 'application/pdf'
59 59 else
60 60 content_type = 'application/octet-stream'
61 61 end
62 62
63 63 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
64 64 end
65 65 end
66 66
67 67 def check_viewability
68 68 @user = User.find(session[:user_id])
69 69 if @user==nil or !GraderConfiguration.show_tasks_to?(@user)
70 70 redirect_to :controller => 'main', :action => 'list'
71 71 return false
72 72 end
73 73 end
74 74
75 75 end
@@ -1,419 +1,416
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 3 require 'net/https'
4 4 require 'net/http'
5 5 require 'json'
6 6
7 7 class User < ActiveRecord::Base
8 8
9 9 has_and_belongs_to_many :roles
10 10
11 11 #has_and_belongs_to_many :groups
12 12 has_many :groups_users, class_name: GroupUser
13 13 has_many :groups, :through => :groups_users
14 14
15 15 has_many :test_requests, -> {order(submitted_at: DESC)}
16 16
17 17 has_many :messages, -> { order(created_at: DESC) },
18 18 :class_name => "Message",
19 19 :foreign_key => "sender_id"
20 20
21 21 has_many :replied_messages, -> { order(created_at: DESC) },
22 22 :class_name => "Message",
23 23 :foreign_key => "receiver_id"
24 24
25 25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26 26
27 27 belongs_to :site
28 28 belongs_to :country
29 29
30 30 has_and_belongs_to_many :contests, -> { order(:name); uniq}
31 31
32 32 scope :activated_users, -> {where activated: true}
33 33
34 34 validates_presence_of :login
35 35 validates_uniqueness_of :login
36 36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 37 validates_length_of :login, :within => 3..30
38 38
39 39 validates_presence_of :full_name
40 40 validates_length_of :full_name, :minimum => 1
41 41
42 42 validates_presence_of :password, :if => :password_required?
43 43 validates_length_of :password, :within => 4..20, :if => :password_required?
44 44 validates_confirmation_of :password, :if => :password_required?
45 45
46 46 validates_format_of :email,
47 47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 48 :if => :email_validation?
49 49 validate :uniqueness_of_email_from_activated_users,
50 50 :if => :email_validation?
51 51 validate :enough_time_interval_between_same_email_registrations,
52 52 :if => :email_validation?
53 53
54 54 # these are for ytopc
55 55 # disable for now
56 56 #validates_presence_of :province
57 57
58 58 attr_accessor :password
59 59
60 60 before_save :encrypt_new_password
61 61 before_save :assign_default_site
62 62 before_save :assign_default_contest
63 63
64 64 # this is for will_paginate
65 65 cattr_reader :per_page
66 66 @@per_page = 50
67 67
68 68 def self.authenticate(login, password)
69 69 user = find_by_login(login)
70 70 if user
71 71 return user if user.authenticated?(password)
72 72 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
73 73 user.password = password
74 74 user.save
75 75 return user
76 76 end
77 77 end
78 78 end
79 79
80 80 def authenticated?(password)
81 81 if self.activated
82 82 hashed_password == User.encrypt(password,self.salt)
83 83 else
84 84 false
85 85 end
86 86 end
87 87
88 88 def authenticated_by_pop3?(password)
89 89 Net::POP3.enable_ssl
90 90 pop = Net::POP3.new('pops.it.chula.ac.th')
91 91 authen = true
92 92 begin
93 93 pop.start(login, password)
94 94 pop.finish
95 95 return true
96 96 rescue
97 97 return false
98 98 end
99 99 end
100 100
101 101 def authenticated_by_cucas?(password)
102 102 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
103 103 appid = '41508763e340d5858c00f8c1a0f5a2bb'
104 104 appsecret ='d9cbb5863091dbe186fded85722a1e31'
105 105 post_args = {
106 106 'appid' => appid,
107 107 'appsecret' => appsecret,
108 108 'username' => login,
109 109 'password' => password
110 110 }
111 111
112 112 #simple call
113 113 begin
114 114 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
115 115 http.use_ssl = true
116 116 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
117 117 result = [ ]
118 118 http.start do |http|
119 119 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
120 120 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
121 121 resp = http.request(req,param)
122 122 result = JSON.parse resp.body
123 123 end
124 124 return true if result["type"] == "beanStudent"
125 125 rescue => e
126 126 return false
127 127 end
128 128 return false
129 129 end
130 130
131 131 def admin?
132 132 self.roles.detect {|r| r.name == 'admin' }
133 133 end
134 134
135 135 def email_for_editing
136 136 if self.email==nil
137 137 "(unknown)"
138 138 elsif self.email==''
139 139 "(blank)"
140 140 else
141 141 self.email
142 142 end
143 143 end
144 144
145 145 def email_for_editing=(e)
146 146 self.email=e
147 147 end
148 148
149 149 def alias_for_editing
150 150 if self.alias==nil
151 151 "(unknown)"
152 152 elsif self.alias==''
153 153 "(blank)"
154 154 else
155 155 self.alias
156 156 end
157 157 end
158 158
159 159 def alias_for_editing=(e)
160 160 self.alias=e
161 161 end
162 162
163 163 def activation_key
164 164 if self.hashed_password==nil
165 165 encrypt_new_password
166 166 end
167 167 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
168 168 end
169 169
170 170 def verify_activation_key(key)
171 171 key == activation_key
172 172 end
173 173
174 174 def self.random_password(length=5)
175 175 chars = 'abcdefghjkmnopqrstuvwxyz'
176 176 password = ''
177 177 length.times { password << chars[rand(chars.length - 1)] }
178 178 password
179 179 end
180 180
181 181 def self.find_non_admin_with_prefix(prefix='')
182 182 users = User.all
183 183 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
184 184 end
185 185
186 186 # Contest information
187 187
188 188 def self.find_users_with_no_contest()
189 189 users = User.all
190 190 return users.find_all { |u| u.contests.length == 0 }
191 191 end
192 192
193 193
194 194 def contest_time_left
195 195 if GraderConfiguration.contest_mode?
196 196 return nil if site==nil
197 197 return site.time_left
198 198 elsif GraderConfiguration.indv_contest_mode?
199 199 time_limit = GraderConfiguration.contest_time_limit
200 200 if time_limit == nil
201 201 return nil
202 202 end
203 203 if contest_stat==nil or contest_stat.started_at==nil
204 204 return (Time.now.gmtime + time_limit) - Time.now.gmtime
205 205 else
206 206 finish_time = contest_stat.started_at + time_limit
207 207 current_time = Time.now.gmtime
208 208 if current_time > finish_time
209 209 return 0
210 210 else
211 211 return finish_time - current_time
212 212 end
213 213 end
214 214 else
215 215 return nil
216 216 end
217 217 end
218 218
219 219 def contest_finished?
220 220 if GraderConfiguration.contest_mode?
221 221 return false if site==nil
222 222 return site.finished?
223 223 elsif GraderConfiguration.indv_contest_mode?
224 224 return false if self.contest_stat(true)==nil
225 225 return contest_time_left == 0
226 226 else
227 227 return false
228 228 end
229 229 end
230 230
231 231 def contest_started?
232 232 if GraderConfiguration.indv_contest_mode?
233 233 stat = self.contest_stat
234 234 return ((stat != nil) and (stat.started_at != nil))
235 235 elsif GraderConfiguration.contest_mode?
236 236 return true if site==nil
237 237 return site.started
238 238 else
239 239 return true
240 240 end
241 241 end
242 242
243 243 def update_start_time
244 244 stat = self.contest_stat
245 245 if stat.nil? or stat.started_at.nil?
246 246 stat ||= UserContestStat.new(:user => self)
247 247 stat.started_at = Time.now.gmtime
248 248 stat.save
249 249 end
250 250 end
251 251
252 252 def problem_in_user_contests?(problem)
253 253 problem_contests = problem.contests.all
254 254
255 255 if problem_contests.length == 0 # this is public contest
256 256 return true
257 257 end
258 258
259 259 contests.each do |contest|
260 260 if problem_contests.find {|c| c.id == contest.id }
261 261 return true
262 262 end
263 263 end
264 264 return false
265 265 end
266 266
267 267 def available_problems_group_by_contests
268 268 contest_problems = []
269 269 pin = {}
270 270 contests.enabled.each do |contest|
271 271 available_problems = contest.problems.available
272 272 contest_problems << {
273 273 :contest => contest,
274 274 :problems => available_problems
275 275 }
276 276 available_problems.each {|p| pin[p.id] = true}
277 277 end
278 278 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
279 279 contest_problems << {
280 280 :contest => nil,
281 281 :problems => other_avaiable_problems
282 282 }
283 283 return contest_problems
284 284 end
285 285
286 286 def solve_all_available_problems?
287 287 available_problems.each do |p|
288 288 u = self
289 289 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
290 290 return false if !p or !sub or sub.points < p.full_score
291 291 end
292 292 return true
293 293 end
294 294
295 295 def available_problems
296 296 if not GraderConfiguration.multicontests?
297 297 if GraderConfiguration.use_problem_group?
298 298 return available_problems_in_group
299 299 else
300 300 return Problem.available_problems
301 301 end
302 302 else
303 303 contest_problems = []
304 304 pin = {}
305 305 contests.enabled.each do |contest|
306 306 contest.problems.available.each do |problem|
307 307 if not pin.has_key? problem.id
308 308 contest_problems << problem
309 309 end
310 310 pin[problem.id] = true
311 311 end
312 312 end
313 313 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
314 314 return contest_problems + other_avaiable_problems
315 315 end
316 316 end
317 317
318 318 def available_problems_in_group
319 319 problem = []
320 320 self.groups.each do |group|
321 321 group.problems.where(available: true).each { |p| problem << p }
322 322 end
323 323 problem.uniq!
324 324 if problem
325 325 problem.sort! do |a,b|
326 326 case
327 327 when a.date_added < b.date_added
328 328 1
329 329 when a.date_added > b.date_added
330 330 -1
331 331 else
332 332 a.name <=> b.name
333 333 end
334 334 end
335 335 return problem
336 336 else
337 337 return []
338 338 end
339 339 end
340 340
341 341 def can_view_problem?(problem)
342 - if not GraderConfiguration.multicontests?
343 - return problem.available
344 - else
345 - return problem_in_user_contests? problem
346 - end
342 + return true if admin?
343 + return available_problems.include? problem
347 344 end
348 345
349 346 def self.clear_last_login
350 347 User.update_all(:last_ip => nil)
351 348 end
352 349
353 350 protected
354 351 def encrypt_new_password
355 352 return if password.blank?
356 353 self.salt = (10+rand(90)).to_s
357 354 self.hashed_password = User.encrypt(self.password,self.salt)
358 355 end
359 356
360 357 def assign_default_site
361 358 # have to catch error when migrating (because self.site is not available).
362 359 begin
363 360 if self.site==nil
364 361 self.site = Site.find_by_name('default')
365 362 if self.site==nil
366 363 self.site = Site.find(1) # when 'default has be renamed'
367 364 end
368 365 end
369 366 rescue
370 367 end
371 368 end
372 369
373 370 def assign_default_contest
374 371 # have to catch error when migrating (because self.site is not available).
375 372 begin
376 373 if self.contests.length == 0
377 374 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
378 375 if default_contest
379 376 self.contests = [default_contest]
380 377 end
381 378 end
382 379 rescue
383 380 end
384 381 end
385 382
386 383 def password_required?
387 384 self.hashed_password.blank? || !self.password.blank?
388 385 end
389 386
390 387 def self.encrypt(string,salt)
391 388 Digest::SHA1.hexdigest(salt + string)
392 389 end
393 390
394 391 def uniqueness_of_email_from_activated_users
395 392 user = User.activated_users.find_by_email(self.email)
396 393 if user and (user.login != self.login)
397 394 self.errors.add(:base,"Email has already been taken")
398 395 end
399 396 end
400 397
401 398 def enough_time_interval_between_same_email_registrations
402 399 return if !self.new_record?
403 400 return if self.activated
404 401 open_user = User.find_by_email(self.email,
405 402 :order => 'created_at DESC')
406 403 if open_user and open_user.created_at and
407 404 (open_user.created_at > Time.now.gmtime - 5.minutes)
408 405 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
409 406 end
410 407 end
411 408
412 409 def email_validation?
413 410 begin
414 411 return VALIDATE_USER_EMAILS
415 412 rescue
416 413 return false
417 414 end
418 415 end
419 416 end
@@ -1,15 +1,15
1 1 %h1= "Task: #{@task.id}"
2 2
3 3 %p
4 4 User:
5 5 = "#{@task.submission.user.login}"
6 6 %br/
7 7 Status:
8 8 = "#{@task.status_str} (at #{format_short_time(@task.updated_at)})"
9 9 %br/
10 10 = "Submission: #{@task.submission_id}"
11 11 - if @task.submission !=nil
12 - = link_to '[view submission]', :action => 'submission', :id => @task.submission.id
12 + = link_to '[view submission]', submission_path( @task.submission.id )
13 13 %br/
14 14 = "Submitted at: #{format_short_time(@task.created_at)}"
15 15 %br/
@@ -1,72 +1,73
1 1 %p
2 2 %b Name:
3 3 = @group.name
4 4 %p
5 5 %b Description:
6 6 = @group.description
7 7
8 8 %br
9 9 = link_to 'Edit', edit_group_path(@group)
10 10 \|
11 11 = link_to 'Back', groups_path
12 12
13 13 .row
14 + .col-md-12
14 15 %h1 Group details
15 16 .row
16 17 .col-md-6
17 18 .panel.panel-default
18 19 .panel-heading
19 20 .panel-title Users in this group
20 21 .panel-body
21 22 =form_tag add_user_group_path(@group), class: 'form-inline' do
22 23 .form-group
23 24 =label_tag :user_id, "User"
24 25 =select_tag :user_id, options_from_collection_for_select(User.all,'id','full_name'), class: 'select2'
25 26 =submit_tag "Add",class: 'btn btn-primary'
26 27
27 28
28 29 %table.table.table-hover
29 30 %thead
30 31 %tr
31 32 %th Login
32 33 %th Full name
33 34 %th Remark
34 - %th
35 + %th= link_to 'Remove All', remove_all_user_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL USERS from group?" }, class: 'btn btn-danger btn-sm'
35 36
36 37 %tbody
37 38 - @group.users.each do |user|
38 39 %tr
39 40 %td= user.login
40 41 %td= user.full_name
41 42 %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 + %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger btn-sm'
43 44 .col-md-6
44 45 .panel.panel-default
45 46 .panel-heading
46 47 .panel-title Problems
47 48 .panel-body
48 49
49 50 =form_tag add_problem_group_path(@group), class: 'form-inline' do
50 51 .form-group
51 52 =label_tag :problem_id, "Problem"
52 53 =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','full_name'), class: 'select2'
53 54 =submit_tag "Add",class: 'btn btn-primary'
54 55
55 56
56 57 %table.table.table-hover
57 58 %thead
58 59 %tr
59 60 %th name
60 61 %th Full name
61 62 %th Full score
62 - %th
63 + %th= link_to 'Remove All', remove_all_problem_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL PROBLEMS from group?" }, class: 'btn btn-danger btn-sm'
63 64
64 65 %tbody
65 66 - @group.problems.each do |problem|
66 67 %tr
67 68 %td= problem.name
68 69 %td= problem.full_name
69 70 %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 + %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger btn-sm'
71 72
72 73
@@ -1,54 +1,60
1 1 - content_for :head do
2 2 = stylesheet_link_tag 'problems'
3 3 %h1 Problems
4 4 %p
5 5 = link_to 'Import problems', {:action => 'import'}, class: 'btn btn-success btn-sm'
6 6 = link_to 'New problem', new_problem_path, class: 'btn btn-success btn-sm'
7 7 = link_to 'Bulk Manage', { action: 'manage'}, class: 'btn btn-info btn-sm'
8 8 = link_to 'Turn off all problems', {:action => 'turn_all_off'}, class: 'btn btn-default btn-sm'
9 9 = link_to 'Turn on all problems', {:action => 'turn_all_on'}, class: 'btn btn-default btn-sm'
10 10 .submitbox
11 11 = form_tag :action => 'quick_create' do
12 12 %b Quick New:
13 13 %label{:for => "problem_name"} Name
14 14 = text_field 'problem', 'name'
15 15 |
16 16 %label{:for => "problem_full_name"} Full name
17 17 = text_field 'problem', 'full_name'
18 18 = submit_tag "Create"
19 19 %table.table.table-condense.table-hover
20 20 %thead
21 21 %th Name
22 22 %th Full name
23 23 %th.text-right Full score
24 + %th
25 + Submit
26 + %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Admin can always submit to any problem' } [?]
24 27 %th Date added
25 28 %th.text-center
26 29 Avail?
27 30 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user submits to this problem?' } [?]
28 31 %th.text-center
29 32 View Data?
30 33 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user view the testcase of this problem?' } [?]
31 34 %th.text-center
32 35 Test?
33 36 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?]
34 37 - if GraderConfiguration.multicontests?
35 38 %th Contests
36 39 - for problem in @problems
37 40 %tr{:class => "#{(problem.available) ? "success" : "danger"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
38 41 - @problem=problem
39 42 %td= problem.name #in_place_editor_field :problem, :name, {}, :rows=>1
40 - %td= problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
43 + %td
44 + = problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
45 + = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, problem
41 46 %td.text-right= problem.full_score #in_place_editor_field :problem, :full_score, {}, :rows=>1
47 + %td= link_to "Submit", direct_edit_problem_submissions_path(problem), class: 'btn btn-xs btn-primary'
42 48 %td= problem.date_added
43 49 %td= toggle_button(@problem.available?, toggle_problem_path(@problem), "problem-avail-#{@problem.id}")
44 50 %td= toggle_button(@problem.view_testcase?, toggle_view_testcase_problem_path(@problem), "problem-view-testcase-#{@problem.id}")
45 51 %td= toggle_button(@problem.test_allowed?, toggle_test_problem_path(@problem), "problem-test-#{@problem.id}")
46 52 - if GraderConfiguration.multicontests?
47 53 %td
48 54 = problem.contests.collect { |c| c.name }.join(', ')
49 55 %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-xs btn-block'
50 56 %td= link_to 'Show', {:action => 'show', :id => problem}, class: 'btn btn-info btn-xs btn-block'
51 57 %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-xs btn-block'
52 58 %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-xs btn-block'
53 59 %br/
54 60 = link_to '[New problem]', :action => 'new'
@@ -1,108 +1,113
1 1 CafeGrader::Application.routes.draw do
2 2 get "sources/direct_edit"
3 3
4 4 root :to => 'main#login'
5 5
6 6 #logins
7 7 get 'login/login', to: 'login#login'
8 8
9 9 resources :contests
10 10
11 11 resources :sites
12 12
13 13 resources :announcements do
14 14 member do
15 15 get 'toggle','toggle_front'
16 16 end
17 17 end
18 18
19 19 resources :problems do
20 20 member do
21 21 get 'toggle'
22 22 get 'toggle_test'
23 23 get 'toggle_view_testcase'
24 24 get 'stat'
25 25 end
26 26 collection do
27 27 get 'turn_all_off'
28 28 get 'turn_all_on'
29 29 get 'import'
30 30 get 'manage'
31 31 end
32 32 end
33 33
34 34 resources :groups do
35 35 member do
36 36 post 'add_user', to: 'groups#add_user', as: 'add_user'
37 37 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
38 + delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
38 39 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
39 40 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
41 + delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
42 + end
43 + collection do
44 +
40 45 end
41 46 end
42 47
43 48 resources :testcases, only: [] do
44 49 member do
45 50 get 'download_input'
46 51 get 'download_sol'
47 52 end
48 53 collection do
49 54 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
50 55 end
51 56 end
52 57
53 58 resources :grader_configuration, controller: 'configurations'
54 59
55 60 resources :users do
56 61 member do
57 62 get 'toggle_activate', 'toggle_enable'
58 63 get 'stat'
59 64 end
60 65 end
61 66
62 67 resources :submissions do
63 68 member do
64 69 get 'download'
65 70 get 'compiler_msg'
66 71 get 'rejudge'
67 72 end
68 73 collection do
69 74 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
70 75 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
71 76 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
72 77 end
73 78 end
74 79
75 80
76 81
77 82 #main
78 83 get "main/list"
79 84 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
80 85
81 86 #user admin
82 87 get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
83 88 post 'user_admin', to: 'user_admin#create'
84 89 delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
85 90
86 91 #report
87 92 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
88 93 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
89 94 get "report/login"
90 95 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
91 96 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
92 97
93 98
94 99 #
95 100 get 'tasks/view/:file.:ext' => 'tasks#view'
96 101 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
97 102 get 'heartbeat/:id/edit' => 'heartbeat#edit'
98 103
99 104 #grader
100 105 get 'graders/list', to: 'graders#list', as: 'grader_list'
101 106
102 107
103 108 # See how all your routes lay out with "rake routes"
104 109
105 110 # This is a legacy wild controller route that's not recommended for RESTful applications.
106 111 # Note: This route will make all actions in every controller accessible via GET requests.
107 112 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
108 113 end
deleted file
You need to be logged in to leave comments. Login now