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

r753:9918c6e0c313 - - 6 files changed: 15 inserted, 6 deleted

@@ -21,104 +21,104
21 21 @description = nil
22 22 end
23 23
24 24 def create
25 25 @problem = Problem.new(problem_params)
26 26 @description = Description.new(problem_params[:description])
27 27 if @description.body!=''
28 28 if !@description.save
29 29 render :action => new and return
30 30 end
31 31 else
32 32 @description = nil
33 33 end
34 34 @problem.description = @description
35 35 if @problem.save
36 36 flash[:notice] = 'Problem was successfully created.'
37 37 redirect_to action: :index
38 38 else
39 39 render :action => 'new'
40 40 end
41 41 end
42 42
43 43 def quick_create
44 44 @problem = Problem.new(problem_params)
45 45 @problem.full_name = @problem.name if @problem.full_name == ''
46 46 @problem.full_score = 100
47 47 @problem.available = false
48 48 @problem.test_allowed = true
49 49 @problem.output_only = false
50 50 @problem.date_added = Time.new
51 51 if @problem.save
52 52 flash[:notice] = 'Problem was successfully created.'
53 53 redirect_to action: :index
54 54 else
55 55 flash[:notice] = 'Error saving problem'
56 56 redirect_to action: :index
57 57 end
58 58 end
59 59
60 60 def edit
61 61 @problem = Problem.find(params[:id])
62 62 @description = @problem.description
63 63 end
64 64
65 65 def update
66 66 @problem = Problem.find(params[:id])
67 67 @description = @problem.description
68 68 if @description.nil? and params[:description][:body]!=''
69 - @description = Description.new(params[:description])
69 + @description = Description.new(description_params)
70 70 if !@description.save
71 71 flash[:notice] = 'Error saving description'
72 72 render :action => 'edit' and return
73 73 end
74 74 @problem.description = @description
75 75 elsif @description
76 - if !@description.update_attributes(params[:description])
76 + if !@description.update_attributes(description_params)
77 77 flash[:notice] = 'Error saving description'
78 78 render :action => 'edit' and return
79 79 end
80 80 end
81 81 if params[:file] and params[:file].content_type != 'application/pdf'
82 82 flash[:notice] = 'Error: Uploaded file is not PDF'
83 83 render :action => 'edit' and return
84 84 end
85 85 if @problem.update_attributes(problem_params)
86 86 flash[:notice] = 'Problem was successfully updated.'
87 87 unless params[:file] == nil or params[:file] == ''
88 88 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
89 89 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
90 90 if not FileTest.exists? out_dirname
91 91 Dir.mkdir out_dirname
92 92 end
93 93
94 94 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
95 95 if FileTest.exists? out_filename
96 96 File.delete out_filename
97 97 end
98 98
99 99 File.open(out_filename,"wb") do |file|
100 100 file.write(params[:file].read)
101 101 end
102 102 @problem.description_filename = "#{@problem.name}.pdf"
103 103 @problem.save
104 104 end
105 105 redirect_to :action => 'show', :id => @problem
106 106 else
107 107 render :action => 'edit'
108 108 end
109 109 end
110 110
111 111 def destroy
112 112 p = Problem.find(params[:id]).destroy
113 113 redirect_to action: :index
114 114 end
115 115
116 116 def toggle
117 117 @problem = Problem.find(params[:id])
118 118 @problem.update_attributes(available: !(@problem.available) )
119 119 respond_to do |format|
120 120 format.js { }
121 121 end
122 122 end
123 123
124 124 def toggle_test
@@ -256,49 +256,53
256 256
257 257 def change_date_added
258 258 problems = get_problems_from_params
259 259 date = Date.parse(params[:date_added])
260 260 problems.each do |p|
261 261 p.date_added = date
262 262 p.save
263 263 end
264 264 end
265 265
266 266 def add_to_contest
267 267 problems = get_problems_from_params
268 268 contest = Contest.find(params[:contest][:id])
269 269 if contest!=nil and contest.enabled
270 270 problems.each do |p|
271 271 p.contests << contest
272 272 end
273 273 end
274 274 end
275 275
276 276 def set_available(avail)
277 277 problems = get_problems_from_params
278 278 problems.each do |p|
279 279 p.available = avail
280 280 p.save
281 281 end
282 282 end
283 283
284 284 def get_problems_from_params
285 285 problems = []
286 286 params.keys.each do |k|
287 287 if k.index('prob-')==0
288 288 name, id, order = k.split('-')
289 289 problems << Problem.find(id)
290 290 end
291 291 end
292 292 problems
293 293 end
294 294
295 295 def get_problems_stat
296 296 end
297 297
298 298 private
299 299
300 300 def problem_params
301 301 params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
302 302 end
303 303
304 + def description_params
305 + params.require(:description).permit(:body, :markdown)
304 306 end
307 +
308 + end
@@ -1,78 +1,78
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 - has_and_belongs_to_many :contests, -> { order(:name); uniq}
30 + has_and_belongs_to_many :contests, -> { order(:name)}
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 end
73 73 end
74 74
75 75 def authenticated?(password)
76 76 if self.activated
77 77 hashed_password == User.encrypt(password,self.salt)
78 78 else
@@ -128,97 +128,97
128 128 password = ''
129 129 length.times { password << chars[rand(chars.length - 1)] }
130 130 password
131 131 end
132 132
133 133 def self.find_non_admin_with_prefix(prefix='')
134 134 users = User.all
135 135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
136 136 end
137 137
138 138 # Contest information
139 139
140 140 def self.find_users_with_no_contest()
141 141 users = User.all
142 142 return users.find_all { |u| u.contests.length == 0 }
143 143 end
144 144
145 145
146 146 def contest_time_left
147 147 if GraderConfiguration.contest_mode?
148 148 return nil if site==nil
149 149 return site.time_left
150 150 elsif GraderConfiguration.indv_contest_mode?
151 151 time_limit = GraderConfiguration.contest_time_limit
152 152 if time_limit == nil
153 153 return nil
154 154 end
155 155 if contest_stat==nil or contest_stat.started_at==nil
156 156 return (Time.now.gmtime + time_limit) - Time.now.gmtime
157 157 else
158 158 finish_time = contest_stat.started_at + time_limit
159 159 current_time = Time.now.gmtime
160 160 if current_time > finish_time
161 161 return 0
162 162 else
163 163 return finish_time - current_time
164 164 end
165 165 end
166 166 else
167 167 return nil
168 168 end
169 169 end
170 170
171 171 def contest_finished?
172 172 if GraderConfiguration.contest_mode?
173 173 return false if site==nil
174 174 return site.finished?
175 175 elsif GraderConfiguration.indv_contest_mode?
176 - return false if self.contest_stat(true)==nil
176 + return false if self.contest_stat==nil
177 177 return contest_time_left == 0
178 178 else
179 179 return false
180 180 end
181 181 end
182 182
183 183 def contest_started?
184 184 if GraderConfiguration.indv_contest_mode?
185 185 stat = self.contest_stat
186 186 return ((stat != nil) and (stat.started_at != nil))
187 187 elsif GraderConfiguration.contest_mode?
188 188 return true if site==nil
189 189 return site.started
190 190 else
191 191 return true
192 192 end
193 193 end
194 194
195 195 def update_start_time
196 196 stat = self.contest_stat
197 197 if stat.nil? or stat.started_at.nil?
198 198 stat ||= UserContestStat.new(:user => self)
199 199 stat.started_at = Time.now.gmtime
200 200 stat.save
201 201 end
202 202 end
203 203
204 204 def problem_in_user_contests?(problem)
205 205 problem_contests = problem.contests.all
206 206
207 207 if problem_contests.length == 0 # this is public contest
208 208 return true
209 209 end
210 210
211 211 contests.each do |contest|
212 212 if problem_contests.find {|c| c.id == contest.id }
213 213 return true
214 214 end
215 215 end
216 216 return false
217 217 end
218 218
219 219 def available_problems_group_by_contests
220 220 contest_problems = []
221 221 pin = {}
222 222 contests.enabled.each do |contest|
223 223 available_problems = contest.problems.available
224 224 contest_problems << {
@@ -1,59 +1,60
1 1 - content_for :head do
2 2 = stylesheet_link_tag 'problems'
3 3
4 4 %h1 Import problems
5 5
6 6 %p= link_to '[Back to problem list]', problems_path
7 7
8 8 - if @problem and @problem.errors
9 9 =error_messages_for 'problem'
10 10
11 - = form_tag({:action => 'do_import'}, :multipart => true) do
11 + = simple_form_for :problem, url: do_import_problems_path, :multipart => true do |f|
12 +
12 13 .submitbox
13 14 %table
14 15 %tr
15 16 %td Name:
16 17 %td= text_field_tag 'name'
17 18 %tr
18 19 %td Full name:
19 20 %td
20 21 = text_field_tag 'full_name'
21 22 %span{:class => 'help'} Leave blank to use the same value as the name above.
22 23 %tr
23 24 %td Testdata file:
24 25 %td= file_field_tag 'file'
25 26 %tr
26 27 %td
27 28 %td
28 29 %span{:class => 'help'}
29 30 In .zip, .tgz, tar.gz, .tar format.
30 31 It should includes inputs (e.g., 1.in, 2a.in, 2b.in)
31 32 and solutions (e.g., 1.sol, 2a.sol, 2b.sol).
32 33 %br/
33 34 You may put task description in *.html for raw html
34 35 and *.md or *.markdown for markdown.
35 36 %br/
36 37 You may also put a pdf file for the task description
37 38 %tr
38 39 %td Checker:
39 40 %td= select_tag 'checker', options_for_select([['Text checker','text'],['Float checker','float']], 'text')
40 41 %tr
41 42 %td
42 43 %td
43 44 %span{:class => 'help'}
44 45 "Text" checker checks if the text (including numbers) is the same, ignoring any whitespace
45 46 %br/
46 47 "Float" checker checks if all numbers is within EPSILON error using formula |a-b| < EPSILON * max(|a|,|b|)
47 48
48 49 - if @allow_test_pair_import
49 50 %tr
50 51 %td
51 52 %td
52 53 = check_box_tag 'import_to_db'
53 54 Import test data to database (for a test-pair task)
54 55 %tr
55 56 %td Time limit:
56 57 %td
57 58 = text_field_tag 'time_limit'
58 59 %span{:class => 'help'} In seconds. Leave blank to use 1 sec.
59 60 %tr
@@ -1,49 +1,49
1 1 %h1 Maximum score
2 2
3 - = form_tag report_show_max_score_path
3 + = form_tag show_max_score_report_path
4 4 .row
5 5 .col-md-4
6 6 .panel.panel-primary
7 7 .panel-heading
8 8 Problems
9 9 .panel-body
10 10 %p
11 11 Select problem(s) that we wish to know the score.
12 12 = label_tag :problem_id, "Problems"
13 13 = select_tag 'problem_id[]',
14 14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
15 15 { class: 'select2 form-control', multiple: "true" }
16 16 .col-md-4
17 17 .panel.panel-primary
18 18 .panel-heading
19 19 Submission range
20 20 .panel-body
21 21 %p
22 22 Input minimum and maximum range of submission ID that should be included. A blank value for min and max means -1 and infinity, respectively.
23 23 .form-group
24 24 = label_tag :from, "Min"
25 25 = text_field_tag 'from_id', @since_id, class: "form-control"
26 26 .form-group
27 27 = label_tag :from, "Max"
28 28 = text_field_tag 'to_id', @until_id, class: "form-control"
29 29 .col-md-4
30 30 .panel.panel-primary
31 31 .panel-heading
32 32 Users
33 33 .panel-body
34 34 .radio
35 35 %label
36 36 = radio_button_tag 'users', 'all', (params[:users] == "all")
37 37 All users
38 38 .radio
39 39 %label
40 40 = radio_button_tag 'users', 'enabled', (params[:users] == "enabled")
41 41 Only enabled users
42 42 .row
43 43 .col-md-12
44 44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
45 45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
46 46
47 47 - if @scorearray
48 48 %h2 Result
49 49 =render "score_table"
@@ -6,96 +6,97
6 6 .row
7 7 .col-md-12
8 8 .alert.alert-info
9 9 Write your code in the following box, choose language, and click submit button when finished
10 10 .row
11 11 .col-md-8
12 12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 13 .col-md-4
14 14 - # submission form
15 15 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
16 16
17 17 = hidden_field_tag 'editor_text', @source
18 18 = hidden_field_tag 'submission[problem_id]', @problem.id
19 19 .form-group
20 20 = label_tag "Task:"
21 21 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
22 22 .form-group
23 23 = label_tag "Description:"
24 24 = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
25 25
26 26 .form-group
27 27 = label_tag 'Language:'
28 28 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
29 29 .form-group
30 30 .input-group
31 31 %span.input-group-btn
32 32 %span.btn.btn-default.btn-file
33 33 Browse
34 34 = file_field_tag 'load_file'
35 35 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
36 36 .form-group
37 37 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
38 38 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
39 39 - # latest submission status
40 40 .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
41 41 .panel-heading
42 42 Latest Submission Status
43 43 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
44 44 .panel-body
45 45 %div#latest_status
46 46 - if @submission
47 47 = render :partial => 'submission_short',
48 48 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
49 49 .row
50 50 .col-md-12
51 51 %h2 Console
52 52 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
53 53
54 + - if @submission
54 55 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
55 56 .modal-dialog.modal-lg{role:'document'}
56 57 .modal-content
57 58 .modal-header
58 59 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
59 60 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
60 61 %h4 Compiler message
61 62 .modal-body
62 63 %pre#compiler_msg= @submission.compiler_message
63 64 .modal-footer
64 65 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
65 66
66 67 :javascript
67 68 $(document).ready(function() {
68 69 e = ace.edit("editor")
69 70 e.setValue($("#text_sourcecode").val());
70 71 e.gotoLine(1);
71 72 $("#language_id").trigger('change');
72 73
73 74 $("#load_file").on('change',function(evt) {
74 75 var file = evt.target.files[0];
75 76 var reader = new FileReader();
76 77 reader.onload = function(theFile) {
77 78 var e = ace.edit("editor")
78 79 e.setValue(theFile.target.result);
79 80 e.gotoLine(1);
80 81 };
81 82 reader.readAsText(file)
82 83 });
83 84
84 85 //brython();
85 86 });
86 87
87 88
88 89
89 90
90 91
91 92 %script#__main__{type:'text/python3'}
92 93 :plain
93 94 import sys
94 95 import traceback
95 96
96 97 from browser import document as doc
97 98 from browser import window, alert, console
98 99
99 100 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
100 101 for supporting Python development. See www.python.org for more information."""
101 102
@@ -1,165 +1,168
1 1 Rails.application.routes.draw do
2 2 resources :tags
3 3 get "sources/direct_edit"
4 4
5 5 root :to => 'main#login'
6 6
7 7 #logins
8 8 match 'login/login', to: 'login#login', via: [:get,:post]
9 9
10 10
11 11 resources :contests
12 12
13 13 resources :sites
14 14
15 15 resources :test
16 16
17 17 resources :messages do
18 18 collection do
19 19 get 'console'
20 20 end
21 21 end
22 22
23 23 resources :announcements do
24 24 member do
25 25 get 'toggle','toggle_front'
26 26 end
27 27 end
28 28
29 29 resources :problems do
30 30 member do
31 31 get 'toggle'
32 32 get 'toggle_test'
33 33 get 'toggle_view_testcase'
34 34 get 'stat'
35 35 end
36 36 collection do
37 37 get 'turn_all_off'
38 38 get 'turn_all_on'
39 39 get 'import'
40 40 get 'manage'
41 41 get 'quick_create'
42 42 post 'do_manage'
43 + post 'do_import'
43 44 end
44 45 end
45 46
46 47 resources :groups do
47 48 member do
48 49 post 'add_user', to: 'groups#add_user', as: 'add_user'
49 50 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
50 51 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
51 52 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
52 53 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
53 54 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
54 55 end
55 56 collection do
56 57
57 58 end
58 59 end
59 60
60 61 resources :testcases, only: [] do
61 62 member do
62 63 get 'download_input'
63 64 get 'download_sol'
64 65 end
65 66 collection do
66 67 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
67 68 end
68 69 end
69 70
70 71 resources :grader_configuration, controller: 'configurations'
71 72
72 73 resources :users do
73 74 member do
74 75 get 'toggle_activate', 'toggle_enable'
75 76 get 'stat'
76 77 end
77 78 end
78 79
79 80 resources :submissions do
80 81 member do
81 82 get 'download'
82 83 get 'compiler_msg'
83 84 get 'rejudge'
85 + get 'source'
84 86 end
85 87 collection do
86 88 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
87 89 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
88 90 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
89 91 end
90 92 end
91 93
92 94
93 95 #user admin
94 96 resources :user_admin do
95 97 collection do
96 98 match 'bulk_manage', via: [:get, :post]
97 99 get 'bulk_mail'
98 100 get 'user_stat'
99 101 get 'import'
100 102 get 'new_list'
101 103 get 'admin'
102 104 get 'active'
103 105 get 'mass_mailing'
104 106 post 'grant_admin'
105 107 match 'create_from_list', via: [:get, :post]
106 108 match 'random_all_passwords', via: [:get, :post]
107 109 end
108 110 member do
109 111 get 'clear_last_ip'
110 112 end
111 113 end
112 114
113 115 resources :contest_management, only: [:index] do
114 116 collection do
115 117 get 'user_stat'
116 118 get 'clear_stat'
117 119 get 'clear_all_stat'
120 + get 'change_contest_mode'
118 121 end
119 122 end
120 123
121 124 #get 'user_admin', to: 'user_admin#index'
122 125 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
123 126 #post 'user_admin', to: 'user_admin#create'
124 127 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
125 128
126 129 #singular resource
127 130 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
128 131 #report
129 132 resource :report, only: [], controller: 'report' do
130 133 get 'login'
131 134 get 'multiple_login'
132 135 get 'problem_hof/:id', action: 'problem_hof'
133 136 get 'current_score'
134 137 get 'max_score'
135 138 post 'show_max_score'
136 139 end
137 140 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
138 141 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
139 142 #get "report/login"
140 143 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
141 144 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
142 145
143 146 resource :main, only: [], controller: 'main' do
144 147 get 'list'
145 148 get 'submission(/:id)', action: 'submission', as: 'main_submission'
146 149 post 'submit'
147 150 get 'announcements'
148 151 get 'help'
149 152 end
150 153 #main
151 154 #get "main/list"
152 155 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
153 156 #post 'main/submit', to: 'main#submit'
154 157 #get 'main/announcements', to: 'main#announcements'
155 158
156 159
157 160 #
158 161 get 'tasks/view/:file.:ext' => 'tasks#view'
159 162 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
160 163 get 'heartbeat/:id/edit' => 'heartbeat#edit'
161 164
162 165 #grader
163 166 get 'graders/list', to: 'graders#list', as: 'grader_list'
164 167
165 168
You need to be logged in to leave comments. Login now