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

r879:60919c3675f4 - - 13 files changed: 87 inserted, 104 deleted

@@ -5,332 +5,336
5 specs:
5 specs:
6 simple_form (5.1.0)
6 simple_form (5.1.0)
7 actionpack (>= 5.2)
7 actionpack (>= 5.2)
8 activemodel (>= 5.2)
8 activemodel (>= 5.2)
9
9
10 GIT
10 GIT
11 remote: https://github.com/mmotherwell/best_in_place
11 remote: https://github.com/mmotherwell/best_in_place
12 revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0
12 revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0
13 specs:
13 specs:
14 best_in_place (3.1.1)
14 best_in_place (3.1.1)
15 actionpack (>= 3.2)
15 actionpack (>= 3.2)
16 railties (>= 3.2)
16 railties (>= 3.2)
17
17
18 GEM
18 GEM
19 remote: https://rubygems.org/
19 remote: https://rubygems.org/
20 specs:
20 specs:
21 RubyInline (3.12.6)
21 RubyInline (3.12.6)
22 ZenTest (~> 4.3)
22 ZenTest (~> 4.3)
23 ZenTest (4.12.1)
23 ZenTest (4.12.1)
24 ace-rails-ap (4.4)
24 ace-rails-ap (4.4)
25 actioncable (7.0.4)
25 actioncable (7.0.4)
26 actionpack (= 7.0.4)
26 actionpack (= 7.0.4)
27 activesupport (= 7.0.4)
27 activesupport (= 7.0.4)
28 nio4r (~> 2.0)
28 nio4r (~> 2.0)
29 websocket-driver (>= 0.6.1)
29 websocket-driver (>= 0.6.1)
30 actionmailbox (7.0.4)
30 actionmailbox (7.0.4)
31 actionpack (= 7.0.4)
31 actionpack (= 7.0.4)
32 activejob (= 7.0.4)
32 activejob (= 7.0.4)
33 activerecord (= 7.0.4)
33 activerecord (= 7.0.4)
34 activestorage (= 7.0.4)
34 activestorage (= 7.0.4)
35 activesupport (= 7.0.4)
35 activesupport (= 7.0.4)
36 mail (>= 2.7.1)
36 mail (>= 2.7.1)
37 net-imap
37 net-imap
38 net-pop
38 net-pop
39 net-smtp
39 net-smtp
40 actionmailer (7.0.4)
40 actionmailer (7.0.4)
41 actionpack (= 7.0.4)
41 actionpack (= 7.0.4)
42 actionview (= 7.0.4)
42 actionview (= 7.0.4)
43 activejob (= 7.0.4)
43 activejob (= 7.0.4)
44 activesupport (= 7.0.4)
44 activesupport (= 7.0.4)
45 mail (~> 2.5, >= 2.5.4)
45 mail (~> 2.5, >= 2.5.4)
46 net-imap
46 net-imap
47 net-pop
47 net-pop
48 net-smtp
48 net-smtp
49 rails-dom-testing (~> 2.0)
49 rails-dom-testing (~> 2.0)
50 actionpack (7.0.4)
50 actionpack (7.0.4)
51 actionview (= 7.0.4)
51 actionview (= 7.0.4)
52 activesupport (= 7.0.4)
52 activesupport (= 7.0.4)
53 rack (~> 2.0, >= 2.2.0)
53 rack (~> 2.0, >= 2.2.0)
54 rack-test (>= 0.6.3)
54 rack-test (>= 0.6.3)
55 rails-dom-testing (~> 2.0)
55 rails-dom-testing (~> 2.0)
56 rails-html-sanitizer (~> 1.0, >= 1.2.0)
56 rails-html-sanitizer (~> 1.0, >= 1.2.0)
57 actiontext (7.0.4)
57 actiontext (7.0.4)
58 actionpack (= 7.0.4)
58 actionpack (= 7.0.4)
59 activerecord (= 7.0.4)
59 activerecord (= 7.0.4)
60 activestorage (= 7.0.4)
60 activestorage (= 7.0.4)
61 activesupport (= 7.0.4)
61 activesupport (= 7.0.4)
62 globalid (>= 0.6.0)
62 globalid (>= 0.6.0)
63 nokogiri (>= 1.8.5)
63 nokogiri (>= 1.8.5)
64 actionview (7.0.4)
64 actionview (7.0.4)
65 activesupport (= 7.0.4)
65 activesupport (= 7.0.4)
66 builder (~> 3.1)
66 builder (~> 3.1)
67 erubi (~> 1.4)
67 erubi (~> 1.4)
68 rails-dom-testing (~> 2.0)
68 rails-dom-testing (~> 2.0)
69 rails-html-sanitizer (~> 1.1, >= 1.2.0)
69 rails-html-sanitizer (~> 1.1, >= 1.2.0)
70 activejob (7.0.4)
70 activejob (7.0.4)
71 activesupport (= 7.0.4)
71 activesupport (= 7.0.4)
72 globalid (>= 0.3.6)
72 globalid (>= 0.3.6)
73 activemodel (7.0.4)
73 activemodel (7.0.4)
74 activesupport (= 7.0.4)
74 activesupport (= 7.0.4)
75 activerecord (7.0.4)
75 activerecord (7.0.4)
76 activemodel (= 7.0.4)
76 activemodel (= 7.0.4)
77 activesupport (= 7.0.4)
77 activesupport (= 7.0.4)
78 activestorage (7.0.4)
78 activestorage (7.0.4)
79 actionpack (= 7.0.4)
79 actionpack (= 7.0.4)
80 activejob (= 7.0.4)
80 activejob (= 7.0.4)
81 activerecord (= 7.0.4)
81 activerecord (= 7.0.4)
82 activesupport (= 7.0.4)
82 activesupport (= 7.0.4)
83 marcel (~> 1.0)
83 marcel (~> 1.0)
84 mini_mime (>= 1.1.0)
84 mini_mime (>= 1.1.0)
85 activesupport (7.0.4)
85 activesupport (7.0.4)
86 concurrent-ruby (~> 1.0, >= 1.0.2)
86 concurrent-ruby (~> 1.0, >= 1.0.2)
87 i18n (>= 1.6, < 2)
87 i18n (>= 1.6, < 2)
88 minitest (>= 5.1)
88 minitest (>= 5.1)
89 tzinfo (~> 2.0)
89 tzinfo (~> 2.0)
90 addressable (2.8.1)
90 addressable (2.8.1)
91 public_suffix (>= 2.0.2, < 6.0)
91 public_suffix (>= 2.0.2, < 6.0)
92 ansi (1.5.0)
92 ansi (1.5.0)
93 autoprefixer-rails (10.4.7.0)
93 autoprefixer-rails (10.4.7.0)
94 execjs (~> 2)
94 execjs (~> 2)
95 bindex (0.8.1)
95 bindex (0.8.1)
96 bootsnap (1.13.0)
96 bootsnap (1.13.0)
97 msgpack (~> 1.2)
97 msgpack (~> 1.2)
98 bootstrap (5.2.1)
98 bootstrap (5.2.1)
99 autoprefixer-rails (>= 9.1.0)
99 autoprefixer-rails (>= 9.1.0)
100 popper_js (>= 2.11.6, < 3)
100 popper_js (>= 2.11.6, < 3)
101 sassc-rails (>= 2.0.0)
101 sassc-rails (>= 2.0.0)
102 builder (3.2.4)
102 builder (3.2.4)
103 byebug (11.1.3)
103 byebug (11.1.3)
104 capybara (3.37.1)
104 capybara (3.37.1)
105 addressable
105 addressable
106 matrix
106 matrix
107 mini_mime (>= 0.1.3)
107 mini_mime (>= 0.1.3)
108 nokogiri (~> 1.8)
108 nokogiri (~> 1.8)
109 rack (>= 1.6.0)
109 rack (>= 1.6.0)
110 rack-test (>= 0.6.3)
110 rack-test (>= 0.6.3)
111 regexp_parser (>= 1.5, < 3.0)
111 regexp_parser (>= 1.5, < 3.0)
112 xpath (~> 3.2)
112 xpath (~> 3.2)
113 childprocess (4.1.0)
113 childprocess (4.1.0)
114 coffee-rails (5.0.0)
114 coffee-rails (5.0.0)
115 coffee-script (>= 2.2.0)
115 coffee-script (>= 2.2.0)
116 railties (>= 5.2.0)
116 railties (>= 5.2.0)
117 coffee-script (2.4.1)
117 coffee-script (2.4.1)
118 coffee-script-source
118 coffee-script-source
119 execjs
119 execjs
120 coffee-script-source (1.12.2)
120 coffee-script-source (1.12.2)
121 concurrent-ruby (1.1.10)
121 concurrent-ruby (1.1.10)
122 crass (1.0.6)
122 crass (1.0.6)
123 digest (3.1.0)
123 digest (3.1.0)
124 erubi (1.11.0)
124 erubi (1.11.0)
125 erubis (2.7.0)
125 erubis (2.7.0)
126 execjs (2.8.1)
126 execjs (2.8.1)
127 ffi (1.15.5)
127 ffi (1.15.5)
128 fuzzy-string-match (1.0.1)
128 fuzzy-string-match (1.0.1)
129 RubyInline (>= 3.8.6)
129 RubyInline (>= 3.8.6)
130 globalid (1.0.0)
130 globalid (1.0.0)
131 activesupport (>= 5.0)
131 activesupport (>= 5.0)
132 haml (5.2.2)
132 haml (5.2.2)
133 temple (>= 0.8.0)
133 temple (>= 0.8.0)
134 tilt
134 tilt
135 haml-rails (2.0.1)
135 haml-rails (2.0.1)
136 actionpack (>= 5.1)
136 actionpack (>= 5.1)
137 activesupport (>= 5.1)
137 activesupport (>= 5.1)
138 haml (>= 4.0.6, < 6.0)
138 haml (>= 4.0.6, < 6.0)
139 html2haml (>= 1.0.1)
139 html2haml (>= 1.0.1)
140 railties (>= 5.1)
140 railties (>= 5.1)
141 html2haml (2.2.0)
141 html2haml (2.2.0)
142 erubis (~> 2.7.0)
142 erubis (~> 2.7.0)
143 haml (>= 4.0, < 6)
143 haml (>= 4.0, < 6)
144 nokogiri (>= 1.6.0)
144 nokogiri (>= 1.6.0)
145 ruby_parser (~> 3.5)
145 ruby_parser (~> 3.5)
146 i18n (1.12.0)
146 i18n (1.12.0)
147 concurrent-ruby (~> 1.0)
147 concurrent-ruby (~> 1.0)
148 importmap-rails (1.1.5)
148 importmap-rails (1.1.5)
149 actionpack (>= 6.0.0)
149 actionpack (>= 6.0.0)
150 railties (>= 6.0.0)
150 railties (>= 6.0.0)
151 jbuilder (2.11.5)
151 jbuilder (2.11.5)
152 actionview (>= 5.0.0)
152 actionview (>= 5.0.0)
153 activesupport (>= 5.0.0)
153 activesupport (>= 5.0.0)
154 jquery-rails (4.5.0)
154 jquery-rails (4.5.0)
155 rails-dom-testing (>= 1, < 3)
155 rails-dom-testing (>= 1, < 3)
156 railties (>= 4.2.0)
156 railties (>= 4.2.0)
157 thor (>= 0.14, < 2.0)
157 thor (>= 0.14, < 2.0)
158 listen (3.0.8)
158 listen (3.0.8)
159 rb-fsevent (~> 0.9, >= 0.9.4)
159 rb-fsevent (~> 0.9, >= 0.9.4)
160 rb-inotify (~> 0.9, >= 0.9.7)
160 rb-inotify (~> 0.9, >= 0.9.7)
161 loofah (2.19.0)
161 loofah (2.19.0)
162 crass (~> 1.0.2)
162 crass (~> 1.0.2)
163 nokogiri (>= 1.5.9)
163 nokogiri (>= 1.5.9)
164 mail (2.7.1)
164 mail (2.7.1)
165 mini_mime (>= 0.1.1)
165 mini_mime (>= 0.1.1)
166 marcel (1.0.2)
166 marcel (1.0.2)
167 material_icons (2.2.1)
167 material_icons (2.2.1)
168 railties (>= 3.2)
168 railties (>= 3.2)
169 matrix (0.4.2)
169 matrix (0.4.2)
170 method_source (1.0.0)
170 method_source (1.0.0)
171 mini_mime (1.1.2)
171 mini_mime (1.1.2)
172 minitest (5.16.3)
172 minitest (5.16.3)
173 minitest-reporters (1.5.0)
173 minitest-reporters (1.5.0)
174 ansi
174 ansi
175 builder
175 builder
176 minitest (>= 5.0)
176 minitest (>= 5.0)
177 ruby-progressbar
177 ruby-progressbar
178 momentjs-rails (2.29.4.1)
178 momentjs-rails (2.29.4.1)
179 railties (>= 3.1)
179 railties (>= 3.1)
180 msgpack (1.5.6)
180 msgpack (1.5.6)
181 mysql2 (0.5.4)
181 mysql2 (0.5.4)
182 net-imap (0.2.3)
182 net-imap (0.2.3)
183 digest
183 digest
184 net-protocol
184 net-protocol
185 strscan
185 strscan
186 net-pop (0.1.1)
186 net-pop (0.1.1)
187 digest
187 digest
188 net-protocol
188 net-protocol
189 timeout
189 timeout
190 net-protocol (0.1.3)
190 net-protocol (0.1.3)
191 timeout
191 timeout
192 net-smtp (0.3.1)
192 net-smtp (0.3.1)
193 digest
193 digest
194 net-protocol
194 net-protocol
195 timeout
195 timeout
196 nio4r (2.5.8)
196 nio4r (2.5.8)
197 + nokogiri (1.13.8-x86_64-darwin)
198 + racc (~> 1.4)
197 nokogiri (1.13.8-x86_64-linux)
199 nokogiri (1.13.8-x86_64-linux)
198 racc (~> 1.4)
200 racc (~> 1.4)
199 popper_js (2.11.6)
201 popper_js (2.11.6)
200 public_suffix (5.0.0)
202 public_suffix (5.0.0)
201 puma (5.6.5)
203 puma (5.6.5)
202 nio4r (~> 2.0)
204 nio4r (~> 2.0)
203 racc (1.6.0)
205 racc (1.6.0)
204 rack (2.2.4)
206 rack (2.2.4)
205 rack-test (2.0.2)
207 rack-test (2.0.2)
206 rack (>= 1.3)
208 rack (>= 1.3)
207 rails (7.0.4)
209 rails (7.0.4)
208 actioncable (= 7.0.4)
210 actioncable (= 7.0.4)
209 actionmailbox (= 7.0.4)
211 actionmailbox (= 7.0.4)
210 actionmailer (= 7.0.4)
212 actionmailer (= 7.0.4)
211 actionpack (= 7.0.4)
213 actionpack (= 7.0.4)
212 actiontext (= 7.0.4)
214 actiontext (= 7.0.4)
213 actionview (= 7.0.4)
215 actionview (= 7.0.4)
214 activejob (= 7.0.4)
216 activejob (= 7.0.4)
215 activemodel (= 7.0.4)
217 activemodel (= 7.0.4)
216 activerecord (= 7.0.4)
218 activerecord (= 7.0.4)
217 activestorage (= 7.0.4)
219 activestorage (= 7.0.4)
218 activesupport (= 7.0.4)
220 activesupport (= 7.0.4)
219 bundler (>= 1.15.0)
221 bundler (>= 1.15.0)
220 railties (= 7.0.4)
222 railties (= 7.0.4)
221 rails-dom-testing (2.0.3)
223 rails-dom-testing (2.0.3)
222 activesupport (>= 4.2.0)
224 activesupport (>= 4.2.0)
223 nokogiri (>= 1.6)
225 nokogiri (>= 1.6)
224 rails-html-sanitizer (1.4.3)
226 rails-html-sanitizer (1.4.3)
225 loofah (~> 2.3)
227 loofah (~> 2.3)
226 railties (7.0.4)
228 railties (7.0.4)
227 actionpack (= 7.0.4)
229 actionpack (= 7.0.4)
228 activesupport (= 7.0.4)
230 activesupport (= 7.0.4)
229 method_source
231 method_source
230 rake (>= 12.2)
232 rake (>= 12.2)
231 thor (~> 1.0)
233 thor (~> 1.0)
232 zeitwerk (~> 2.5)
234 zeitwerk (~> 2.5)
233 rake (13.0.6)
235 rake (13.0.6)
234 rb-fsevent (0.11.2)
236 rb-fsevent (0.11.2)
235 rb-inotify (0.10.1)
237 rb-inotify (0.10.1)
236 ffi (~> 1.0)
238 ffi (~> 1.0)
237 rdiscount (2.2.0.2)
239 rdiscount (2.2.0.2)
238 regexp_parser (2.5.0)
240 regexp_parser (2.5.0)
239 rexml (3.2.5)
241 rexml (3.2.5)
240 rouge (4.0.0)
242 rouge (4.0.0)
241 ruby-progressbar (1.11.0)
243 ruby-progressbar (1.11.0)
242 ruby_parser (3.19.1)
244 ruby_parser (3.19.1)
243 sexp_processor (~> 4.16)
245 sexp_processor (~> 4.16)
244 rubyzip (2.3.2)
246 rubyzip (2.3.2)
245 sassc (2.4.0)
247 sassc (2.4.0)
246 ffi (~> 1.9)
248 ffi (~> 1.9)
247 sassc-rails (2.1.2)
249 sassc-rails (2.1.2)
248 railties (>= 4.0.0)
250 railties (>= 4.0.0)
249 sassc (>= 2.0)
251 sassc (>= 2.0)
250 sprockets (> 3.0)
252 sprockets (> 3.0)
251 sprockets-rails
253 sprockets-rails
252 tilt
254 tilt
253 selenium-webdriver (4.4.0)
255 selenium-webdriver (4.4.0)
254 childprocess (>= 0.5, < 5.0)
256 childprocess (>= 0.5, < 5.0)
255 rexml (~> 3.2, >= 3.2.5)
257 rexml (~> 3.2, >= 3.2.5)
256 rubyzip (>= 1.2.2, < 3.0)
258 rubyzip (>= 1.2.2, < 3.0)
257 websocket (~> 1.0)
259 websocket (~> 1.0)
258 sexp_processor (4.16.1)
260 sexp_processor (4.16.1)
259 spring (2.1.1)
261 spring (2.1.1)
260 spring-watcher-listen (2.0.1)
262 spring-watcher-listen (2.0.1)
261 listen (>= 2.7, < 4.0)
263 listen (>= 2.7, < 4.0)
262 spring (>= 1.2, < 3.0)
264 spring (>= 1.2, < 3.0)
263 sprockets (4.1.1)
265 sprockets (4.1.1)
264 concurrent-ruby (~> 1.0)
266 concurrent-ruby (~> 1.0)
265 rack (> 1, < 3)
267 rack (> 1, < 3)
266 sprockets-rails (3.4.2)
268 sprockets-rails (3.4.2)
267 actionpack (>= 5.2)
269 actionpack (>= 5.2)
268 activesupport (>= 5.2)
270 activesupport (>= 5.2)
269 sprockets (>= 3.0.0)
271 sprockets (>= 3.0.0)
272 + sqlite3 (1.5.0-x86_64-darwin)
270 sqlite3 (1.5.0-x86_64-linux)
273 sqlite3 (1.5.0-x86_64-linux)
271 strscan (3.0.4)
274 strscan (3.0.4)
272 temple (0.8.2)
275 temple (0.8.2)
273 thor (1.2.1)
276 thor (1.2.1)
274 tilt (2.0.11)
277 tilt (2.0.11)
275 timeout (0.3.0)
278 timeout (0.3.0)
276 tzinfo (2.0.5)
279 tzinfo (2.0.5)
277 concurrent-ruby (~> 1.0)
280 concurrent-ruby (~> 1.0)
278 web-console (4.2.0)
281 web-console (4.2.0)
279 actionview (>= 6.0.0)
282 actionview (>= 6.0.0)
280 activemodel (>= 6.0.0)
283 activemodel (>= 6.0.0)
281 bindex (>= 0.4.0)
284 bindex (>= 0.4.0)
282 railties (>= 6.0.0)
285 railties (>= 6.0.0)
283 webdrivers (5.1.0)
286 webdrivers (5.1.0)
284 nokogiri (~> 1.6)
287 nokogiri (~> 1.6)
285 rubyzip (>= 1.3.0)
288 rubyzip (>= 1.3.0)
286 selenium-webdriver (~> 4.0)
289 selenium-webdriver (~> 4.0)
287 websocket (1.2.9)
290 websocket (1.2.9)
288 websocket-driver (0.7.5)
291 websocket-driver (0.7.5)
289 websocket-extensions (>= 0.1.0)
292 websocket-extensions (>= 0.1.0)
290 websocket-extensions (0.1.5)
293 websocket-extensions (0.1.5)
291 xpath (3.2.0)
294 xpath (3.2.0)
292 nokogiri (~> 1.8)
295 nokogiri (~> 1.8)
293 zeitwerk (2.6.0)
296 zeitwerk (2.6.0)
294
297
295 PLATFORMS
298 PLATFORMS
299 + x86_64-darwin-20
296 x86_64-linux
300 x86_64-linux
297
301
298 DEPENDENCIES
302 DEPENDENCIES
299 ace-rails-ap
303 ace-rails-ap
300 best_in_place!
304 best_in_place!
301 bootsnap
305 bootsnap
302 bootstrap (~> 5.2)
306 bootstrap (~> 5.2)
303 byebug
307 byebug
304 capybara
308 capybara
305 coffee-rails
309 coffee-rails
306 fuzzy-string-match
310 fuzzy-string-match
307 haml
311 haml
308 haml-rails
312 haml-rails
309 importmap-rails (~> 1.1)
313 importmap-rails (~> 1.1)
310 jbuilder
314 jbuilder
311 jquery-rails
315 jquery-rails
312 listen (>= 3.0.5, < 3.2)
316 listen (>= 3.0.5, < 3.2)
313 mail
317 mail
314 material_icons
318 material_icons
315 minitest-reporters
319 minitest-reporters
316 momentjs-rails
320 momentjs-rails
317 mysql2
321 mysql2
318 puma
322 puma
319 rails (~> 7.0)
323 rails (~> 7.0)
320 rdiscount
324 rdiscount
321 rouge
325 rouge
322 sassc-rails
326 sassc-rails
323 selenium-webdriver
327 selenium-webdriver
324 simple_form!
328 simple_form!
325 spring
329 spring
326 spring-watcher-listen (~> 2.0.0)
330 spring-watcher-listen (~> 2.0.0)
327 sprockets-rails
331 sprockets-rails
328 sqlite3
332 sqlite3
329 web-console (>= 3.3.0)
333 web-console (>= 3.3.0)
330 webdrivers
334 webdrivers
331
335
332 RUBY VERSION
336 RUBY VERSION
333 ruby 3.1.2p20
337 ruby 3.1.2p20
334
338
335 BUNDLED WITH
339 BUNDLED WITH
336 2.3.22
340 2.3.22
@@ -1,264 +1,251
1 require 'ipaddr'
1 require 'ipaddr'
2 require "securerandom"
2 require "securerandom"
3
3
4 class ApplicationController < ActionController::Base
4 class ApplicationController < ActionController::Base
5 protect_from_forgery
5 protect_from_forgery
6
6
7 before_action :current_user
7 before_action :current_user
8 before_action :nav_announcement
8 before_action :nav_announcement
9 before_action :unique_visitor_id
9 before_action :unique_visitor_id
10 before_action :active_controller_action
10 before_action :active_controller_action
11
11
12 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
12 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
13 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
13 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
14 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
14 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
15 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
15 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
16
16
17 #report and redirect for unauthorized activities
17 #report and redirect for unauthorized activities
18 - def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
18 + def unauthorized_redirect(msg = 'You are not authorized to view the page you requested')
19 - flash[:notice] = notice
19 + redirect_to login_main_path, alert: msg
20 - redirect_to login_main_path
21 end
20 end
22
21
23 # Returns the current logged-in user (if any).
22 # Returns the current logged-in user (if any).
24 def current_user
23 def current_user
25 return nil unless session[:user_id]
24 return nil unless session[:user_id]
26 @current_user ||= User.find(session[:user_id])
25 @current_user ||= User.find(session[:user_id])
27 end
26 end
28
27
29 def nav_announcement
28 def nav_announcement
30 @nav_announcement = Announcement.where(on_nav_bar: true)
29 @nav_announcement = Announcement.where(on_nav_bar: true)
31 end
30 end
32
31
33 def active_controller_action
32 def active_controller_action
34 #so that we can override this value inside each action
33 #so that we can override this value inside each action
35 @active_controller = controller_name
34 @active_controller = controller_name
36 @active_action = action_name
35 @active_action = action_name
37 end
36 end
38
37
39 def admin_authorization
38 def admin_authorization
40 return false unless check_valid_login
39 return false unless check_valid_login
41 user = User.includes(:roles).find(session[:user_id])
40 user = User.includes(:roles).find(session[:user_id])
42 unless user.admin?
41 unless user.admin?
43 unauthorized_redirect
42 unauthorized_redirect
44 return false
43 return false
45 end
44 end
46 return true
45 return true
47 end
46 end
48
47
49 - #admin always count as every roles
48 + def authorization_by_roles(allowed_roles)
50 - def role_authorization(roles)
51 return false unless check_valid_login
49 return false unless check_valid_login
52 - user = User.find(session[:user_id])
50 + return true if @current_user.admin?
53 - return true if user.admin?
54 roles.each do |r|
51 roles.each do |r|
55 - return true if user.has_role?(r)
52 + return true if @current_user.has_role?(r)
56 end
53 end
57 unauthorized_redirect
54 unauthorized_redirect
58 end
55 end
59
56
60 - def authorization_by_roles(allowed_roles)
61 - return false unless check_valid_login
62 - unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
63 - unauthorized_redirect
64 - return false
65 - end
66 - end
67 -
68 def testcase_authorization
57 def testcase_authorization
69 #admin always has privileged
58 #admin always has privileged
70 - if @current_user.admin?
59 + return true if @current_user.admin?
71 - return true
72 - end
73
60
74 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
61 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
75 end
62 end
76
63
77 def unique_visitor_id
64 def unique_visitor_id
78 unless cookies.encrypted[:uuid]
65 unless cookies.encrypted[:uuid]
79 value = SecureRandom.uuid
66 value = SecureRandom.uuid
80 cookies.encrypted[:uuid] = { value: value, expires: 20.year }
67 cookies.encrypted[:uuid] = { value: value, expires: 20.year }
81 end
68 end
82 end
69 end
83
70
84 protected
71 protected
85
72
86 #redirect to root (and also force logout)
73 #redirect to root (and also force logout)
87 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
74 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
88 def check_valid_login
75 def check_valid_login
89 #check if logged in
76 #check if logged in
90 unless session[:user_id]
77 unless session[:user_id]
91 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
78 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
92 unauthorized_redirect('You need to login but you cannot log in at this time')
79 unauthorized_redirect('You need to login but you cannot log in at this time')
93 else
80 else
94 unauthorized_redirect('You need to login')
81 unauthorized_redirect('You need to login')
95 end
82 end
96 return false
83 return false
97 end
84 end
98
85
99 # check if run in single user mode
86 # check if run in single user mode
100 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
87 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
101 if @current_user==nil || (!@current_user.admin?)
88 if @current_user==nil || (!@current_user.admin?)
102 unauthorized_redirect('You cannot log in at this time')
89 unauthorized_redirect('You cannot log in at this time')
103 return false
90 return false
104 end
91 end
105 end
92 end
106
93
107 # check if the user is enabled
94 # check if the user is enabled
108 unless @current_user.enabled? || @current_user.admin?
95 unless @current_user.enabled? || @current_user.admin?
109 unauthorized_redirect 'Your account is disabled'
96 unauthorized_redirect 'Your account is disabled'
110 return false
97 return false
111 end
98 end
112
99
113 # check if user ip is allowed
100 # check if user ip is allowed
114 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
101 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
115 unless is_request_ip_allowed?
102 unless is_request_ip_allowed?
116 unauthorized_redirect 'Your IP is not allowed to login at this time.'
103 unauthorized_redirect 'Your IP is not allowed to login at this time.'
117 return false
104 return false
118 end
105 end
119 end
106 end
120
107
121 if GraderConfiguration.multicontests?
108 if GraderConfiguration.multicontests?
122 return true if @current_user.admin?
109 return true if @current_user.admin?
123 begin
110 begin
124 if @current_user.contest_stat(true).forced_logout
111 if @current_user.contest_stat(true).forced_logout
125 flash[:notice] = 'You have been automatically logged out.'
112 flash[:notice] = 'You have been automatically logged out.'
126 redirect_to :controller => 'main', :action => 'index'
113 redirect_to :controller => 'main', :action => 'index'
127 end
114 end
128 rescue
115 rescue
129 end
116 end
130 end
117 end
131 return true
118 return true
132 end
119 end
133
120
134 #redirect to root (and also force logout)
121 #redirect to root (and also force logout)
135 #if the user use different ip from the previous connection
122 #if the user use different ip from the previous connection
136 # only applicable when MULTIPLE_IP_LOGIN options is false only
123 # only applicable when MULTIPLE_IP_LOGIN options is false only
137 def authenticate_by_ip_address
124 def authenticate_by_ip_address
138 #this assume that we have already authenticate normally
125 #this assume that we have already authenticate normally
139 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
126 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
140 user = User.find(session[:user_id])
127 user = User.find(session[:user_id])
141 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
128 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
142 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
129 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
143 redirect_to :controller => 'main', :action => 'login'
130 redirect_to :controller => 'main', :action => 'login'
144 return false
131 return false
145 end
132 end
146 unless user.last_ip
133 unless user.last_ip
147 user.last_ip = request.remote_ip
134 user.last_ip = request.remote_ip
148 user.save
135 user.save
149 end
136 end
150 end
137 end
151 return true
138 return true
152 end
139 end
153
140
154 def authorization
141 def authorization
155 return false unless check_valid_login
142 return false unless check_valid_login
156 user = User.find(session[:user_id])
143 user = User.find(session[:user_id])
157 unless user.roles.detect { |role|
144 unless user.roles.detect { |role|
158 role.rights.detect{ |right|
145 role.rights.detect{ |right|
159 right.controller == self.class.controller_name and
146 right.controller == self.class.controller_name and
160 (right.action == 'all' || right.action == action_name)
147 (right.action == 'all' || right.action == action_name)
161 }
148 }
162 }
149 }
163 flash[:notice] = 'You are not authorized to view the page you requested'
150 flash[:notice] = 'You are not authorized to view the page you requested'
164 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
151 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
165 redirect_to :controller => 'main', :action => 'login'
152 redirect_to :controller => 'main', :action => 'login'
166 return false
153 return false
167 end
154 end
168 end
155 end
169
156
170 def verify_time_limit
157 def verify_time_limit
171 return true if session[:user_id]==nil
158 return true if session[:user_id]==nil
172 user = User.find(session[:user_id], :include => :site)
159 user = User.find(session[:user_id], :include => :site)
173 return true if user==nil || user.site == nil
160 return true if user==nil || user.site == nil
174 if user.contest_finished?
161 if user.contest_finished?
175 flash[:notice] = 'Error: the contest you are participating is over.'
162 flash[:notice] = 'Error: the contest you are participating is over.'
176 redirect_to :back
163 redirect_to :back
177 return false
164 return false
178 end
165 end
179 return true
166 return true
180 end
167 end
181
168
182 def is_request_ip_allowed?
169 def is_request_ip_allowed?
183 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
170 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
184 user_ip = IPAddr.new(request.remote_ip)
171 user_ip = IPAddr.new(request.remote_ip)
185 allowed = GraderConfiguration[WHITELIST_IP_CONF_KEY] || ''
172 allowed = GraderConfiguration[WHITELIST_IP_CONF_KEY] || ''
186
173
187 allowed.delete(' ').split(',').each do |ips|
174 allowed.delete(' ').split(',').each do |ips|
188 allow_ips = IPAddr.new(ips)
175 allow_ips = IPAddr.new(ips)
189 if allow_ips.include?(user_ip)
176 if allow_ips.include?(user_ip)
190 return true
177 return true
191 end
178 end
192 end
179 end
193 return false
180 return false
194 end
181 end
195 return true
182 return true
196 end
183 end
197
184
198 #function for datatable ajax query
185 #function for datatable ajax query
199 #return record,total_count,filter_count
186 #return record,total_count,filter_count
200 def process_query_record(record,
187 def process_query_record(record,
201 total_count: nil,
188 total_count: nil,
202 select: '',
189 select: '',
203 global_search: [],
190 global_search: [],
204 no_search: false,
191 no_search: false,
205 force_order: '',
192 force_order: '',
206 date_filter: '', date_param_since: 'date_since',date_param_until: 'date_until',
193 date_filter: '', date_param_since: 'date_since',date_param_until: 'date_until',
207 hard_limit: nil)
194 hard_limit: nil)
208 arel_table = record.model.arel_table
195 arel_table = record.model.arel_table
209
196
210 if !no_search && params['search']
197 if !no_search && params['search']
211 global_value = record.model.sanitize_sql(params['search']['value'].strip.downcase)
198 global_value = record.model.sanitize_sql(params['search']['value'].strip.downcase)
212 if !global_value.blank?
199 if !global_value.blank?
213 global_value.split.each do |value|
200 global_value.split.each do |value|
214 global_where = global_search.map{|f| "LOWER(#{f}) like '%#{value}%'"}.join(' OR ')
201 global_where = global_search.map{|f| "LOWER(#{f}) like '%#{value}%'"}.join(' OR ')
215 record = record.where(global_where)
202 record = record.where(global_where)
216 end
203 end
217 end
204 end
218
205
219 params['columns'].each do |i, col|
206 params['columns'].each do |i, col|
220 if !col['search']['value'].blank?
207 if !col['search']['value'].blank?
221 record = record.where(arel_table[col['name']].lower.matches("%#{col['search']['value'].strip.downcase}%"))
208 record = record.where(arel_table[col['name']].lower.matches("%#{col['search']['value'].strip.downcase}%"))
222 end
209 end
223 end
210 end
224 end
211 end
225
212
226 if !date_filter.blank?
213 if !date_filter.blank?
227 param_since = params[date_param_since]
214 param_since = params[date_param_since]
228 param_until = params[date_param_until]
215 param_until = params[date_param_until]
229 date_since = Time.zone.parse( param_since ) || Time.new(1,1,1) rescue Time.new(1,1,1)
216 date_since = Time.zone.parse( param_since ) || Time.new(1,1,1) rescue Time.new(1,1,1)
230 date_until = Time.zone.parse( param_until ) || Time.zone.now() rescue Time.zone.now()
217 date_until = Time.zone.parse( param_until ) || Time.zone.now() rescue Time.zone.now()
231 date_range = date_since..(date_until.end_of_day)
218 date_range = date_since..(date_until.end_of_day)
232 record = record.where(date_filter.to_sym => date_range)
219 record = record.where(date_filter.to_sym => date_range)
233 end
220 end
234
221
235 if force_order.blank?
222 if force_order.blank?
236 if params['order']
223 if params['order']
237 params['order'].each do |i, o|
224 params['order'].each do |i, o|
238 colName = params['columns'][o['column']]['name']
225 colName = params['columns'][o['column']]['name']
239 colName = "#{record.model.table_name}.#{colName}" if colName.upcase == 'ID'
226 colName = "#{record.model.table_name}.#{colName}" if colName.upcase == 'ID'
240 record = record.order("#{colName} #{o['dir'].casecmp('desc') != 0 ? 'ASC' : 'DESC'}") unless colName.blank?
227 record = record.order("#{colName} #{o['dir'].casecmp('desc') != 0 ? 'ASC' : 'DESC'}") unless colName.blank?
241 end
228 end
242 end
229 end
243 else
230 else
244 record = record.order(force_order)
231 record = record.order(force_order)
245 end
232 end
246
233
247 filterCount = record.count(record.model.primary_key)
234 filterCount = record.count(record.model.primary_key)
248 # if .group() is used, filterCount might be like {id_1: count_1, id_2: count_2, ...}
235 # if .group() is used, filterCount might be like {id_1: count_1, id_2: count_2, ...}
249 # so we should count the result again..
236 # so we should count the result again..
250 if filterCount.is_a? Hash
237 if filterCount.is_a? Hash
251 filterCount = filterCount.count
238 filterCount = filterCount.count
252 end
239 end
253
240
254
241
255 record = record.offset(params['start'] || 0)
242 record = record.offset(params['start'] || 0)
256 record = record.limit(hard_limit)
243 record = record.limit(hard_limit)
257 if (params['length'])
244 if (params['length'])
258 limit = params['length'].to_i
245 limit = params['length'].to_i
259 limit == hard_limit if (hard_limit && hard_limit < limit)
246 limit == hard_limit if (hard_limit && hard_limit < limit)
260 record = record.limit(limit)
247 record = record.limit(limit)
261 end
248 end
262 if (!select.blank?)
249 if (!select.blank?)
263 record = record.select(select)
250 record = record.select(select)
264 end
251 end
@@ -1,99 +1,97
1 class LoginController < ApplicationController
1 class LoginController < ApplicationController
2
2
3 @@authenticators = []
3 @@authenticators = []
4
4
5 def index
5 def index
6 # show login screen
6 # show login screen
7 reset_session
7 reset_session
8 redirect_to :controller => 'main', :action => 'login'
8 redirect_to :controller => 'main', :action => 'login'
9 end
9 end
10
10
11 def login
11 def login
12 user = get_authenticated_user(params[:login], params[:password])
12 user = get_authenticated_user(params[:login], params[:password])
13 unless user
13 unless user
14 - flash[:notice] = 'Wrong password'
14 + redirect_to login_main_path, alert: 'Wrong password'
15 - redirect_to :controller => 'main', :action => 'login'
16 return
15 return
17 end
16 end
18
17
19 if (!GraderConfiguration['right.bypass_agreement']) and (!params[:accept_agree]) and !user.admin?
18 if (!GraderConfiguration['right.bypass_agreement']) and (!params[:accept_agree]) and !user.admin?
20 - flash[:notice] = 'You must accept the agreement before logging in'
19 + redirect_to login_main_path, alert: 'You must accept the agreement before logging in'
21 - redirect_to :controller => 'main', :action => 'login'
22 return
20 return
23 end
21 end
24
22
25 #store uuid when login
23 #store uuid when login
26 if user.last_ip.nil?
24 if user.last_ip.nil?
27 user.last_ip = cookies.encrypted[:uuid]
25 user.last_ip = cookies.encrypted[:uuid]
28 else
26 else
29 if user.last_ip != cookies.encrypted[:uuid]
27 if user.last_ip != cookies.encrypted[:uuid]
30 user.last_ip =cookies.encrypted[:uuid]
28 user.last_ip =cookies.encrypted[:uuid]
31 #log different login
29 #log different login
32 end
30 end
33 end
31 end
34
32
35 #process logging in
33 #process logging in
36 session[:user_id] = user.id
34 session[:user_id] = user.id
37 session[:admin] = user.admin?
35 session[:admin] = user.admin?
38
36
39 # clear forced logout flag for multicontests contest change
37 # clear forced logout flag for multicontests contest change
40 if GraderConfiguration.multicontests?
38 if GraderConfiguration.multicontests?
41 contest_stat = user.contest_stat
39 contest_stat = user.contest_stat
42 if contest_stat.respond_to? :forced_logout
40 if contest_stat.respond_to? :forced_logout
43 if contest_stat.forced_logout
41 if contest_stat.forced_logout
44 contest_stat.forced_logout = false
42 contest_stat.forced_logout = false
45 contest_stat.save
43 contest_stat.save
46 end
44 end
47 end
45 end
48 end
46 end
49
47
50 #save login information
48 #save login information
51 Login.create(user_id: user.id, ip_address: cookies.encrypted[:uuid])
49 Login.create(user_id: user.id, ip_address: cookies.encrypted[:uuid])
52
50
53 redirect_to :controller => 'main', :action => 'list'
51 redirect_to :controller => 'main', :action => 'list'
54 end
52 end
55
53
56 def site_login
54 def site_login
57 begin
55 begin
58 site = Site.find(params[:login][:site_id])
56 site = Site.find(params[:login][:site_id])
59 rescue ActiveRecord::RecordNotFound
57 rescue ActiveRecord::RecordNotFound
60 site = nil
58 site = nil
61 end
59 end
62 if site==nil
60 if site==nil
63 - flash[:notice] = 'Wrong site'
61 + flash[:alert] = 'Wrong site'
64 redirect_to :controller => 'main', :action => 'login' and return
62 redirect_to :controller => 'main', :action => 'login' and return
65 end
63 end
66 if (site.password) and (site.password == params[:login][:password])
64 if (site.password) and (site.password == params[:login][:password])
67 session[:site_id] = site.id
65 session[:site_id] = site.id
68 redirect_to :controller => 'site', :action => 'index'
66 redirect_to :controller => 'site', :action => 'index'
69 else
67 else
70 - flash[:notice] = 'Wrong site password'
68 + flash[:alert] = 'Wrong site password'
71 redirect_to :controller => 'site', :action => 'login'
69 redirect_to :controller => 'site', :action => 'login'
72 end
70 end
73 end
71 end
74
72
75 def logout
73 def logout
76 redirect_to root_path
74 redirect_to root_path
77 end
75 end
78
76
79 def self.add_authenticator(authenticator)
77 def self.add_authenticator(authenticator)
80 @@authenticators << authenticator
78 @@authenticators << authenticator
81 end
79 end
82
80
83 protected
81 protected
84
82
85 def get_authenticated_user(login, password)
83 def get_authenticated_user(login, password)
86 if @@authenticators.empty?
84 if @@authenticators.empty?
87 return User.authenticate(login, password)
85 return User.authenticate(login, password)
88 else
86 else
89 user = User.authenticate(login, password)
87 user = User.authenticate(login, password)
90 @@authenticators.each do |authenticator|
88 @@authenticators.each do |authenticator|
91 if not user
89 if not user
92 user = authenticator.authenticate(login, password)
90 user = authenticator.authenticate(login, password)
93 end
91 end
94 end
92 end
95 return user
93 return user
96 end
94 end
97 end
95 end
98
96
99 end
97 end
@@ -1,215 +1,214
1 class MainController < ApplicationController
1 class MainController < ApplicationController
2
2
3 before_action :check_valid_login, :except => [:login]
3 before_action :check_valid_login, :except => [:login]
4 before_action :check_viewability, :except => [:index, :login]
4 before_action :check_viewability, :except => [:index, :login]
5
5
6 append_before_action :confirm_and_update_start_time,
6 append_before_action :confirm_and_update_start_time,
7 :except => [:index,
7 :except => [:index,
8 :login,
8 :login,
9 :confirm_contest_start]
9 :confirm_contest_start]
10
10
11 # to prevent log in box to be shown when user logged out of the
11 # to prevent log in box to be shown when user logged out of the
12 # system only in some tab
12 # system only in some tab
13 prepend_before_action :reject_announcement_refresh_when_logged_out,
13 prepend_before_action :reject_announcement_refresh_when_logged_out,
14 :only => [:announcements]
14 :only => [:announcements]
15
15
16 before_action :authenticate_by_ip_address, :only => [:list]
16 before_action :authenticate_by_ip_address, :only => [:list]
17
17
18 #reset login, clear session
18 #reset login, clear session
19 #front page
19 #front page
20 def login
20 def login
21 - saved_notice = flash[:notice]
21 + #saved_notice = flash[:notice]
22 - reset_session
22 + #flash[:notice] = saved_notice
23 - flash.now[:notice] = saved_notice
24 @remote_ip = request.remote_ip
23 @remote_ip = request.remote_ip
25
24
26 # EXPERIMENT:
25 # EXPERIMENT:
27 # Hide login if in single user mode and the url does not
26 # Hide login if in single user mode and the url does not
28 # explicitly specify /login
27 # explicitly specify /login
29 #
28 #
30 # logger.info "PATH: #{request.path}"
29 # logger.info "PATH: #{request.path}"
31 # if GraderConfiguration['system.single_user_mode'] and
30 # if GraderConfiguration['system.single_user_mode'] and
32 # request.path!='/main/login'
31 # request.path!='/main/login'
33 # @hidelogin = true
32 # @hidelogin = true
34 # end
33 # end
35
34
36 @announcements = Announcement.frontpage
35 @announcements = Announcement.frontpage
37 render :action => 'login', locals: {skip_header: true}
36 render :action => 'login', locals: {skip_header: true}
38 end
37 end
39
38
40 def logout
39 def logout
41 reset_session
40 reset_session
42 redirect_to root_path
41 redirect_to root_path
43 end
42 end
44
43
45 def list
44 def list
46 prepare_list_information
45 prepare_list_information
47 end
46 end
48
47
49 def help
48 def help
50 @user = User.find(session[:user_id])
49 @user = User.find(session[:user_id])
51 end
50 end
52
51
53 def submit
52 def submit
54 user = User.find(session[:user_id])
53 user = User.find(session[:user_id])
55
54
56 @submission = Submission.new
55 @submission = Submission.new
57 @submission.problem_id = params[:submission][:problem_id]
56 @submission.problem_id = params[:submission][:problem_id]
58 @submission.user = user
57 @submission.user = user
59 @submission.language_id = 0
58 @submission.language_id = 0
60 if (params['file']) and (params['file']!='')
59 if (params['file']) and (params['file']!='')
61 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
60 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
62 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
61 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
63 @submission.source_filename = params['file'].original_filename
62 @submission.source_filename = params['file'].original_filename
64 end
63 end
65
64
66 if (params[:editor_text])
65 if (params[:editor_text])
67 language = Language.find_by_id(params[:language_id])
66 language = Language.find_by_id(params[:language_id])
68 @submission.source = params[:editor_text]
67 @submission.source = params[:editor_text]
69 @submission.source_filename = "live_edit.#{language.ext}"
68 @submission.source_filename = "live_edit.#{language.ext}"
70 @submission.language = language
69 @submission.language = language
71 end
70 end
72
71
73 @submission.submitted_at = Time.new.gmtime
72 @submission.submitted_at = Time.new.gmtime
74 @submission.ip_address = cookies.encrypted[:uuid]
73 @submission.ip_address = cookies.encrypted[:uuid]
75
74
76 if @current_user.admin? == false && GraderConfiguration.time_limit_mode? && @current_user.contest_finished?
75 if @current_user.admin? == false && GraderConfiguration.time_limit_mode? && @current_user.contest_finished?
77 @submission.errors.add(:base,"The contest is over.")
76 @submission.errors.add(:base,"The contest is over.")
78 prepare_list_information
77 prepare_list_information
79 render :action => 'list' and return
78 render :action => 'list' and return
80 end
79 end
81
80
82 if @submission.valid?(@current_user)
81 if @submission.valid?(@current_user)
83 if @submission.save == false
82 if @submission.save == false
84 flash[:notice] = 'Error saving your submission'
83 flash[:notice] = 'Error saving your submission'
85 elsif Task.create(:submission_id => @submission.id,
84 elsif Task.create(:submission_id => @submission.id,
86 :status => Task::STATUS_INQUEUE) == false
85 :status => Task::STATUS_INQUEUE) == false
87 flash[:notice] = 'Error adding your submission to task queue'
86 flash[:notice] = 'Error adding your submission to task queue'
88 end
87 end
89 else
88 else
90 prepare_list_information
89 prepare_list_information
91 render :action => 'list' and return
90 render :action => 'list' and return
92 end
91 end
93 redirect_to edit_submission_path(@submission)
92 redirect_to edit_submission_path(@submission)
94 end
93 end
95
94
96 def source
95 def source
97 submission = Submission.find(params[:id])
96 submission = Submission.find(params[:id])
98 if ((submission.user_id == session[:user_id]) and
97 if ((submission.user_id == session[:user_id]) and
99 (submission.problem != nil) and
98 (submission.problem != nil) and
100 (submission.problem.available))
99 (submission.problem.available))
101 send_data(submission.source,
100 send_data(submission.source,
102 {:filename => submission.download_filename,
101 {:filename => submission.download_filename,
103 :type => 'text/plain'})
102 :type => 'text/plain'})
104 else
103 else
105 flash[:notice] = 'Error viewing source'
104 flash[:notice] = 'Error viewing source'
106 redirect_to :action => 'list'
105 redirect_to :action => 'list'
107 end
106 end
108 end
107 end
109
108
110 def compiler_msg
109 def compiler_msg
111 @submission = Submission.find(params[:id])
110 @submission = Submission.find(params[:id])
112 if @submission.user_id == session[:user_id]
111 if @submission.user_id == session[:user_id]
113 render :action => 'compiler_msg', :layout => 'empty'
112 render :action => 'compiler_msg', :layout => 'empty'
114 else
113 else
115 flash[:notice] = 'Error viewing source'
114 flash[:notice] = 'Error viewing source'
116 redirect_to :action => 'list'
115 redirect_to :action => 'list'
117 end
116 end
118 end
117 end
119
118
120 def result
119 def result
121 if !GraderConfiguration.show_grading_result
120 if !GraderConfiguration.show_grading_result
122 redirect_to :action => 'list' and return
121 redirect_to :action => 'list' and return
123 end
122 end
124 @user = User.find(session[:user_id])
123 @user = User.find(session[:user_id])
125 @submission = Submission.find(params[:id])
124 @submission = Submission.find(params[:id])
126 if @submission.user!=@user
125 if @submission.user!=@user
127 flash[:notice] = 'You are not allowed to view result of other users.'
126 flash[:notice] = 'You are not allowed to view result of other users.'
128 redirect_to :action => 'list' and return
127 redirect_to :action => 'list' and return
129 end
128 end
130 prepare_grading_result(@submission)
129 prepare_grading_result(@submission)
131 end
130 end
132
131
133 def load_output
132 def load_output
134 if !GraderConfiguration.show_grading_result or params[:num]==nil
133 if !GraderConfiguration.show_grading_result or params[:num]==nil
135 redirect_to :action => 'list' and return
134 redirect_to :action => 'list' and return
136 end
135 end
137 @user = User.find(session[:user_id])
136 @user = User.find(session[:user_id])
138 @submission = Submission.find(params[:id])
137 @submission = Submission.find(params[:id])
139 if @submission.user!=@user
138 if @submission.user!=@user
140 flash[:notice] = 'You are not allowed to view result of other users.'
139 flash[:notice] = 'You are not allowed to view result of other users.'
141 redirect_to :action => 'list' and return
140 redirect_to :action => 'list' and return
142 end
141 end
143 case_num = params[:num].to_i
142 case_num = params[:num].to_i
144 out_filename = output_filename(@user.login,
143 out_filename = output_filename(@user.login,
145 @submission.problem.name,
144 @submission.problem.name,
146 @submission.id,
145 @submission.id,
147 case_num)
146 case_num)
148 if !FileTest.exists?(out_filename)
147 if !FileTest.exists?(out_filename)
149 flash[:notice] = 'Output not found.'
148 flash[:notice] = 'Output not found.'
150 redirect_to :action => 'list' and return
149 redirect_to :action => 'list' and return
151 end
150 end
152
151
153 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
152 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
154 response.headers['Content-Type'] = "application/force-download"
153 response.headers['Content-Type'] = "application/force-download"
155 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
154 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
156 response.headers["X-Sendfile"] = out_filename
155 response.headers["X-Sendfile"] = out_filename
157 response.headers['Content-length'] = File.size(out_filename)
156 response.headers['Content-length'] = File.size(out_filename)
158 render :nothing => true
157 render :nothing => true
159 else
158 else
160 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
159 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
161 end
160 end
162 end
161 end
163
162
164 def error
163 def error
165 @user = User.find(session[:user_id])
164 @user = User.find(session[:user_id])
166 end
165 end
167
166
168 # announcement refreshing and hiding methods
167 # announcement refreshing and hiding methods
169
168
170 def announcements
169 def announcements
171 if params.has_key? 'recent'
170 if params.has_key? 'recent'
172 prepare_announcements(params[:recent])
171 prepare_announcements(params[:recent])
173 else
172 else
174 prepare_announcements
173 prepare_announcements
175 end
174 end
176 render(:partial => 'announcement',
175 render(:partial => 'announcement',
177 :collection => @announcements,
176 :collection => @announcements,
178 :locals => {:announcement_effect => true})
177 :locals => {:announcement_effect => true})
179 end
178 end
180
179
181 def confirm_contest_start
180 def confirm_contest_start
182 user = User.find(session[:user_id])
181 user = User.find(session[:user_id])
183 if request.method == 'POST'
182 if request.method == 'POST'
184 user.update_start_time
183 user.update_start_time
185 redirect_to :action => 'list'
184 redirect_to :action => 'list'
186 else
185 else
187 @contests = user.contests
186 @contests = user.contests
188 @user = user
187 @user = user
189 end
188 end
190 end
189 end
191
190
192 protected
191 protected
193
192
194 def prepare_announcements(recent=nil)
193 def prepare_announcements(recent=nil)
195 if GraderConfiguration.show_tasks_to?(@user)
194 if GraderConfiguration.show_tasks_to?(@user)
196 @announcements = Announcement.published(true)
195 @announcements = Announcement.published(true)
197 else
196 else
198 @announcements = Announcement.published
197 @announcements = Announcement.published
199 end
198 end
200 if recent!=nil
199 if recent!=nil
201 recent_id = recent.to_i
200 recent_id = recent.to_i
202 @announcements = @announcements.find_all { |a| a.id > recent_id }
201 @announcements = @announcements.find_all { |a| a.id > recent_id }
203 end
202 end
204 end
203 end
205
204
206 def prepare_list_information
205 def prepare_list_information
207 @user = User.find(session[:user_id])
206 @user = User.find(session[:user_id])
208 if not GraderConfiguration.multicontests?
207 if not GraderConfiguration.multicontests?
209 @problems = @user.available_problems
208 @problems = @user.available_problems
210 else
209 else
211 @contest_problems = @user.available_problems_group_by_contests
210 @contest_problems = @user.available_problems_group_by_contests
212 @problems = @user.available_problems
211 @problems = @user.available_problems
213 end
212 end
214 @prob_submissions = {}
213 @prob_submissions = {}
215 @problems.each do |p|
214 @problems.each do |p|
@@ -1,115 +1,115
1 class SubmissionsController < ApplicationController
1 class SubmissionsController < ApplicationController
2 before_action :set_submission, only: [:show,:download,:compiler_msg,:rejudge,:set_tag, :edit]
2 before_action :set_submission, only: [:show,:download,:compiler_msg,:rejudge,:set_tag, :edit]
3 before_action :check_valid_login
3 before_action :check_valid_login
4 before_action :submission_authorization, only: [:show, :download, :edit]
4 before_action :submission_authorization, only: [:show, :download, :edit]
5 - before_action only: [:rejudge, :set_tag] do role_authorization([:ta]) end
5 + before_action only: [:rejudge, :set_tag] do authorization_by_roles([:ta]) end
6
6
7 # GET /submissions
7 # GET /submissions
8 # GET /submissions.json
8 # GET /submissions.json
9 # Show problem selection and user's submission of that problem
9 # Show problem selection and user's submission of that problem
10 def index
10 def index
11 @user = @current_user
11 @user = @current_user
12 @problems = @user.available_problems
12 @problems = @user.available_problems
13
13
14 if params[:problem_id]==nil
14 if params[:problem_id]==nil
15 @problem = nil
15 @problem = nil
16 @submissions = nil
16 @submissions = nil
17 else
17 else
18 @problem = Problem.find_by_id(params[:problem_id])
18 @problem = Problem.find_by_id(params[:problem_id])
19 if (@problem == nil) or (not @problem.available)
19 if (@problem == nil) or (not @problem.available)
20 redirect_to list_main_path
20 redirect_to list_main_path
21 flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
21 flash[:error] = 'Authorization error: You have no right to view submissions for this problem'
22 return
22 return
23 end
23 end
24 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
24 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
25 end
25 end
26 end
26 end
27
27
28 # GET /submissions/1
28 # GET /submissions/1
29 # GET /submissions/1.json
29 # GET /submissions/1.json
30 def show
30 def show
31 #log the viewing
31 #log the viewing
32 user = User.find(session[:user_id])
32 user = User.find(session[:user_id])
33 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
33 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
34
34
35 @task = @submission.task
35 @task = @submission.task
36 end
36 end
37
37
38 def download
38 def download
39 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
39 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
40 end
40 end
41
41
42 def compiler_msg
42 def compiler_msg
43 respond_to do |format|
43 respond_to do |format|
44 format.js
44 format.js
45 end
45 end
46 end
46 end
47
47
48 #on-site new submission on specific problem
48 #on-site new submission on specific problem
49 def direct_edit_problem
49 def direct_edit_problem
50 @problem = Problem.find(params[:problem_id])
50 @problem = Problem.find(params[:problem_id])
51 unless @current_user.can_view_problem?(@problem)
51 unless @current_user.can_view_problem?(@problem)
52 unauthorized_redirect
52 unauthorized_redirect
53 return
53 return
54 end
54 end
55 @source = ''
55 @source = ''
56 if (params[:view_latest])
56 if (params[:view_latest])
57 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
57 sub = Submission.find_last_by_user_and_problem(@current_user.id,@problem.id)
58 @source = @submission.source.to_s if @submission and @submission.source
58 @source = @submission.source.to_s if @submission and @submission.source
59 end
59 end
60 render 'edit'
60 render 'edit'
61 end
61 end
62
62
63 # GET /submissions/1/edit
63 # GET /submissions/1/edit
64 def edit
64 def edit
65 @source = @submission.source.to_s
65 @source = @submission.source.to_s
66 @problem = @submission.problem
66 @problem = @submission.problem
67 @lang_id = @submission.language.id
67 @lang_id = @submission.language.id
68 end
68 end
69
69
70
70
71 def get_latest_submission_status
71 def get_latest_submission_status
72 @problem = Problem.find(params[:pid])
72 @problem = Problem.find(params[:pid])
73 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
73 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
74 respond_to do |format|
74 respond_to do |format|
75 format.js
75 format.js
76 end
76 end
77 end
77 end
78
78
79 # GET /submissions/:id/rejudge
79 # GET /submissions/:id/rejudge
80 def rejudge
80 def rejudge
81 @task = @submission.task
81 @task = @submission.task
82 @task.status_inqueue! if @task
82 @task.status_inqueue! if @task
83 respond_to do |format|
83 respond_to do |format|
84 format.js
84 format.js
85 end
85 end
86 end
86 end
87
87
88 def set_tag
88 def set_tag
89 @submission.update(tag: params[:tag])
89 @submission.update(tag: params[:tag])
90 redirect_to @submission
90 redirect_to @submission
91 end
91 end
92
92
93 protected
93 protected
94
94
95 def submission_authorization
95 def submission_authorization
96 #admin always has privileged
96 #admin always has privileged
97 return true if @current_user.admin?
97 return true if @current_user.admin?
98 return true if @current_user.has_role?('ta') && (['show','download'].include? action_name)
98 return true if @current_user.has_role?('ta') && (['show','download'].include? action_name)
99
99
100 sub = Submission.find(params[:id])
100 sub = Submission.find(params[:id])
101 if @current_user.available_problems.include? sub.problem
101 if @current_user.available_problems.include? sub.problem
102 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
102 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
103 end
103 end
104
104
105 #default to NO
105 #default to NO
106 unauthorized_redirect
106 unauthorized_redirect
107 return false
107 return false
108 end
108 end
109
109
110 def set_submission
110 def set_submission
111 @submission = Submission.find(params[:id])
111 @submission = Submission.find(params[:id])
112 end
112 end
113
113
114
114
115 end
115 end
@@ -1,61 +1,61
1 class TagsController < ApplicationController
1 class TagsController < ApplicationController
2 before_action :admin_authorization
2 before_action :admin_authorization
3 before_action :set_tag, only: [:show, :edit, :update, :destroy]
3 before_action :set_tag, only: [:show, :edit, :update, :destroy]
4
4
5 # GET /tags
5 # GET /tags
6 def index
6 def index
7 @tags = Tag.all
7 @tags = Tag.all
8 end
8 end
9
9
10 # GET /tags/1
10 # GET /tags/1
11 def show
11 def show
12 end
12 end
13
13
14 # GET /tags/new
14 # GET /tags/new
15 def new
15 def new
16 @tag = Tag.new
16 @tag = Tag.new
17 end
17 end
18
18
19 # GET /tags/1/edit
19 # GET /tags/1/edit
20 def edit
20 def edit
21 end
21 end
22
22
23 # POST /tags
23 # POST /tags
24 def create
24 def create
25 @tag = Tag.new(tag_params)
25 @tag = Tag.new(tag_params)
26
26
27 if @tag.save
27 if @tag.save
28 - redirect_to @tag, notice: 'Tag was successfully created.'
28 + redirect_to tags_path, notice: 'Tag was successfully created.'
29 else
29 else
30 render :new
30 render :new
31 end
31 end
32 end
32 end
33
33
34 # PATCH/PUT /tags/1
34 # PATCH/PUT /tags/1
35 def update
35 def update
36 if @tag.update(tag_params)
36 if @tag.update(tag_params)
37 redirect_to @tag, notice: 'Tag was successfully updated.'
37 redirect_to @tag, notice: 'Tag was successfully updated.'
38 else
38 else
39 render :edit
39 render :edit
40 end
40 end
41 end
41 end
42
42
43 # DELETE /tags/1
43 # DELETE /tags/1
44 def destroy
44 def destroy
45 #remove any association
45 #remove any association
46 ProblemTag.where(tag_id: @tag.id).destroy_all
46 ProblemTag.where(tag_id: @tag.id).destroy_all
47 @tag.destroy
47 @tag.destroy
48 redirect_to tags_url, notice: 'Tag was successfully destroyed.'
48 redirect_to tags_url, notice: 'Tag was successfully destroyed.'
49 end
49 end
50
50
51 private
51 private
52 # Use callbacks to share common setup or constraints between actions.
52 # Use callbacks to share common setup or constraints between actions.
53 def set_tag
53 def set_tag
54 @tag = Tag.find(params[:id])
54 @tag = Tag.find(params[:id])
55 end
55 end
56
56
57 # Only allow a trusted parameter "white list" through.
57 # Only allow a trusted parameter "white list" through.
58 def tag_params
58 def tag_params
59 params.require(:tag).permit(:name, :description, :public)
59 params.require(:tag).permit(:name, :description, :public)
60 end
60 end
61 end
61 end
@@ -1,23 +1,23
1 %h1 Groups
1 %h1 Groups
2
2
3 %p
3 %p
4 = link_to 'New Group', new_group_path, class: 'btn btn-success'
4 = link_to 'New Group', new_group_path, class: 'btn btn-success'
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 Enabled?
11 %th
11 %th
12 %tbody
12 %tbody
13 - @groups.each do |group|
13 - @groups.each do |group|
14 %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
14 %tr{:class => "#{(group.enabled?) ? "success" : "danger"}", id: "group-#{group.id}"}
15 %td= group.name
15 %td= group.name
16 %td= group.description
16 %td= group.description
17 %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", block: ' ')
17 %td= toggle_button(group.enabled?, toggle_group_path(group), "group-enabled-#{group.id}", block: ' ')
18 %td
18 %td
19 - = link_to 'Edit members and problems', group, class: 'btn btn-secondary btn-sm'
19 + = link_to 'Edit members and problems', group, class: 'btn btn-info btn-sm'
20 = link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger btn-sm'
20 = link_to 'Destroy', group, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger btn-sm'
21
21
22 %br
22 %br
23
23
@@ -1,93 +1,93
1 %header
1 %header
2 %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg
2 %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg
3 .container-fluid
3 .container-fluid
4 %a.navbar-brand{href: list_main_path}
4 %a.navbar-brand{href: list_main_path}
5 %span.mi.mi-bs home
5 %span.mi.mi-bs home
6 MAIN
6 MAIN
7 %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} }
7 %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} }
8 %span.navbar-toggler-icon
8 %span.navbar-toggler-icon
9 .collapse.navbar-collapse#navbar-collapse
9 .collapse.navbar-collapse#navbar-collapse
10 %ul.navbar-nav.me-auto.mb-2.mb-lg-0
10 %ul.navbar-nav.me-auto.mb-2.mb-lg-0
11 / submission
11 / submission
12 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
12 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
13 %li.nav-item.dropdown.mx-2
13 %li.nav-item.dropdown.mx-2
14 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"}
14 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"}
15 = "#{I18n.t 'menu.submissions'}"
15 = "#{I18n.t 'menu.submissions'}"
16 %ul.dropdown-menu
16 %ul.dropdown-menu
17 %li= link_to 'View', submissions_path, class: 'dropdown-item '+active_class_when(controller: :submissions)
17 %li= link_to 'View', submissions_path, class: 'dropdown-item '+active_class_when(controller: :submissions)
18 %li= link_to 'Self Test', test_index_path, class:'dropdown-item'
18 %li= link_to 'Self Test', test_index_path, class:'dropdown-item'
19 / hall of fame
19 / hall of fame
20 - if GraderConfiguration['right.user_hall_of_fame']
20 - if GraderConfiguration['right.user_hall_of_fame']
21 %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2'+active_class_when(controller: :report, action: :problem_hof)
21 %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2'+active_class_when(controller: :report, action: :problem_hof)
22 / display MODE button (with countdown in contest mode)
22 / display MODE button (with countdown in contest mode)
23 - if GraderConfiguration.analysis_mode?
23 - if GraderConfiguration.analysis_mode?
24 %div.btn.btn-success#countdown= "ANALYSIS MODE"
24 %div.btn.btn-success#countdown= "ANALYSIS MODE"
25 - elsif GraderConfiguration.time_limit_mode?
25 - elsif GraderConfiguration.time_limit_mode?
26 - if @current_user.contest_finished?
26 - if @current_user.contest_finished?
27 %div.btn.btn-danger#countdown= "Contest is over"
27 %div.btn.btn-danger#countdown= "Contest is over"
28 - elsif !@current_user.contest_started?
28 - elsif !@current_user.contest_started?
29 %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
29 %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
30 - else
30 - else
31 %div.btn.btn-primary#countdown asdf
31 %div.btn.btn-primary#countdown asdf
32 :javascript
32 :javascript
33 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
33 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
34 / admin section
34 / admin section
35 - if (@current_user!=nil) and (session[:admin])
35 - if (@current_user!=nil) and (session[:admin])
36 / management
36 / management
37 %li.nav-item.dropdown.mx-2
37 %li.nav-item.dropdown.mx-2
38 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
38 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
39 Manage
39 Manage
40 %ul.dropdown-menu
40 %ul.dropdown-menu
41 %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'+active_class_when(controller: :announcements)
41 %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'+active_class_when(controller: :announcements)
42 %li= link_to 'Problems', problems_path, class: 'dropdown-item'+active_class_when(controller: :problems)
42 %li= link_to 'Problems', problems_path, class: 'dropdown-item'+active_class_when(controller: :problems)
43 %li= link_to 'Tags', tags_path, class: 'dropdown-item'+active_class_when(controller: :tags)
43 %li= link_to 'Tags', tags_path, class: 'dropdown-item'+active_class_when(controller: :tags)
44 %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'+active_class_when(controller: :user_admin)
44 %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'+active_class_when(controller: :user_admin)
45 %li= link_to 'User Groups', groups_path, class: 'dropdown-item'+active_class_when(controller: :groups)
45 %li= link_to 'User Groups', groups_path, class: 'dropdown-item'+active_class_when(controller: :groups)
46 %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'+active_class_when(controller: :graders)
46 %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'+active_class_when(controller: :graders)
47 %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'+active_class_when(controller: :messages)
47 %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'+active_class_when(controller: :messages)
48 %li
48 %li
49 %hr.dropdown-divider
49 %hr.dropdown-divider
50 %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item'+active_class_when(controller: :grader_configuration)
50 %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item'+active_class_when(controller: :grader_configuration)
51 %li
51 %li
52 %hr.dropdown-divider
52 %hr.dropdown-divider
53 %li= link_to 'Sites', sites_path, class: 'dropdown-item'+active_class_when(controller: :sites)
53 %li= link_to 'Sites', sites_path, class: 'dropdown-item'+active_class_when(controller: :sites)
54 %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item'+active_class_when(controller: :contest_management)
54 %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item'+active_class_when(controller: :contest_management)
55 -#
55 -#
56 / report
56 / report
57 %li.nav-item.dropdown.mx-2
57 %li.nav-item.dropdown.mx-2
58 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
58 %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
59 Report
59 Report
60 %ul.dropdown-menu
60 %ul.dropdown-menu
61 %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :current_score)
61 %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :current_score)
62 %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :max_score)
62 %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :max_score)
63 %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :submission)
63 %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :submission)
64 %li= link_to 'Login Report', login_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :login)
64 %li= link_to 'Login Report', login_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :login)
65 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
65 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
66 =link_to "#{ungraded} backlogs!",
66 =link_to "#{ungraded} backlogs!",
67 graders_list_path,
67 graders_list_path,
68 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
68 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
69 / announcement
69 / announcement
70 - @nav_announcement.each do |ann|
70 - @nav_announcement.each do |ann|
71 %p.navbar-text
71 %p.navbar-text
72 = ann.body.html_safe
72 = ann.body.html_safe
73 %ul.navbar-nav
73 %ul.navbar-nav
74 %li.nav-item
74 %li.nav-item
75 %a.nav-link{href: help_main_path}
75 %a.nav-link{href: help_main_path}
76 %span.mi.mi-bs.md-18 help
76 %span.mi.mi-bs.md-18 help
77 %li.nav-item
77 %li.nav-item
78 %a.nav-link{href: messages_path}
78 %a.nav-link{href: messages_path}
79 %span.mi.mi-bs.md-18 chat
79 %span.mi.mi-bs.md-18 chat
80 - if GraderConfiguration['system.user_setting_enabled']
80 - if GraderConfiguration['system.user_setting_enabled']
81 %li.nav-item
81 %li.nav-item
82 %a.nav-link{href: profile_users_path}
82 %a.nav-link{href: profile_users_path}
83 %span.mi.mi-bs.md-18 settings
83 %span.mi.mi-bs.md-18 settings
84 %li.nav-item
84 %li.nav-item
85 - %a.nav-link{href: login_main_path}
85 + %a.nav-link{href: logout_main_path}
86 %span.mi.mi-bs.md-18 exit_to_app
86 %span.mi.mi-bs.md-18 exit_to_app
87 = @current_user.full_name
87 = @current_user.full_name
88 :javascript
88 :javascript
89 $('.active-with-children').each( (index,obj) => {
89 $('.active-with-children').each( (index,obj) => {
90 if ($(obj).siblings('.dropdown-menu').has('.active').length > 0) {
90 if ($(obj).siblings('.dropdown-menu').has('.active').length > 0) {
91 $(obj).addClass('active')
91 $(obj).addClass('active')
92 }
92 }
93 } )
93 } )
@@ -1,88 +1,87
1
1
2 .card
2 .card
3 .card-body
3 .card-body
4 .card-title
4 .card-title
5 %h3= GraderConfiguration['ui.front.welcome_message']
5 %h3= GraderConfiguration['ui.front.welcome_message']
6 - if !@hidelogin
6 - if !@hidelogin
7 .card-subtitle=t 'login.message'
7 .card-subtitle=t 'login.message'
8
8
9 - if flash[:notice]
9 - if flash[:notice]
10 - %hr/
10 + .alert.alert-danger
11 - %b= flash[:notice]
11 + = flash[:notice]
12 - %hr/
13
12
14 .card
13 .card
15 .card-body{ style: "background: #eeeeff;"}
14 .card-body{ style: "background: #eeeeff;"}
16 = form_with url: login_login_path do |f|
15 = form_with url: login_login_path do |f|
17 .mb-3
16 .mb-3
18 = f.label :login, "Login", class: 'form-label'
17 = f.label :login, "Login", class: 'form-label'
19 = f.text_field :login, class: 'form-control'
18 = f.text_field :login, class: 'form-control'
20 .mb-3
19 .mb-3
21 = f.label :password, "Password", class: 'form-label'
20 = f.label :password, "Password", class: 'form-label'
22 = f.password_field :password, class: 'form-control'
21 = f.password_field :password, class: 'form-control'
23 - unless GraderConfiguration['right.bypass_agreement']
22 - unless GraderConfiguration['right.bypass_agreement']
24 .col-sm-offset-3.col-sm-9
23 .col-sm-offset-3.col-sm-9
25 .checkbox
24 .checkbox
26 %label
25 %label
27 = check_box_tag 'accept_agree'
26 = check_box_tag 'accept_agree'
28 ΰΈ’ΰΈ­ΰΈ‘ΰΈ£ΰΈ±ΰΈšΰΈ‚ΰΉ‰ΰΈ­ΰΈ•ΰΈΰΈ₯ΰΈ‡ΰΈΰΈ²ΰΈ£ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™
27 ΰΈ’ΰΈ­ΰΈ‘ΰΈ£ΰΈ±ΰΈšΰΈ‚ΰΉ‰ΰΈ­ΰΈ•ΰΈΰΈ₯ΰΈ‡ΰΈΰΈ²ΰΈ£ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™
29 .mb-3
28 .mb-3
30 .col-sm-offset-3.col-sm-9
29 .col-sm-offset-3.col-sm-9
31 = submit_tag t('login.login_submit'), class: 'btn btn-primary'
30 = submit_tag t('login.login_submit'), class: 'btn btn-primary'
32 - else
31 - else
33 Login is not possible right now
32 Login is not possible right now
34
33
35 %br/
34 %br/
36
35
37 - if GraderConfiguration['system.online_registration']
36 - if GraderConfiguration['system.online_registration']
38 =t 'login.participation'
37 =t 'login.participation'
39 %b
38 %b
40 = "#{t 'login.please'} "
39 = "#{t 'login.please'} "
41 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
40 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
42 %br/
41 %br/
43 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
42 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
44 -#
43 -#
45 %br/
44 %br/
46
45
47 - if !@hidelogin
46 - if !@hidelogin
48 =t 'login.message'
47 =t 'login.message'
49 %br/
48 %br/
50 %br/
49 %br/
51
50
52 - if flash[:notice]
51 - if flash[:notice]
53 %hr/
52 %hr/
54 %b= flash[:notice]
53 %b= flash[:notice]
55 %hr/
54 %hr/
56
55
57 %div{ :style => "border: solid 1px gray; padding: 4px; background: #eeeeff;"}
56 %div{ :style => "border: solid 1px gray; padding: 4px; background: #eeeeff;"}
58 = form_tag login_login_path, {class: 'form-horizontal'} do
57 = form_tag login_login_path, {class: 'form-horizontal'} do
59 .form-group
58 .form-group
60 =label_tag :login, "Login",class: 'col-sm-3 control-label'
59 =label_tag :login, "Login",class: 'col-sm-3 control-label'
61 .col-sm-9
60 .col-sm-9
62 =text_field_tag :login, nil, class: 'form-control'
61 =text_field_tag :login, nil, class: 'form-control'
63 .form-group
62 .form-group
64 =label_tag :password, "Password", class: 'col-sm-3 control-label'
63 =label_tag :password, "Password", class: 'col-sm-3 control-label'
65 .col-sm-9
64 .col-sm-9
66 =password_field_tag :password, nil, class: 'form-control'
65 =password_field_tag :password, nil, class: 'form-control'
67 - unless GraderConfiguration['right.bypass_agreement']
66 - unless GraderConfiguration['right.bypass_agreement']
68 .form-group
67 .form-group
69 .col-sm-offset-3.col-sm-9
68 .col-sm-offset-3.col-sm-9
70 .checkbox
69 .checkbox
71 %label
70 %label
72 = check_box_tag 'accept_agree'
71 = check_box_tag 'accept_agree'
73 ΰΈ’ΰΈ­ΰΈ‘ΰΈ£ΰΈ±ΰΈšΰΈ‚ΰΉ‰ΰΈ­ΰΈ•ΰΈΰΈ₯ΰΈ‡ΰΈΰΈ²ΰΈ£ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™
72 ΰΈ’ΰΈ­ΰΈ‘ΰΈ£ΰΈ±ΰΈšΰΈ‚ΰΉ‰ΰΈ­ΰΈ•ΰΈΰΈ₯ΰΈ‡ΰΈΰΈ²ΰΈ£ΰΉƒΰΈŠΰΉ‰ΰΈ‡ΰΈ²ΰΈ™
74
73
75 .form-group
74 .form-group
76 .col-sm-offset-3.col-sm-9
75 .col-sm-offset-3.col-sm-9
77 = submit_tag t('login.login_submit'), class: 'btn btn-primary'
76 = submit_tag t('login.login_submit'), class: 'btn btn-primary'
78 - else
77 - else
79
78
80 %br/
79 %br/
81
80
82 - if GraderConfiguration['system.online_registration']
81 - if GraderConfiguration['system.online_registration']
83 =t 'login.participation'
82 =t 'login.participation'
84 %b
83 %b
85 = "#{t 'login.please'} "
84 = "#{t 'login.please'} "
86 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
85 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
87 %br/
86 %br/
88 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
87 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
@@ -1,22 +1,7
1 - = form_for @tag do |f|
1 + = simple_form_for @tag do |f|
2 - - if @tag.errors.any?
3 - #error_explanation
4 - %h2= "#{pluralize(@tag.errors.count, "error")} prohibited this tag from being saved:"
5 - %ul
6 - - @tag.errors.full_messages.each do |msg|
7 - %li= msg
8 -
9 .row
2 .row
10 .col-md-6
3 .col-md-6
11 - .form-group.field
4 + = f.input :name
12 - = f.label :name
5 + = f.input :description
13 - = f.text_field :name, class: 'form-control'
6 + = f.input :public
14 - .form-group.field
15 - = f.label :description
16 - = f.text_area :description, class: 'form-control'
17 - .form-group.field
18 - = f.label :public
19 - = f.text_field :public, class: 'form-control'
20 - .actions
21 = f.submit 'Save', class: 'btn btn-primary'
7 = f.submit 'Save', class: 'btn btn-primary'
22 - .col-md-6
@@ -1,26 +1,26
1 %h1 Tags
1 %h1 Tags
2
2
3 = link_to 'New Tag', new_tag_path, class: 'btn btn-success'
3 = link_to 'New Tag', new_tag_path, class: 'btn btn-success'
4
4
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 Public
10 %th Public
11 %th
11 %th
12 %th
12 %th
13 %th
13 %th
14
14
15 %tbody
15 %tbody
16 - @tags.each do |tag|
16 - @tags.each do |tag|
17 %tr
17 %tr
18 %td= tag.name
18 %td= tag.name
19 %td= tag.description
19 %td= tag.description
20 %td= tag.public
20 %td= tag.public
21 - %td= link_to 'Show', tag
21 + %td= link_to 'Show', tag, class: 'btn btn-info'
22 - %td= link_to 'Edit', edit_tag_path(tag)
22 + %td= link_to 'Edit', edit_tag_path(tag), class: 'btn btn-info'
23 - %td= link_to 'Destroy', tag, :method => :delete, :data => { :confirm => 'Are you sure?' }
23 + %td= button_to 'Destroy', tag, :method => :delete, :data => { :confirm => 'Are you sure?' }, class: 'btn btn-danger'
24
24
25 %br
25 %br
26
26
@@ -1,91 +1,91
1 %h1 Users
1 %h1 Users
2
2
3 .card.border-success.mb-3
3 .card.border-success.mb-3
4 .card-header.text-bg-success.border-success
4 .card-header.text-bg-success.border-success
5 Quick Add
5 Quick Add
6 .card-body
6 .card-body
7 = form_with url: user_admin_index_path, scope: :user, class: 'row row-cols-lg-auto g-3 align-items-center' do |f|
7 = form_with url: user_admin_index_path, scope: :user, class: 'row row-cols-lg-auto g-3 align-items-center' do |f|
8 .col-12
8 .col-12
9 = f.text_field 'login', :size => 10,class: 'form-control', placeholder: 'login'
9 = f.text_field 'login', :size => 10,class: 'form-control', placeholder: 'login'
10 .form-group
10 .form-group
11 = f.text_field 'full_name', :size => 10,class: 'form-control', placeholder: 'full name'
11 = f.text_field 'full_name', :size => 10,class: 'form-control', placeholder: 'full name'
12 .form-group
12 .form-group
13 = f.password_field 'password', :size => 10,class: 'form-control', placeholder: 'password'
13 = f.password_field 'password', :size => 10,class: 'form-control', placeholder: 'password'
14 .form-group
14 .form-group
15 = f.password_field 'password_confirmation', :size => 10,class: 'form-control', placeholder: 'password confirmation'
15 = f.password_field 'password_confirmation', :size => 10,class: 'form-control', placeholder: 'password confirmation'
16 .form-group
16 .form-group
17 = f.text_field 'email', :size => 10,class: 'form-control', placeholder: 'email'
17 = f.text_field 'email', :size => 10,class: 'form-control', placeholder: 'email'
18 =submit_tag "Create", class: 'btn btn-success align-items-bottom'
18 =submit_tag "Create", class: 'btn btn-success align-items-bottom'
19
19
20 .card.border-success.mb-3
20 .card.border-success.mb-3
21 .card-header.text-bg-success.border-success
21 .card-header.text-bg-success.border-success
22 Import from site management
22 Import from site management
23 .card-body
23 .card-body
24 = form_with url: import_user_admin_index_path, :multipart => true do |f|
24 = form_with url: import_user_admin_index_path, :multipart => true do |f|
25 .row
25 .row
26 .col-auto
26 .col-auto
27 = f.label :file, 'File:', class: 'col-form-label'
27 = f.label :file, 'File:', class: 'col-form-label'
28 .col-auto
28 .col-auto
29 = f.file_field :file, class: 'form-control'
29 = f.file_field :file, class: 'form-control'
30 .col-auto
30 .col-auto
31 = f.submit 'Submit', class: 'btn btn-secondary'
31 = f.submit 'Submit', class: 'btn btn-secondary'
32
32
33
33
34 %p
34 %p
35 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
35 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
36 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
36 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
37 = link_to 'Bulk Manage', { action: :bulk_manage} , { class: 'btn btn-secondary btn-info'}
37 = link_to 'Bulk Manage', { action: :bulk_manage} , { class: 'btn btn-secondary btn-info'}
38 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-secondary '}
38 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-secondary '}
39 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-secondary '}
39 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-secondary '}
40 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-secondary '}
40 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-secondary '}
41 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-secondary '}
41 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-secondary '}
42
42
43 - if GraderConfiguration.multicontests?
43 - if GraderConfiguration.multicontests?
44 %br/
44 %br/
45 %b Multi-contest:
45 %b Multi-contest:
46 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
46 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
47 View users in:
47 View users in:
48 - @contests.each do |contest|
48 - @contests.each do |contest|
49 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
49 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
50 = link_to "[no contest]", :action => 'contests', :id => 'none'
50 = link_to "[no contest]", :action => 'contests', :id => 'none'
51
51
52 %table.table.table-hover.table-condense.datatable
52 %table.table.table-hover.table-condense.datatable
53 %thead
53 %thead
54 %th Login
54 %th Login
55 %th Full name
55 %th Full name
56 %th email
56 %th email
57 %th Remark
57 %th Remark
58 %th
58 %th
59 Activated
59 Activated
60 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
60 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
61 %th
61 %th
62 Enabled
62 Enabled
63 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
63 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
64 %th Last IP
64 %th Last IP
65 %th
65 %th
66 %th
66 %th
67 %th
67 %th
68 %th
68 %th
69 - for user in @users
69 - for user in @users
70 %tr
70 %tr
71 %td= link_to user.login, stat_user_path(user)
71 %td= link_to user.login, stat_user_path(user)
72 %td= user.full_name
72 %td= user.full_name
73 %td= user.email
73 %td= user.email
74 %td= user.remark
74 %td= user.remark
75 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
75 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
76 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
76 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
77 %td= user.last_ip
77 %td= user.last_ip
78 %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-secondary btn-sm btn-block'
78 %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-secondary btn-sm btn-block'
79 - %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-secondary btn-sm btn-block'
79 + %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-info btn-sm btn-block'
80 - %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-secondary btn-sm btn-block'
80 + %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-info btn-sm btn-block'
81 %td= link_to 'Destroy', {action: :destroy, id: user}, data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-sm btn-block'
81 %td= link_to 'Destroy', {action: :destroy, id: user}, data: {confirm: 'Are you sure?'}, method: :delete, class: 'btn btn-danger btn-sm btn-block'
82 %br/
82 %br/
83 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
83 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
84 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
84 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
85
85
86 :javascript
86 :javascript
87 $(document).on('import-map-loaded',(e) => {
87 $(document).on('import-map-loaded',(e) => {
88 $('.datatable').DataTable({
88 $('.datatable').DataTable({
89 'pageLength': 50
89 'pageLength': 50
90 });
90 });
91 })
91 })
@@ -1,346 +1,357
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 # This file is the source Rails uses to define your schema when running `bin/rails
5 # This file is the source Rails uses to define your schema when running `bin/rails
6 # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
6 # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7 # be faster and is potentially less error prone than running all of your
7 # be faster and is potentially less error prone than running all of your
8 # migrations from scratch. Old migrations may fail to apply correctly if those
8 # migrations from scratch. Old migrations may fail to apply correctly if those
9 # migrations use external dependencies or application code.
9 # migrations use external dependencies or application code.
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[7.0].define(version: 2022_09_27_074644) do
13 ActiveRecord::Schema[7.0].define(version: 2022_09_27_074644) do
14 - create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
14 + create_table "active_storage_attachments", charset: "latin1", force: :cascade do |t|
15 t.string "name", null: false
15 t.string "name", null: false
16 t.string "record_type", null: false
16 t.string "record_type", null: false
17 t.bigint "record_id", null: false
17 t.bigint "record_id", null: false
18 t.bigint "blob_id", null: false
18 t.bigint "blob_id", null: false
19 t.datetime "created_at", null: false
19 t.datetime "created_at", null: false
20 t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
20 t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
21 t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
21 t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
22 end
22 end
23
23
24 - create_table "active_storage_blobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
24 + create_table "active_storage_blobs", charset: "latin1", force: :cascade do |t|
25 t.string "key", null: false
25 t.string "key", null: false
26 t.string "filename", null: false
26 t.string "filename", null: false
27 t.string "content_type"
27 t.string "content_type"
28 t.text "metadata"
28 t.text "metadata"
29 t.string "service_name", null: false
29 t.string "service_name", null: false
30 t.bigint "byte_size", null: false
30 t.bigint "byte_size", null: false
31 t.string "checksum"
31 t.string "checksum"
32 t.datetime "created_at", null: false
32 t.datetime "created_at", null: false
33 t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
33 t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
34 end
34 end
35
35
36 - create_table "active_storage_variant_records", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
36 + create_table "active_storage_variant_records", charset: "latin1", force: :cascade do |t|
37 t.bigint "blob_id", null: false
37 t.bigint "blob_id", null: false
38 t.string "variation_digest", null: false
38 t.string "variation_digest", null: false
39 t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
39 t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
40 end
40 end
41
41
42 - create_table "announcements", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
42 + create_table "announcements", id: :integer, charset: "utf8", force: :cascade do |t|
43 t.string "author"
43 t.string "author"
44 - t.text "body"
44 + t.text "body", size: :medium
45 t.boolean "published"
45 t.boolean "published"
46 t.datetime "created_at", precision: nil, null: false
46 t.datetime "created_at", precision: nil, null: false
47 t.datetime "updated_at", precision: nil, null: false
47 t.datetime "updated_at", precision: nil, null: false
48 t.boolean "frontpage", default: false
48 t.boolean "frontpage", default: false
49 t.boolean "contest_only", default: false
49 t.boolean "contest_only", default: false
50 t.string "title"
50 t.string "title"
51 t.string "notes"
51 t.string "notes"
52 t.boolean "on_nav_bar", default: false
52 t.boolean "on_nav_bar", default: false
53 end
53 end
54
54
55 - create_table "contests", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
55 + create_table "contests", id: :integer, charset: "utf8", force: :cascade do |t|
56 t.string "title"
56 t.string "title"
57 t.boolean "enabled"
57 t.boolean "enabled"
58 t.datetime "created_at", precision: nil, null: false
58 t.datetime "created_at", precision: nil, null: false
59 t.datetime "updated_at", precision: nil, null: false
59 t.datetime "updated_at", precision: nil, null: false
60 t.string "name"
60 t.string "name"
61 end
61 end
62
62
63 - create_table "contests_problems", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
63 + create_table "contests_problems", id: false, charset: "utf8", force: :cascade do |t|
64 t.integer "contest_id"
64 t.integer "contest_id"
65 t.integer "problem_id"
65 t.integer "problem_id"
66 end
66 end
67
67
68 - create_table "contests_users", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
68 + create_table "contests_users", id: false, charset: "utf8", force: :cascade do |t|
69 t.integer "contest_id"
69 t.integer "contest_id"
70 t.integer "user_id"
70 t.integer "user_id"
71 end
71 end
72
72
73 - create_table "countries", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
73 + create_table "countries", id: :integer, charset: "utf8", force: :cascade do |t|
74 t.string "name"
74 t.string "name"
75 t.datetime "created_at", precision: nil, null: false
75 t.datetime "created_at", precision: nil, null: false
76 t.datetime "updated_at", precision: nil, null: false
76 t.datetime "updated_at", precision: nil, null: false
77 end
77 end
78
78
79 - create_table "descriptions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
79 + create_table "descriptions", id: :integer, charset: "utf8", force: :cascade do |t|
80 - t.text "body"
80 + t.text "body", size: :medium
81 t.boolean "markdowned"
81 t.boolean "markdowned"
82 t.datetime "created_at", precision: nil, null: false
82 t.datetime "created_at", precision: nil, null: false
83 t.datetime "updated_at", precision: nil, null: false
83 t.datetime "updated_at", precision: nil, null: false
84 end
84 end
85
85
86 - create_table "grader_configurations", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
86 + create_table "grader_configurations", id: :integer, charset: "utf8", force: :cascade do |t|
87 t.string "key"
87 t.string "key"
88 t.string "value_type"
88 t.string "value_type"
89 t.string "value"
89 t.string "value"
90 t.datetime "created_at", precision: nil, null: false
90 t.datetime "created_at", precision: nil, null: false
91 t.datetime "updated_at", precision: nil, null: false
91 t.datetime "updated_at", precision: nil, null: false
92 - t.text "description"
92 + t.text "description", size: :medium
93 end
93 end
94
94
95 - create_table "grader_processes", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
95 + create_table "grader_processes", id: :integer, charset: "utf8", force: :cascade do |t|
96 t.string "host"
96 t.string "host"
97 t.integer "pid"
97 t.integer "pid"
98 t.string "mode"
98 t.string "mode"
99 t.boolean "active"
99 t.boolean "active"
100 t.datetime "created_at", precision: nil, null: false
100 t.datetime "created_at", precision: nil, null: false
101 t.datetime "updated_at", precision: nil, null: false
101 t.datetime "updated_at", precision: nil, null: false
102 t.integer "task_id"
102 t.integer "task_id"
103 t.string "task_type"
103 t.string "task_type"
104 t.boolean "terminated"
104 t.boolean "terminated"
105 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
105 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
106 end
106 end
107
107
108 create_table "groups", id: :integer, charset: "latin1", force: :cascade do |t|
108 create_table "groups", id: :integer, charset: "latin1", force: :cascade do |t|
109 t.string "name"
109 t.string "name"
110 t.string "description"
110 t.string "description"
111 t.boolean "enabled", default: true
111 t.boolean "enabled", default: true
112 end
112 end
113
113
114 create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t|
114 create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t|
115 t.integer "problem_id", null: false
115 t.integer "problem_id", null: false
116 t.integer "group_id", null: false
116 t.integer "group_id", null: false
117 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
117 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
118 end
118 end
119
119
120 create_table "groups_users", charset: "latin1", force: :cascade do |t|
120 create_table "groups_users", charset: "latin1", force: :cascade do |t|
121 t.integer "group_id", null: false
121 t.integer "group_id", null: false
122 t.integer "user_id", null: false
122 t.integer "user_id", null: false
123 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
123 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
124 end
124 end
125
125
126 - create_table "heart_beats", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
126 + create_table "heart_beats", id: :integer, charset: "latin1", force: :cascade do |t|
127 t.integer "user_id"
127 t.integer "user_id"
128 t.string "ip_address"
128 t.string "ip_address"
129 t.datetime "created_at", precision: nil, null: false
129 t.datetime "created_at", precision: nil, null: false
130 t.datetime "updated_at", precision: nil, null: false
130 t.datetime "updated_at", precision: nil, null: false
131 t.string "status"
131 t.string "status"
132 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
132 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
133 end
133 end
134
134
135 - create_table "languages", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
135 + create_table "languages", id: :integer, charset: "utf8", force: :cascade do |t|
136 t.string "name", limit: 10
136 t.string "name", limit: 10
137 t.string "pretty_name"
137 t.string "pretty_name"
138 t.string "ext", limit: 10
138 t.string "ext", limit: 10
139 t.string "common_ext"
139 t.string "common_ext"
140 end
140 end
141
141
142 - create_table "logins", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
142 + create_table "logins", id: :integer, charset: "latin1", force: :cascade do |t|
143 t.integer "user_id"
143 t.integer "user_id"
144 t.string "ip_address"
144 t.string "ip_address"
145 t.datetime "created_at", precision: nil, null: false
145 t.datetime "created_at", precision: nil, null: false
146 t.datetime "updated_at", precision: nil, null: false
146 t.datetime "updated_at", precision: nil, null: false
147 t.index ["user_id"], name: "index_logins_on_user_id"
147 t.index ["user_id"], name: "index_logins_on_user_id"
148 end
148 end
149
149
150 - create_table "messages", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
150 + create_table "messages", id: :integer, charset: "utf8", force: :cascade do |t|
151 t.integer "sender_id"
151 t.integer "sender_id"
152 t.integer "receiver_id"
152 t.integer "receiver_id"
153 t.integer "replying_message_id"
153 t.integer "replying_message_id"
154 - t.text "body"
154 + t.text "body", size: :medium
155 t.boolean "replied"
155 t.boolean "replied"
156 t.datetime "created_at", precision: nil, null: false
156 t.datetime "created_at", precision: nil, null: false
157 t.datetime "updated_at", precision: nil, null: false
157 t.datetime "updated_at", precision: nil, null: false
158 end
158 end
159
159
160 - create_table "problems", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
160 + create_table "problems", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
161 - t.string "name", limit: 30
161 + t.string "name", limit: 100
162 t.string "full_name"
162 t.string "full_name"
163 t.integer "full_score"
163 t.integer "full_score"
164 t.date "date_added"
164 t.date "date_added"
165 t.boolean "available"
165 t.boolean "available"
166 t.string "url"
166 t.string "url"
167 t.integer "description_id"
167 t.integer "description_id"
168 t.boolean "test_allowed"
168 t.boolean "test_allowed"
169 t.boolean "output_only"
169 t.boolean "output_only"
170 t.string "description_filename"
170 t.string "description_filename"
171 t.boolean "view_testcase"
171 t.boolean "view_testcase"
172 t.integer "difficulty"
172 t.integer "difficulty"
173 t.text "description"
173 t.text "description"
174 t.boolean "markdown"
174 t.boolean "markdown"
175 end
175 end
176
176
177 - create_table "problems_tags", id: :integer, charset: "latin1", force: :cascade do |t|
177 + create_table "problems_tags", id: :bigint, default: nil, charset: "latin1", force: :cascade do |t|
178 - t.integer "problem_id"
178 + t.bigint "problem_id"
179 t.integer "tag_id"
179 t.integer "tag_id"
180 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
180 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
181 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
181 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
182 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
182 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
183 end
183 end
184
184
185 - create_table "rights", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
185 + create_table "rights", id: :integer, charset: "utf8", force: :cascade do |t|
186 t.string "name"
186 t.string "name"
187 t.string "controller"
187 t.string "controller"
188 t.string "action"
188 t.string "action"
189 end
189 end
190
190
191 - create_table "rights_roles", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
191 + create_table "rights_roles", id: false, charset: "utf8", force: :cascade do |t|
192 t.integer "right_id"
192 t.integer "right_id"
193 t.integer "role_id"
193 t.integer "role_id"
194 t.index ["role_id"], name: "index_rights_roles_on_role_id"
194 t.index ["role_id"], name: "index_rights_roles_on_role_id"
195 end
195 end
196
196
197 - create_table "roles", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
197 + create_table "roles", id: :integer, charset: "utf8", force: :cascade do |t|
198 t.string "name"
198 t.string "name"
199 end
199 end
200
200
201 - create_table "roles_users", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
201 + create_table "roles_users", id: false, charset: "utf8", force: :cascade do |t|
202 t.integer "role_id"
202 t.integer "role_id"
203 t.integer "user_id"
203 t.integer "user_id"
204 t.index ["user_id"], name: "index_roles_users_on_user_id"
204 t.index ["user_id"], name: "index_roles_users_on_user_id"
205 end
205 end
206
206
207 - create_table "sessions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
207 + create_table "sessions", id: :integer, charset: "utf8", force: :cascade do |t|
208 t.string "session_id"
208 t.string "session_id"
209 - t.text "data"
209 + t.text "data", size: :medium
210 t.datetime "updated_at", precision: nil
210 t.datetime "updated_at", precision: nil
211 t.index ["session_id"], name: "index_sessions_on_session_id"
211 t.index ["session_id"], name: "index_sessions_on_session_id"
212 t.index ["updated_at"], name: "index_sessions_on_updated_at"
212 t.index ["updated_at"], name: "index_sessions_on_updated_at"
213 end
213 end
214
214
215 - create_table "sites", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
215 + create_table "sites", id: :integer, charset: "utf8", force: :cascade do |t|
216 t.string "name"
216 t.string "name"
217 t.boolean "started"
217 t.boolean "started"
218 t.datetime "start_time", precision: nil
218 t.datetime "start_time", precision: nil
219 t.datetime "created_at", precision: nil, null: false
219 t.datetime "created_at", precision: nil, null: false
220 t.datetime "updated_at", precision: nil, null: false
220 t.datetime "updated_at", precision: nil, null: false
221 t.integer "country_id"
221 t.integer "country_id"
222 t.string "password"
222 t.string "password"
223 end
223 end
224
224
225 - create_table "submission_view_logs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
225 + create_table "solutions", charset: "latin1", force: :cascade do |t|
226 + t.string "solution"
227 + t.bigint "problem_id"
228 + t.bigint "submission_id"
229 + t.integer "type"
230 + t.index ["problem_id"], name: "index_solutions_on_problem_id"
231 + t.index ["submission_id"], name: "index_solutions_on_submission_id"
232 + end
233 +
234 + create_table "submission_view_logs", id: :integer, charset: "latin1", force: :cascade do |t|
226 t.integer "user_id"
235 t.integer "user_id"
227 t.integer "submission_id"
236 t.integer "submission_id"
228 t.datetime "created_at", precision: nil, null: false
237 t.datetime "created_at", precision: nil, null: false
229 t.datetime "updated_at", precision: nil, null: false
238 t.datetime "updated_at", precision: nil, null: false
230 end
239 end
231
240
232 - create_table "submissions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
241 + create_table "submissions", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
233 t.integer "user_id"
242 t.integer "user_id"
234 t.integer "problem_id"
243 t.integer "problem_id"
235 t.integer "language_id"
244 t.integer "language_id"
236 t.text "source", size: :medium
245 t.text "source", size: :medium
237 t.binary "binary"
246 t.binary "binary"
238 t.datetime "submitted_at", precision: nil
247 t.datetime "submitted_at", precision: nil
239 t.datetime "compiled_at", precision: nil
248 t.datetime "compiled_at", precision: nil
240 - t.text "compiler_message"
249 + t.text "compiler_message", size: :medium
241 t.datetime "graded_at", precision: nil
250 t.datetime "graded_at", precision: nil
242 t.integer "points"
251 t.integer "points"
243 - t.text "grader_comment"
252 + t.text "grader_comment", size: :medium
244 t.integer "number"
253 t.integer "number"
245 t.string "source_filename"
254 t.string "source_filename"
246 t.float "max_runtime"
255 t.float "max_runtime"
247 t.integer "peak_memory"
256 t.integer "peak_memory"
248 t.integer "effective_code_length"
257 t.integer "effective_code_length"
249 t.string "ip_address"
258 t.string "ip_address"
250 t.integer "tag", default: 0
259 t.integer "tag", default: 0
251 t.index ["submitted_at"], name: "index_submissions_on_submitted_at"
260 t.index ["submitted_at"], name: "index_submissions_on_submitted_at"
252 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
261 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
253 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
262 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
254 end
263 end
255
264
256 create_table "tags", id: :integer, charset: "latin1", force: :cascade do |t|
265 create_table "tags", id: :integer, charset: "latin1", force: :cascade do |t|
257 t.string "name", null: false
266 t.string "name", null: false
258 t.text "description"
267 t.text "description"
259 t.boolean "public"
268 t.boolean "public"
260 t.datetime "created_at", precision: nil, null: false
269 t.datetime "created_at", precision: nil, null: false
261 t.datetime "updated_at", precision: nil, null: false
270 t.datetime "updated_at", precision: nil, null: false
262 end
271 end
263
272
264 - create_table "tasks", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
273 + create_table "tasks", id: :integer, charset: "utf8", force: :cascade do |t|
265 t.integer "submission_id"
274 t.integer "submission_id"
266 t.datetime "created_at", precision: nil
275 t.datetime "created_at", precision: nil
267 t.integer "status"
276 t.integer "status"
268 t.datetime "updated_at", precision: nil
277 t.datetime "updated_at", precision: nil
269 t.index ["status"], name: "index_tasks_on_status"
278 t.index ["status"], name: "index_tasks_on_status"
270 t.index ["submission_id"], name: "index_tasks_on_submission_id"
279 t.index ["submission_id"], name: "index_tasks_on_submission_id"
271 end
280 end
272
281
273 - create_table "test_pairs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
282 + create_table "test_pairs", id: :integer, charset: "utf8", force: :cascade do |t|
274 t.integer "problem_id"
283 t.integer "problem_id"
275 - t.text "input", size: :medium
284 + t.text "input", size: :long
276 - t.text "solution", size: :medium
285 + t.text "solution", size: :long
277 t.datetime "created_at", precision: nil, null: false
286 t.datetime "created_at", precision: nil, null: false
278 t.datetime "updated_at", precision: nil, null: false
287 t.datetime "updated_at", precision: nil, null: false
279 end
288 end
280
289
281 - create_table "test_requests", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
290 + create_table "test_requests", id: :integer, charset: "utf8", force: :cascade do |t|
282 t.integer "user_id"
291 t.integer "user_id"
283 t.integer "problem_id"
292 t.integer "problem_id"
284 t.integer "submission_id"
293 t.integer "submission_id"
285 t.string "input_file_name"
294 t.string "input_file_name"
286 t.string "output_file_name"
295 t.string "output_file_name"
287 t.string "running_stat"
296 t.string "running_stat"
288 t.integer "status"
297 t.integer "status"
289 t.datetime "updated_at", precision: nil, null: false
298 t.datetime "updated_at", precision: nil, null: false
290 t.datetime "submitted_at", precision: nil
299 t.datetime "submitted_at", precision: nil
291 t.datetime "compiled_at", precision: nil
300 t.datetime "compiled_at", precision: nil
292 - t.text "compiler_message"
301 + t.text "compiler_message", size: :medium
293 t.datetime "graded_at", precision: nil
302 t.datetime "graded_at", precision: nil
294 t.string "grader_comment"
303 t.string "grader_comment"
295 t.datetime "created_at", precision: nil, null: false
304 t.datetime "created_at", precision: nil, null: false
296 t.float "running_time"
305 t.float "running_time"
297 t.string "exit_status"
306 t.string "exit_status"
298 t.integer "memory_usage"
307 t.integer "memory_usage"
299 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
308 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
300 end
309 end
301
310
302 create_table "testcases", id: :integer, charset: "latin1", force: :cascade do |t|
311 create_table "testcases", id: :integer, charset: "latin1", force: :cascade do |t|
303 t.integer "problem_id"
312 t.integer "problem_id"
304 t.integer "num"
313 t.integer "num"
305 t.integer "group"
314 t.integer "group"
306 t.integer "score"
315 t.integer "score"
307 t.text "input", size: :long
316 t.text "input", size: :long
308 t.text "sol", size: :long
317 t.text "sol", size: :long
309 - t.datetime "created_at", precision: nil
318 + t.datetime "created_at", precision: nil, null: false
310 - t.datetime "updated_at", precision: nil
319 + t.datetime "updated_at", precision: nil, null: false
311 t.index ["problem_id"], name: "index_testcases_on_problem_id"
320 t.index ["problem_id"], name: "index_testcases_on_problem_id"
312 end
321 end
313
322
314 - create_table "user_contest_stats", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
323 + create_table "user_contest_stats", id: :integer, charset: "utf8", force: :cascade do |t|
315 t.integer "user_id"
324 t.integer "user_id"
316 t.datetime "started_at", precision: nil
325 t.datetime "started_at", precision: nil
317 t.datetime "created_at", precision: nil, null: false
326 t.datetime "created_at", precision: nil, null: false
318 t.datetime "updated_at", precision: nil, null: false
327 t.datetime "updated_at", precision: nil, null: false
319 t.boolean "forced_logout"
328 t.boolean "forced_logout"
320 end
329 end
321
330
322 - create_table "users", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
331 + create_table "users", id: :integer, charset: "utf8", force: :cascade do |t|
323 t.string "login", limit: 50
332 t.string "login", limit: 50
324 t.string "full_name"
333 t.string "full_name"
325 t.string "hashed_password"
334 t.string "hashed_password"
326 t.string "salt", limit: 5
335 t.string "salt", limit: 5
327 t.string "alias"
336 t.string "alias"
328 t.string "email"
337 t.string "email"
329 t.integer "site_id"
338 t.integer "site_id"
330 t.integer "country_id"
339 t.integer "country_id"
331 t.boolean "activated", default: false
340 t.boolean "activated", default: false
332 t.datetime "created_at", precision: nil
341 t.datetime "created_at", precision: nil
333 t.datetime "updated_at", precision: nil
342 t.datetime "updated_at", precision: nil
343 + t.string "section"
334 t.boolean "enabled", default: true
344 t.boolean "enabled", default: true
335 t.string "remark"
345 t.string "remark"
336 t.string "last_ip"
346 t.string "last_ip"
337 - t.string "section"
338 t.integer "default_language"
347 t.integer "default_language"
339 t.index ["login"], name: "index_users_on_login", unique: true
348 t.index ["login"], name: "index_users_on_login", unique: true
340 end
349 end
341
350
342 add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
351 add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
343 add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
352 add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
344 add_foreign_key "problems_tags", "problems"
353 add_foreign_key "problems_tags", "problems"
345 add_foreign_key "problems_tags", "tags"
354 add_foreign_key "problems_tags", "tags"
355 + add_foreign_key "solutions", "problems"
356 + add_foreign_key "solutions", "submissions"
346 end
357 end
You need to be logged in to leave comments. Login now