Description:
MERGED 308:HEAD from http://theory.cpe.ku.ac.th/grader/web/branches/ytopc08-2/, removed some registration info git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@359 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r162:39cf7851046e - - 70 files changed: 899 inserted, 391 deleted

@@ -0,0 +1,4
1 + *~
2 + log
3 + config/environment.rb
4 + config/database.yml
@@ -0,0 +1,76
1 + # Filters added to this controller apply to all controllers in the application.
2 + # Likewise, all the methods added will be available for all controllers.
3 +
4 + class ApplicationController < ActionController::Base
5 + # Pick a unique cookie name to distinguish our session data from others'
6 + session :session_key => '_grader_session_id'
7 +
8 + SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
9 +
10 + def admin_authorization
11 + return false unless authenticate
12 + user = User.find(session[:user_id], :include => ['roles'])
13 + redirect_to :controller => 'main', :action => 'login' unless user.admin?
14 + end
15 +
16 + def authorization_by_roles(allowed_roles)
17 + return false unless authenticate
18 + user = User.find(session[:user_id])
19 + unless user.roles.detect { |role| allowed_roles.member?(role.name) }
20 + flash[:notice] = 'You are not authorized to view the page you requested'
21 + redirect_to :controller => 'main', :action => 'login'
22 + return false
23 + end
24 + end
25 +
26 + protected
27 +
28 + def authenticate
29 + unless session[:user_id]
30 + redirect_to :controller => 'main', :action => 'login'
31 + return false
32 + end
33 +
34 + #Configuration.reload
35 + # check if run in single user mode
36 + if (Configuration[SINGLE_USER_MODE_CONF_KEY])
37 + user = User.find(session[:user_id])
38 + if user==nil or user.login != 'root'
39 + redirect_to :controller => 'main', :action => 'login'
40 + return false
41 + end
42 + end
43 +
44 + return true
45 + end
46 +
47 + def authorization
48 + return false unless authenticate
49 + user = User.find(session[:user_id])
50 + unless user.roles.detect { |role|
51 + role.rights.detect{ |right|
52 + right.controller == self.class.controller_name and
53 + (right.action == 'all' or right.action == action_name)
54 + }
55 + }
56 + flash[:notice] = 'You are not authorized to view the page you requested'
57 + #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
58 + redirect_to :controller => 'main', :action => 'login'
59 + return false
60 + end
61 + end
62 +
63 + def verify_time_limit
64 + return true if session[:user_id]==nil
65 + user = User.find(session[:user_id], :include => :site)
66 + return true if user==nil or user.site == nil
67 + if user.site.finished?
68 + flash[:notice] = 'Error: the contest on your site is over.'
69 + redirect_to :back
70 + return false
71 + end
72 + return true
73 + end
74 +
75 + end
76 +
@@ -0,0 +1,39
1 + %script{:type => 'text/javascript'}
2 + var siteList = new Array();
3 + - @countries.each do |country|
4 + = "siteList[#{country.id}] = new Array();"
5 + - country.sites.each do |site|
6 + = "siteList[#{country.id}][#{site.id}] = \"#{site.name}\";"
7 +
8 + var allSiteList = new Array();
9 + - @site_select.each do |sel|
10 + = "allSiteList[#{sel[1]}]=\"#{sel[0]}\";"
11 +
12 + %script{:type => 'text/javascript', :src => '/javascripts/site_update.js'}
13 +
14 + %div{ :style => "border: solid 1px gray; padding: 2px; background: #f0f0f0;"}
15 + %h2 For Site Administrator.
16 +
17 + - if @default_site
18 + - form_for :login, nil, :url => {:controller => 'login', :action => 'site_login'} do |f|
19 + %b Log in for default site.
20 + = f.hidden_field :site_id, :value => @default_site.id
21 + %br/
22 + Password:
23 + = f.password_field :password
24 + = submit_tag "Site Administrator Login"
25 +
26 + - else
27 + Please select your country and site and login.
28 + - form_for :login, nil, :url => {:controller => 'login', :action => 'site_login'} do |f|
29 + Country:
30 + = select :site_country, :id, @country_select_with_all, {}, {:onchange => "updateSiteList();", :onclick => "updateSiteList();" }
31 + Site:
32 + = select :login, :site_id, @site_select
33 + %br/
34 + Password:
35 + = f.password_field :password
36 + = submit_tag "Site Administrator Login"
37 +
38 + %script{:type => 'text/javascript'}
39 + updateSiteList();
@@ -0,0 +1,118
1 + # Sample localization file for English. Add more files in this directory for other locales.
2 + # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 +
4 + en:
5 + cancel: 'Cancel'
6 +
7 + login_label: 'Login'
8 + full_name_label: 'Full name'
9 + email_label: 'E-mail'
10 + password_label: 'Password'
11 +
12 + go_ahead_to: "Go ahead to"
13 + go_back_to: "Go back to"
14 + login_page: "login page"
15 + home_page: "home page"
16 +
17 + menu:
18 + main: 'Main'
19 + messages: 'Messages'
20 + tasks: 'Tasks'
21 + submissions: 'Submissions'
22 + test: 'Test Interface'
23 + help: 'Help'
24 + settings: 'Settings'
25 + log_out: 'Log out'
26 +
27 + title_bar:
28 + current_time: "Current time is"
29 + remaining_time: "Time left: "
30 + contest_not_started: "The contest has not started."
31 +
32 + login:
33 + message: 'Please login to see the problem list'
34 + login_submit: 'Login'
35 + participation: 'Want to participate?'
36 + please: 'Please'
37 + register: 'register'
38 +
39 + main:
40 + start_soon: "The contest at your site will start soon. Please wait."
41 + specified_in_header: "Specified in header"
42 +
43 + problem_desc: "desc"
44 + submitted_at: "Submitted at"
45 + graded_at: "Graded at"
46 + score: "score: "
47 + cmp_msg: "compiler msg"
48 + src_link: "src"
49 + submissions_link: "submissions"
50 +
51 + test:
52 + title: "Test Interface"
53 + intro: "You can test your submission with your own test data on the grading environment using this test interface."
54 + disabled_at_end_announcement: "<b>Note:</b> Test interface will be disabled in the last 30 minutes of the contest time on your site."
55 +
56 + registration:
57 + title: "New user registration"
58 + successful_title: "Registration successful"
59 +
60 + login_guide: "Only a-z, A-Z, 0-9 and _. Can be at most 20 characters long"
61 + email_guide: "Please make sure that your e-mail is correct.<br/>You'll need to verify your account by email."
62 + register: "Register"
63 +
64 + email_body: "Hello {{full_name}},
65 +
66 + You have registered for {{contest_name}}
67 +
68 + Your login is: {{login}}
69 +
70 + Your password is: {{password}}
71 +
72 + Please follow the link:
73 +
74 + {{activation_url}}
75 +
76 + to activate your user account.
77 +
78 + If you did not register, please ignore this e-mail
79 + and report this event to {{admin_email}}.
80 +
81 + Thanks!"
82 +
83 + email_sent: "We have sent a confimation message to your e-mail. (Please also check the Junk mail box."
84 + email_verify_at: "Please check at {{email}} and confirm."
85 +
86 + activation_sucessful_title: "User activated"
87 + account_activated: "Your account has been activated."
88 +
89 + activation_failed_title: "Activation failed"
90 +
91 + errors:
92 + header: "Errors occured during registration"
93 + email:
94 + title: "Errors in sending registration confirmation"
95 + expl: "<h2>Your user account has been created, but the system cannot send you the confirmation e-mail.</h2>
96 + Maybe there's a problem in the configuration. Please report the admin at {{email}}.<br/>Thank you!"
97 + activation:
98 + email_exists: "A user with this E-mail exists."
99 + invalid: "Your activation code is invalid. Please check again."
100 +
101 + help:
102 + how_to_submit: "How to submit"
103 + must_specify_language: "You <b>must</b> specify the language you are using in your program header. You can optionally specify the task you are submitting to."
104 + list_available_language: "The possible language options are <tt>C</tt>, <tt>C++</tt>, and <tt>Pascal</tt>. The follow are examples."
105 + accept_only_language_specified: "The server <b>will not</b> accept your submission, if you do not specify the language."
106 + specifying_task: "Optionally, you can also specify the task with <tt>TASK:</tt> <i>taskname</i>. On the first page, the taskname for each task is shown in parentheses."
107 + example_cpp: "For example, suppose you are using <tt>C++</tt> to write task <b>mobiles</b>, you put the following on top of your source code."
108 + example_pas: "If you are using <tt>Pascal</tt> to write the same task, you'll use"
109 + ask_questions_at_messages: "If you have any problems, you can ask at [<a href=\"{{url}}\">{{message_link_name}}</a>]."
110 +
111 + activerecord:
112 + attributes:
113 + user:
114 + login: "login"
115 + full_name: "full name"
116 + email: "e-mail"
117 + province: "province"
118 +
@@ -0,0 +1,106
1 + {
2 + :'th' => {
3 + :date => {
4 + :formats => {
5 + :default => lambda { |date| "%d-%m-#{date.year+543}" },
6 + :short => "%e %b",
7 + :long => lambda { |date| "%e %B #{date.year+543}" },
8 + :long_ordinal => lambda { |date| "%e %B #{date.year+543}" },
9 + :only_day => "%e"
10 + },
11 + :day_names => %w(อาทิตย์ จันทร์ อังคาร พุธ พฤหัสบดี ศุกร์ เสาร์),
12 + :abbr_day_names => %w(อา จ อ พ พฤ ศ ส),
13 + :month_names => [nil] + %w(มกราคม กุมภาพันธ์ มีนาคม เมษายน พฤษภาคม มิถุนายน กรกฎาคม สิงหาคม กันยายน ตุลาคม พฤศจิกายน ธันวาคม),
14 + :abbr_month_names => [nil] + %w(ม.ค. ก.พ. มี.ค. เม.ย. พ.ค. มิ.ย. ก.ค. ส.ค. ก.ย. ต.ค. พ.ย. ธ.ค.),
15 + :order => [:day, :month, :year]
16 + },
17 + :time => {
18 + :formats => {
19 + :default => lambda { |time| "%a %d %b #{time.year+543} %H:%M:%S %Z" },
20 + :time => "%H:%M น.",
21 + :short => "%d %b %H:%M น.",
22 + :long => lambda { |time| "%d %B #{time.year+543} %H:%M น." },
23 + :long_ordinal => lambda { |time| "%d %B #{time.year+543} %H:%M น." },
24 + :only_second => "%S"
25 + },
26 + :time_with_zone => {
27 + :formats => {
28 + :default => lambda { |time| "%Y-%m-%d %H:%M:%S #{time.formatted_offset(false, 'UTC')}" }
29 + }
30 + },
31 + :am => '',
32 + :pm => ''
33 + },
34 + :datetime => {
35 + :formats => {
36 + :default => "%Y-%m-%dT%H:%M:%S%Z"
37 + },
38 + :distance_in_words => {
39 + :half_a_minute => 'ครึ่งนาทีที่ผ่านมา',
40 + :less_than_x_seconds => 'น้อยกว่า {{count}} วินาที',
41 + :x_seconds => '{{count}} วินาที',
42 + :less_than_x_minutes => 'น้อยกว่า {{count}} วินาที',
43 + :x_minutes => '{{count}} นาที',
44 + :about_x_hours => 'ประมาณ {{count}} ชั่วโมง',
45 + :x_hours => '{{count}} ชั่วโมง',
46 + :about_x_days => 'ประมาณ {{count}} วัน',
47 + :x_days => '{{count}} วัน',
48 + :about_x_months => 'ประมาณ {{count}} เดือน',
49 + :x_months => '{{count}} เดือน',
50 + :about_x_years => 'ประมาณ {{count}} ปี',
51 + :over_x_years => 'เกิน {{count}} ปี'
52 + }
53 + },
54 +
55 + # numbers
56 + :number => {
57 + :format => {
58 + :precision => 3,
59 + :separator => '.',
60 + :delimiter => ','
61 + },
62 + :currency => {
63 + :format => {
64 + :unit => 'Baht',
65 + :precision => 2,
66 + :format => '%n %u'
67 + }
68 + },
69 + },
70 +
71 + # Active Record
72 + :activerecord => {
73 + :errors => {
74 + :template => {
75 + :header => {
76 + :one => "ไม่สามารถบันทึก {{model}} ได้เนื่องจากเกิดข้อผิดพลาด",
77 + :other => "ไม่สามารถบันทึก {{model}} ได้เนื่องจากเกิด {{count}} ข้อผิดพลาด"
78 + },
79 + :body => "โปรดตรวจสอบข้อมูลที่คุณกรอกในช่องต่อไปนี้:"
80 + },
81 + :messages => {
82 + :inclusion => "ไม่ได้อยู่ในลิสต์",
83 + :exclusion => "ถูกจองเอาไว้แล้ว",
84 + :invalid => "ไม่ถูกต้อง",
85 + :confirmation => "ไม่ตรงกับการยืนยัน",
86 + :accepted => "ต้องอยู่ในรูปแบบที่ยอมรับ",
87 + :empty => "ต้องไม้เว้นว่างเอาไว้",
88 + :blank => "ต้องไม่เว้นว่างเอาไว้",
89 + :too_long => "ยาวเกินไป (ต้องไม่เกิน {{count}} ตัวอักษร)",
90 + :too_short => "สั้นเกินไป (ต้องยาวกว่า {{count}} ตัวอักษร)",
91 + :wrong_length => "มีความยาวไม่ถูกต้อง (ต้องมีความยาว {{count}} ตัวอักษร)",
92 + :taken => "ถูกใช้ไปแล้ว",
93 + :not_a_number => "ไม่ใช่ตัวเลข",
94 + :greater_than => "ต้องมากกว่า {{count}}",
95 + :greater_than_or_equal_to => "ต้องมากกว่าหรือเท่ากับ {{count}}",
96 + :equal_to => "ต้องเท่ากับ {{count}}",
97 + :less_than => "ต้องน้อยกว่า {{count}}",
98 + :less_than_or_equal_to => "ต้องน้อยกว่าหรือเท่ากับ {{count}}",
99 + :odd => "ต้องเป็นเลขคี่",
100 + :even => "ต้องเป็นเลขคู่"
101 + }
102 + }
103 + }
104 + }
105 + }
106 +
@@ -0,0 +1,121
1 + # Sample localization file for English. Add more files in this directory for other locales.
2 + # See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points.
3 +
4 + th:
5 + cancel: 'ยกเลิก'
6 +
7 + login_label: 'ชื่อเข้าใช้ระบบ (login)'
8 + full_name_label: 'ชื่อเต็ม'
9 + email_label: 'E-mail'
10 + password_label: 'รหัสผ่าน'
11 +
12 + go_ahead_to: "ไปยัง"
13 + go_back_to: "กลับไปยัง"
14 + login_page: "หน้าเข้าใช้ระบบ"
15 + home_page: "หน้าแรก"
16 +
17 + menu:
18 + main: 'หน้าหลัก'
19 + messages: 'ข้อความ'
20 + tasks: 'โจทย์'
21 + submissions: 'โปรแกรมที่ส่ง'
22 + test: 'ทดสอบโปรแกรม'
23 + help: 'ความช่วยเหลือ'
24 + settings: 'เปลี่ยนรหัสผ่าน'
25 + log_out: 'ออกจากระบบ'
26 +
27 + title_bar:
28 + current_time: "เวลาปัจจุบันคือ"
29 + remaining_time: "เหลือเวลาอีก"
30 + contest_not_started: "ยังไม่เริ่มแข่งขัน"
31 +
32 + login:
33 + message: 'กรุณา login เพื่อเข้าสู่ระบบ'
34 + login_submit: 'เข้าใช้ระบบ'
35 + participation: 'ต้องการเข้าร่วม?'
36 + please: 'กรุณา'
37 + register: 'ลงทะเบียน'
38 +
39 + main:
40 + start_soon: "การแข่งขันกำลังจะเริ่ม กรุณารอก่อน"
41 + specified_in_header: "ระบุที่หัวโปรแกรมแล้ว"
42 +
43 + problem_desc: "อ่าน"
44 + submitted_at: "ส่งเมื่อเวลา"
45 + graded_at: "ตรวจเมื่อเวลา"
46 + score: "คะแนน: "
47 + cmp_msg: "ผลคอมไพล์"
48 + src_link: "ต้นฉบับ"
49 + submissions_link: "การส่งครั้งอื่น ๆ"
50 +
51 + test:
52 + title: "ทดสอบโปรแกรมบนสภาพแวดล้อมของเครื่องตรวจ"
53 + intro: "คุณสามารถทดลองการทำงานของโปรแกรมที่เขียนกับข้อมูลชุดทดสอบของคุณเองในสภาพแวดล้อมจริงของการตรวจโปรแกรมได้ โดยเลือกโปรแกรมส่งแล้วที่ด้านล่างพร้อมทั้งส่งแฟ้มข้อมูลชุดทดสอบที่ต้องการให้ทำงานด้วย"
54 + disabled_at_end_announcement: "<b>หมายเหตุ:</b> ระบบทดสอบโปรแกรมจะหยุดทำงานในช่วงเวลา 30 นาทีสุดท้ายของการแข่งขัน"
55 +
56 +
57 + registration:
58 + title: "ลงทะเบียนผู้ใช้ใหม่"
59 + description: "ในการลงทะเบียน ให้ผู้สนใจเข้าร่วมการแข่งขันกรอกข้อมูลด้านล่าง จากนั้นระบบจะส่ง e-mail ไปยัง e-mail ที่ระบุเพื่อให้ยืนยันตัวตนและเปิดใช้บัญชีผู้ใช้<br/>ในกรณีที่ผู้เข้าแข่งขันเป็นนักเรียน รบกวนช่วยให้ข้อมูลเกี่ยวกับโรงเรียนและจังหวัดด้วย"
60 +
61 + successful_title: "การลงทะเบียนเสร็จเรียบร้อย"
62 +
63 + login_guide: "ใช้ได้เฉพาะ a-z, A-Z, 0-9 และ _ ความยาวไม่เกิน 20 ตัวอักษร"
64 + email_guide: "กรุณาตรวจสอบ e-mail ที่ใส่ให้ถูกต้อง<br/>คุณจะต้องยืนยันการลงทะเบียนผ่านทางข้อมูลที่จะส่งให้ทาง e-mail"
65 + register: "ลงทะเบียน"
66 +
67 + email_body: "สวัสดีครับ {{full_name}},
68 +
69 + คุณได้ลงทะเบียนเข้าร่วมการแข่งขัน {{contest_name}}
70 +
71 + บัญชีเข้าใช้ของคุณคือ: {{login}}
72 +
73 + รหัสผ่านคือ: {{password}}
74 +
75 + กรุณาเข้าลิงก์ต่อไปนี้:
76 +
77 + {{activation_url}}
78 +
79 + เพื่อเปิดใช้งานบัญชีของคุณ
80 +
81 + ถ้าคุณไม่ใช้คนที่ลงทะเบียน กรุณาละทิ้ง e-mail ฉบับนี้
82 + และแจ้งความผิดพลาดนี้กับ {{admin_email}}
83 +
84 + ขอบคุณมาก!"
85 +
86 + email_sent: "เราได้ส่งข้อมูลสำหรับยืนยันไปให้คุณแล้ว (โปรดอย่าลืมตรวจดูในส่วน Junk mail ด้วย)"
87 + email_verify_at: "กรุณาตรวจสอบที่ {{email}} พร้อมทั้งยืนยัน"
88 +
89 + activation_sucessful_title: "บัณชีผู้ใช้ได้รับการยืนยันแล้ว"
90 + account_activated: "บัญชีผู้ใช้ของคุณพร้อมใช้งานแล้ว"
91 +
92 + activation_failed_title: "การยืนยันล้มเหลว"
93 +
94 + errors:
95 + header: 'การลงทะเบียนมีข้อผิดพลาด'
96 + email:
97 + title: "เกิดปัญหาระหว่างการส่ง e-mail เพื่อยืนยันการสมัคร"
98 + expl: "<h2>บัญชีผู้ใช้ของคุณถูกสร้างขึ้นแล้ว แต่ระบบไม่สามารถส่ง e-mail เพื่อยืนยันการสมัครได้</h2>
99 + อาจเกิดปัญหาในการตั้งค่าเริ่มต้นของระบบ กรุณาช่วยติดต่อผู้ดูแลระบบด้วยที่ {{email}}<br/>ขอขอบคุณจากทีมงาน"
100 + activation:
101 + email_exists: "มีผู้ใช้ที่ใช้ e-mail นี้แล้ว"
102 + invalid: "รหัสสำหรับยืนยันผิดพลาด กรุณาตรวจสอบอีกครั้ง"
103 +
104 + help:
105 + how_to_submit: "วิธีการส่งโปรแกรม"
106 + must_specify_language: "คุณ<b>ต้อง</b>ระบุภาษาโปรแกรมที่ใช้ที่ตอนต้นของรหัสโปรแกรม (source code) นอกจากนี้คุณอาจจะระบุโจทย์ที่ต้องการส่งได้ด้วย"
107 + list_available_language: "ภาษาโปรแกรมที่สามารถระบุได้คือ <tt>C</tt>, <tt>C++</tt>, และ <tt>Pascal</tt> ด้านล่างแสดงตัวอย่างของการระบุสำหรับภาษาต่าง ๆ"
108 + accept_only_language_specified: "ระบบจะ<b>ไม่รับ</b>โปรแกรมที่ส่งถ้าคุณไม่ได้ระบุภาษาที่ใช้"
109 + specifying_task: "นอกจากนี้ คุณยังสามารถระบุชื่อของโจทย์ที่ต้องการส่งเพิ่มเติมได้ ในการระบุให้ใส่ <tt>TASK:</tt> <i>taskname</i> คุณสามารถตรวจสอบชื่อของโจทย์ได้ โดยจะแสดงในวงเล็บหลังชื่อภาษาไทยของโจทย์"
110 + example_cpp: "ยกตัวอย่างเช่น ถ้าคุณใช้ภาษา <tt>C++</tt> สำหรับเขียนโจทย์ <tt>mobiles</tt> ตอนต้นโปรแกรมคุณจะใส่ดังนี้"
111 + example_pas: "ถ้าคุณใช้ภาษา <tt>Pascal</tt> เพื่อเขียนโจทย์ข้อเดียวกัน คุณจะระบุ"
112 + ask_questions_at_messages: "ถ้ามีปัญหาในการใช้งานสามารถสอบถามได้ที่หน้า<a href=\"{{url}}\">{{message_link_name}}</a>"
113 +
114 + activerecord:
115 + attributes:
116 + user:
117 + login: "ชื่อเข้าใช้ระบบ"
118 + full_name: "ชื่อเต็ม"
119 + email: "e-mail"
120 + province: "จังหวัด"
121 +
@@ -0,0 +1,31
1 + ---
2 + beads:
3 + testcases: 20
4 + testruns: 20
5 + dna:
6 + testcases: 15
7 + testruns: 15
8 + roads:
9 + testcases: 11
10 + testruns:
11 + 1:
12 + - 1
13 + - 11
14 + 2:
15 + - 2
16 + 3:
17 + - 3
18 + 4:
19 + - 4
20 + 5:
21 + - 5
22 + 6:
23 + - 6
24 + 7:
25 + - 7
26 + 8:
27 + - 8
28 + 9:
29 + - 9
30 + 10:
31 + - 10
@@ -0,0 +1,11
1 + class AddAdminEmailToConfig < ActiveRecord::Migration
2 + def self.up
3 + Configuration.create(:key => 'system.admin_email',
4 + :value_type => 'string',
5 + :value => 'admin@admin.email')
6 + end
7 +
8 + def self.down
9 + Configuration.find_by_key('system.admin_email').destroy
10 + end
11 + end
@@ -0,0 +1,9
1 + class ChangeUserLoginStringLimit < ActiveRecord::Migration
2 + def self.up
3 + execute "ALTER TABLE `users` CHANGE `login` `login` VARCHAR( 50 )"
4 + end
5 +
6 + def self.down
7 + execute "ALTER TABLE `users` CHANGE `login` `login` VARCHAR( 10 )"
8 + end
9 + end
@@ -0,0 +1,15
1 + class AddTestRequestEarlyTimeoutToConfig < ActiveRecord::Migration
2 + def self.up
3 + # If Configuration['contest.test_request.early_timeout'] is true
4 + # the user will not be able to use test request at 30 minutes
5 + # before the contest ends.
6 +
7 + Configuration.create(:key => 'contest.test_request.early_timeout',
8 + :value_type => 'boolean',
9 + :value => 'false')
10 + end
11 +
12 + def self.down
13 + Configuration.find_by_key('contest.test_request.early_timeout').destroy
14 + end
15 + end
@@ -0,0 +1,9
1 + class AddContestFlagToAnnouncements < ActiveRecord::Migration
2 + def self.up
3 + add_column :announcements, :contest_only, :boolean, :default => false
4 + end
5 +
6 + def self.down
7 + remove_column :announcements, :contest_only
8 + end
9 + end
@@ -1,10 +1,19
1 1 # Add your own tasks in files placed in lib/tasks ending in .rake,
2 2 # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
3 3
4 4 require(File.join(File.dirname(__FILE__), 'config', 'boot'))
5 5
6 6 require 'rake'
7 7 require 'rake/testtask'
8 8 require 'rake/rdoctask'
9 9
10 10 require 'tasks/rails'
11 +
12 + require 'spec/rake/spectask'
13 +
14 + desc "Run all examples with RCov"
15 + Spec::Rake::SpecTask.new('examples_with_rcov') do |t|
16 + t.spec_files = FileList['spec/*/*.rb']
17 + t.rcov = true
18 + #t.rcov_opts = ['--exclude', 'examples']
19 + end
@@ -1,43 +1,43
1 1 class LoginController < ApplicationController
2 2
3 3 def index
4 4 # show login screen
5 5 reset_session
6 6 redirect_to :controller => 'main', :action => 'login'
7 7 end
8 8
9 9 def login
10 10 if user = User.authenticate(params[:login], params[:password])
11 11 session[:user_id] = user.id
12 12 redirect_to :controller => 'main', :action => 'list'
13 13 if user.admin?
14 14 session[:admin] = true
15 15 else
16 16 session[:admin] = false
17 17 end
18 18 else
19 19 flash[:notice] = 'Wrong password'
20 20 redirect_to :controller => 'main', :action => 'login'
21 21 end
22 22 end
23 23
24 24 def site_login
25 25 begin
26 26 site = Site.find(params[:login][:site_id])
27 27 rescue ActiveRecord::RecordNotFound
28 28 site = nil
29 29 end
30 30 if site==nil
31 31 flash[:notice] = 'Wrong site'
32 32 redirect_to :controller => 'main', :action => 'login' and return
33 33 end
34 - if site.password == params[:login][:password]
34 + if (site.password) and (site.password == params[:login][:password])
35 35 session[:site_id] = site.id
36 36 redirect_to :controller => 'site', :action => 'index'
37 37 else
38 38 flash[:notice] = 'Wrong site password'
39 - redirect_to :controller => 'main', :action => 'login'
39 + redirect_to :controller => 'site', :action => 'login'
40 40 end
41 41 end
42 42
43 43 end
@@ -1,101 +1,85
1 1 class MainController < ApplicationController
2 2
3 3 SYSTEM_MODE_CONF_KEY = 'system.mode'
4 4
5 5 before_filter :authenticate, :except => [:index, :login]
6 6 before_filter :check_viewability, :except => [:index, :login]
7 7
8 8 # COMMENTED OUT: filter in each action instead
9 9 # before_filter :verify_time_limit, :only => [:submit]
10 10
11 11 verify :method => :post, :only => [:submit],
12 12 :redirect_to => { :action => :index }
13 13
14 14 # COMMENT OUT: only need when having high load
15 15 # caches_action :index, :login
16 16
17 17 # NOTE: This method is not actually needed, 'config/routes.rb' has
18 18 # assigned action login as a default action.
19 19 def index
20 20 redirect_to :action => 'login'
21 21 end
22 22
23 23 def login
24 24 saved_notice = flash[:notice]
25 25 reset_session
26 26 flash[:notice] = saved_notice
27 27
28 28 # EXPERIMENT:
29 29 # Hide login if in single user mode and the url does not
30 30 # explicitly specify /login
31 31 #
32 32 # logger.info "PATH: #{request.path}"
33 33 # if Configuration['system.single_user_mode'] and
34 34 # request.path!='/main/login'
35 35 # @hidelogin = true
36 36 # end
37 37
38 - # Site administrator login
39 - @countries = Country.find(:all, :include => :sites)
40 - @country_select = @countries.collect { |c| [c.name, c.id] }
41 -
42 - @country_select_with_all = [['Any',0]]
43 - @countries.each do |country|
44 - @country_select_with_all << [country.name, country.id]
45 - end
46 -
47 - @site_select = []
48 - @countries.each do |country|
49 - country.sites.each do |site|
50 - @site_select << ["#{site.name}, #{country.name}", site.id]
51 - end
52 - end
53 -
54 38 @announcements = Announcement.find_for_frontpage
55 39 render :action => 'login', :layout => 'empty'
56 40 end
57 41
58 42 def list
59 43 prepare_list_information
60 44 end
61 45
62 46 def help
63 47 @user = User.find(session[:user_id])
64 48 end
65 49
66 50 def submit
67 51 user = User.find(session[:user_id])
68 52
69 53 @submission = Submission.new(params[:submission])
70 54 @submission.user = user
71 55 @submission.language_id = 0
72 56 if params['file']!=''
73 57 @submission.source = params['file'].read
74 58 @submission.source_filename = params['file'].original_filename
75 59 end
76 60 @submission.submitted_at = Time.new.gmtime
77 61
78 62 if Configuration[SYSTEM_MODE_CONF_KEY]=='contest' and
79 63 user.site!=nil and user.site.finished?
80 64 @submission.errors.add_to_base "The contest is over."
81 65 prepare_list_information
82 66 render :action => 'list' and return
83 67 end
84 68
85 69 if @submission.valid?
86 70 if @submission.save == false
87 71 flash[:notice] = 'Error saving your submission'
88 72 elsif Task.create(:submission_id => @submission.id,
89 73 :status => Task::STATUS_INQUEUE) == false
90 74 flash[:notice] = 'Error adding your submission to task queue'
91 75 end
92 76 else
93 77 prepare_list_information
94 78 render :action => 'list' and return
95 79 end
96 80 redirect_to :action => 'list'
97 81 end
98 82
99 83 def source
100 84 submission = Submission.find(params[:id])
101 85 if submission.user_id == session[:user_id]
@@ -152,98 +136,102
152 136 end
153 137 prepare_grading_result(@submission)
154 138 end
155 139
156 140 def load_output
157 141 if !Configuration.show_grading_result or params[:num]==nil
158 142 redirect_to :action => 'list' and return
159 143 end
160 144 @user = User.find(session[:user_id])
161 145 @submission = Submission.find(params[:id])
162 146 if @submission.user!=@user
163 147 flash[:notice] = 'You are not allowed to view result of other users.'
164 148 redirect_to :action => 'list' and return
165 149 end
166 150 case_num = params[:num].to_i
167 151 out_filename = output_filename(@user.login,
168 152 @submission.problem.name,
169 153 @submission.id,
170 154 case_num)
171 155 if !FileTest.exists?(out_filename)
172 156 flash[:notice] = 'Output not found.'
173 157 redirect_to :action => 'list' and return
174 158 end
175 159
176 160 response.headers['Content-Type'] = "application/force-download"
177 161 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
178 162 response.headers["X-Sendfile"] = out_filename
179 163 response.headers['Content-length'] = File.size(out_filename)
180 164 render :nothing => true
181 165 end
182 166
183 167 def error
184 168 @user = User.find(session[:user_id])
185 169 end
186 170
187 171 protected
188 172 def prepare_list_information
189 173 @problems = Problem.find_available_problems
190 174 @prob_submissions = Array.new
191 175 @user = User.find(session[:user_id])
192 176 @problems.each do |p|
193 177 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
194 178 if sub!=nil
195 179 @prob_submissions << { :count => sub.number, :submission => sub }
196 180 else
197 181 @prob_submissions << { :count => 0, :submission => nil }
198 182 end
199 183 end
184 + if Configuration.show_tasks_to?(@user)
185 + @announcements = Announcement.find_published(true)
186 + else
200 187 @announcements = Announcement.find_published
201 188 end
189 + end
202 190
203 191 def check_viewability
204 192 @user = User.find(session[:user_id])
205 193 if (!Configuration.show_tasks_to?(@user)) and
206 194 ((action_name=='submission') or (action_name=='submit'))
207 195 redirect_to :action => 'list' and return
208 196 end
209 197 end
210 198
211 199 def prepare_grading_result(submission)
212 200 grading_info = Configuration.task_grading_info[submission.problem.name]
213 201 @test_runs = []
214 202 if grading_info['testruns'].is_a? Integer
215 203 trun_count = grading_info['testruns']
216 204 trun_count.times do |i|
217 205 @test_runs << [ read_grading_result(@user.login,
218 206 submission.problem.name,
219 207 submission.id,
220 208 i+1) ]
221 209 end
222 210 else
223 211 grading_info['testruns'].keys.sort.each do |num|
224 212 run = []
225 213 testrun = grading_info['testruns'][num]
226 214 testrun.each do |c|
227 215 run << read_grading_result(@user.login,
228 216 submission.problem.name,
229 217 submission.id,
230 218 c)
231 219 end
232 220 @test_runs << run
233 221 end
234 222 end
235 223 end
236 224
237 225 def grading_result_dir(user_name, problem_name, submission_id, case_num)
238 226 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
239 227 end
240 228
241 229 def output_filename(user_name, problem_name, submission_id, case_num)
242 230 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
243 231 return "#{dir}/output.txt"
244 232 end
245 233
246 234 def read_grading_result(user_name, problem_name, submission_id, case_num)
247 235 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
248 236 result_file_name = "#{dir}/result"
249 237 if !FileTest.exists?(result_file_name)
@@ -1,40 +1,62
1 1 class SiteController < ApplicationController
2 2
3 - before_filter :site_admin_authorization
3 + before_filter :site_admin_authorization, :except => 'login'
4 +
5 + def login
6 + # Site administrator login
7 + @countries = Country.find(:all, :include => :sites)
8 + @country_select = @countries.collect { |c| [c.name, c.id] }
9 +
10 + @country_select_with_all = [['Any',0]]
11 + @countries.each do |country|
12 + @country_select_with_all << [country.name, country.id]
13 + end
14 +
15 + @site_select = []
16 + @countries.each do |country|
17 + country.sites.each do |site|
18 + @site_select << ["#{site.name}, #{country.name}", site.id]
19 + end
20 + end
21 +
22 + @default_site = Site.first if !Configuration['contest.multisites']
23 +
24 + render :action => 'login', :layout => 'empty'
25 + end
4 26
5 27 def index
6 28 if @site.started
7 29 render :action => 'started', :layout => 'empty'
8 30 else
9 31 render :action => 'prompt', :layout => 'empty'
10 32 end
11 33 end
12 34
13 35 def start
14 36 @site.started = true
15 37 @site.start_time = Time.new.gmtime
16 38 @site.save
17 39 redirect_to :action => 'index'
18 40 end
19 41
20 42 def logout
21 43 reset_session
22 44 redirect_to :controller => 'main', :action => 'login'
23 45 end
24 46
25 47 protected
26 48 def site_admin_authorization
27 49 if session[:site_id]==nil
28 - redirect_to :controller => 'main', :action => 'login' and return
50 + redirect_to :controller => 'site', :action => 'login' and return
29 51 end
30 52 begin
31 53 @site = Site.find(session[:site_id], :include => :country)
32 54 rescue ActiveRecord::RecordNotFound
33 55 @site = nil
34 56 end
35 57 if @site==nil
36 - redirect_to :controller => 'main', :action => 'login' and return
58 + redirect_to :controller => 'site', :action => 'login' and return
37 59 end
38 60 end
39 61
40 62 end
@@ -54,62 +54,67
54 54 test_request = TestRequest.find(params[:id])
55 55 rescue
56 56 test_request = nil
57 57 end
58 58 if test_request==nil or test_request.user_id != user.id
59 59 flash[:notice] = 'Invalid output'
60 60 redirect_to :action => 'index'
61 61 return
62 62 end
63 63 if test_request.output_file_name!=nil
64 64 data = File.open(test_request.output_file_name).read(2048)
65 65 if data==nil
66 66 data=""
67 67 end
68 68 send_data(data,
69 69 {:filename => 'output.txt',
70 70 :type => 'text/plain'})
71 71 return
72 72 end
73 73 redirect_to :action => 'index'
74 74 end
75 75
76 76 def result
77 77 @user = User.find(session[:user_id])
78 78 begin
79 79 @test_request = TestRequest.find(params[:id])
80 80 rescue
81 81 @test_request = nil
82 82 end
83 83 if @test_request==nil or @test_request.user_id != @user.id
84 84 flash[:notice] = 'Invalid request'
85 85 redirect_to :action => 'index'
86 86 return
87 87 end
88 88 end
89 89
90 90 protected
91 91
92 92 def prepare_index_information
93 93 @user = User.find(session[:user_id])
94 94 @submissions = Submission.find_last_for_all_available_problems(@user.id)
95 95 all_problems = @submissions.collect { |submission| submission.problem }
96 96 @problems = []
97 97 all_problems.each do |problem|
98 98 if problem.test_allowed
99 99 @problems << problem
100 100 end
101 101 end
102 - @test_requests = @user.test_requests
102 + @test_requests = []
103 + @user.test_requests.each do |ts|
104 + if ts.problem.available
105 + @test_requests << ts
106 + end
107 + end
103 108 end
104 109
105 110 def check_viewability
106 111 user = User.find(session[:user_id])
107 112 if !Configuration.show_tasks_to?(user)
108 113 redirect_to :controller => 'main', :action => 'list'
109 114 end
110 115 if (!Configuration.show_submitbox_to?(user)) and (action_name=='submit')
111 116 redirect_to :controller => 'test', :action => 'index'
112 117 end
113 118 end
114 119
115 120 end
@@ -1,160 +1,165
1 1 class UserAdminController < ApplicationController
2 2
3 3 before_filter :admin_authorization
4 4
5 5 def index
6 6 list
7 7 render :action => 'list'
8 8 end
9 9
10 10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
11 11 verify :method => :post, :only => [ :destroy, :create, :update ],
12 12 :redirect_to => { :action => :list }
13 13
14 14 def list
15 15 @users = User.find(:all)
16 + @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
16 17 end
17 18
18 19 def show
19 20 @user = User.find(params[:id])
20 21 end
21 22
22 23 def new
23 24 @user = User.new
24 25 end
25 26
26 27 def create
27 28 @user = User.new(params[:user])
28 29 @user.activated = true
29 30 if @user.save
30 31 flash[:notice] = 'User was successfully created.'
31 32 redirect_to :action => 'list'
32 33 else
33 34 render :action => 'new'
34 35 end
35 36 end
36 37
37 38 def create_from_list
38 39 lines = params[:user_list]
39 40 lines.split("\n").each do |line|
40 41 items = line.chomp.split(',')
41 42 if items.length==4
42 43 user = User.new
43 44 user.login = items[0]
44 45 user.full_name = items[1]
45 46 user.alias = items[2]
46 47 user.password = items[3]
47 48 user.password_confirmation = items[3]
48 49 user.activated = true
49 50 user.save
50 51 end
51 52 end
52 53 redirect_to :action => 'list'
53 54 end
54 55
55 56 def edit
56 57 @user = User.find(params[:id])
57 58 end
58 59
59 60 def update
60 61 @user = User.find(params[:id])
61 62 if @user.update_attributes(params[:user])
62 63 flash[:notice] = 'User was successfully updated.'
63 64 redirect_to :action => 'show', :id => @user
64 65 else
65 66 render :action => 'edit'
66 67 end
67 68 end
68 69
69 70 def destroy
70 71 User.find(params[:id]).destroy
71 72 redirect_to :action => 'list'
72 73 end
73 74
74 75 def user_stat
75 76 @problems = Problem.find_available_problems
76 77 @users = User.find(:all)
77 78 @scorearray = Array.new
78 79 @users.each do |u|
79 80 ustat = Array.new
80 - ustat[0] = u.login
81 - ustat[1] = u.full_name
81 + ustat[0] = u
82 82 @problems.each do |p|
83 83 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
84 84 if (sub!=nil) and (sub.points!=nil)
85 85 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
86 86 else
87 87 ustat << [0,false]
88 88 end
89 89 end
90 90 @scorearray << ustat
91 91 end
92 92 end
93 93
94 94 def import
95 95 if params[:file]==''
96 96 flash[:notice] = 'Error importing no file'
97 97 redirect_to :action => 'list' and return
98 98 end
99 99 import_from_file(params[:file])
100 100 end
101 101
102 102 protected
103 103
104 104 def import_from_file(f)
105 105 data_hash = YAML.load(f)
106 106 @import_log = ""
107 107
108 108 country_data = data_hash[:countries]
109 109 site_data = data_hash[:sites]
110 110 user_data = data_hash[:users]
111 111
112 112 # import country
113 113 countries = {}
114 114 country_data.each_pair do |id,country|
115 115 c = Country.find_by_name(country[:name])
116 116 if c!=nil
117 117 countries[id] = c
118 118 @import_log << "Found #{country[:name]}\n"
119 119 else
120 120 countries[id] = Country.new(:name => country[:name])
121 121 countries[id].save
122 122 @import_log << "Created #{country[:name]}\n"
123 123 end
124 124 end
125 125
126 126 # import sites
127 127 sites = {}
128 128 site_data.each_pair do |id,site|
129 129 s = Site.find_by_name(site[:name])
130 130 if s!=nil
131 131 @import_log << "Found #{site[:name]}\n"
132 132 else
133 133 s = Site.new(:name => site[:name])
134 134 @import_log << "Created #{site[:name]}\n"
135 135 end
136 136 s.password = site[:password]
137 137 s.country = countries[site[:country_id]]
138 138 s.save
139 139 sites[id] = s
140 140 end
141 141
142 142 # import users
143 143 user_data.each_pair do |id,user|
144 144 u = User.find_by_login(user[:login])
145 145 if u!=nil
146 146 @import_log << "Found #{user[:login]}\n"
147 147 else
148 148 u = User.new(:login => user[:login])
149 149 @import_log << "Created #{user[:login]}\n"
150 150 end
151 151 u.full_name = user[:name]
152 152 u.password = user[:password]
153 153 u.country = countries[user[:country_id]]
154 154 u.site = sites[user[:site_id]]
155 - u.save
155 + u.activated = true
156 + u.email = "empty-#{u.login}@none.com"
157 + if not u.save
158 + @import_log << "Errors\n"
159 + u.errors.each { |attr,msg| @import_log << "#{attr} - #{msg}\n" }
160 + end
156 161 end
157 162
158 163 end
159 164
160 165 end
@@ -1,116 +1,124
1 1 require 'tmail'
2 2 require 'net/smtp'
3 3
4 4 class UsersController < ApplicationController
5 5
6 6 before_filter :authenticate, :except => [:new, :register, :confirm]
7 7
8 + before_filter :verify_online_registration, :only => [:new, :register]
9 +
8 10 verify :method => :post, :only => [:chg_passwd],
9 11 :redirect_to => { :action => :index }
10 12
11 - in_place_edit_for :user, :alias_for_editing
12 - in_place_edit_for :user, :email_for_editing
13 + #in_place_edit_for :user, :alias_for_editing
14 + #in_place_edit_for :user, :email_for_editing
13 15
14 16 def index
15 17 if !Configuration['system.user_setting_enabled']
16 18 redirect_to :controller => 'main', :action => 'list'
17 19 else
18 20 @user = User.find(session[:user_id])
19 21 end
20 22 end
21 23
22 24 def chg_passwd
23 25 user = User.find(session[:user_id])
24 26 user.password = params[:passwd]
25 27 user.password_confirmation = params[:passwd_verify]
26 28 if user.save
27 29 flash[:notice] = 'password changed'
28 30 else
29 31 flash[:notice] = 'Error: password changing failed'
30 32 end
31 33 redirect_to :action => 'index'
32 34 end
33 35
34 36 def new
35 37 @user = User.new
36 38 render :action => 'new', :layout => 'empty'
37 39 end
38 40
39 41 def register
42 + if(params[:cancel])
43 + redirect_to :controller => 'main', :action => 'login'
44 + return
45 + end
40 46 @user = User.new(params[:user])
41 47 @user.password_confirmation = @user.password = User.random_password
42 48 @user.activated = false
43 49 if (@user.valid?) and (@user.save)
44 50 if send_confirmation_email(@user)
45 51 render :action => 'new_splash', :layout => 'empty'
46 52 else
53 + @admin_email = Configuration['system.admin_email']
47 54 render :action => 'email_error', :layout => 'empty'
48 55 end
49 56 else
50 57 @user.errors.add_to_base("Email cannot be blank") if @user.email==''
51 58 render :action => 'new', :layout => 'empty'
52 59 end
53 60 end
54 61
55 62 def confirm
56 63 login = params[:login]
57 64 key = params[:activation]
58 65 @user = User.find_by_login(login)
59 66 if (@user) and (@user.verify_activation_key(key))
60 67 if @user.valid? # check uniquenss of email
61 68 @user.activated = true
62 69 @user.save
63 70 @result = :successful
64 71 else
65 72 @result = :email_used
66 73 end
67 74 else
68 75 @result = :failed
69 76 end
70 77 render :action => 'confirm', :layout => 'empty'
71 78 end
72 79
73 80 protected
74 81
82 + def verify_online_registration
83 + if !Configuration['system.online_registration']
84 + redirect_to :controller => 'main', :action => 'login'
85 + end
86 + end
87 +
75 88 def send_confirmation_email(user)
76 89 contest_name = Configuration['contest.name']
90 + admin_email = Configuration['system.admin_email']
77 91 activation_url = url_for(:action => 'confirm',
78 92 :login => user.login,
79 93 :activation => user.activation_key)
80 94 home_url = url_for(:controller => 'main', :action => 'index')
81 95 mail = TMail::Mail.new
82 96 mail.to = user.email
83 97 mail.from = Configuration['system.online_registration.from']
84 98 mail.subject = "[#{contest_name}] Confirmation"
85 - mail.body = <<-EOF
86 - Hello #{user.full_name},
87 -
88 - You have registered for #{contest_name} (#{home_url}).
89 -
90 - Your login is: #{user.login}
91 - Your password is: #{user.password}
99 + mail.body = t('registration.email_body', {
100 + :full_name => user.full_name,
101 + :contest_name => contest_name,
102 + :login => user.login,
103 + :password => user.password,
104 + :activation_url => activation_url,
105 + :admin_email => admin_email
106 + })
92 107
93 - Please follow the link:
94 - #{activation_url}
95 - to activate your user account.
96 -
97 - If you did not register, please ignore this e-mail.
98 -
99 - Thanks!
100 - EOF
108 + logger.info mail.body
101 109
102 110 smtp_server = Configuration['system.online_registration.smtp']
103 111
104 112 begin
105 113 Net::SMTP.start(smtp_server) do |smtp|
106 114 smtp.send_message(mail.to_s, mail.from, mail.to)
107 115 end
108 116 result = true
109 117 rescue
110 118 result = false
111 119 end
112 120
113 121 return result
114 122 end
115 123
116 124 end
@@ -1,118 +1,124
1 1 # Methods added to this helper will be available to all templates in the application.
2 2 module ApplicationHelper
3 3
4 4 SYSTEM_MODE_CONF_KEY = 'system.mode'
5 5
6 6 def user_header
7 7 menu_items = ''
8 8 user = User.find(session[:user_id])
9 9
10 10 if (user!=nil) and (session[:admin])
11 11 # admin menu
12 12 menu_items << "<b>Administrative task:</b> "
13 13 append_to menu_items, '[Announcements]', 'announcements', 'index'
14 14 append_to menu_items, '[Msg console]', 'messages', 'console'
15 15 append_to menu_items, '[Problem admin]', 'problems', 'index'
16 16 append_to menu_items, '[User admin]', 'user_admin', 'index'
17 - append_to menu_items, '[User stat]', 'user_admin', 'user_stat'
17 + append_to menu_items, '[Results]', 'user_admin', 'user_stat'
18 18 append_to menu_items, '[Graders]', 'graders', 'list'
19 - append_to menu_items, '[Site config]', 'configurations', 'index'
19 + append_to menu_items, '[Sites]', 'sites', 'index'
20 + append_to menu_items, '[System config]', 'configurations', 'index'
20 21 menu_items << "<br/>"
21 22 end
22 23
23 24 # main page
24 - append_to menu_items, '[Main]', 'main', 'list'
25 - append_to menu_items, '[Messages]', 'messages', 'list'
25 + append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
26 + append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
26 27
27 28 if (user!=nil) and (Configuration.show_tasks_to?(user))
28 - append_to menu_items, '[Tasks]', 'tasks', 'list'
29 - append_to menu_items, '[Submissions]', 'main', 'submission'
30 - append_to menu_items, '[Test]', 'test', 'index'
29 + append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
30 + append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
31 + append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
31 32 end
32 - append_to menu_items, '[Help]', 'main', 'help'
33 + append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
33 34
34 35 if Configuration['system.user_setting_enabled']
35 - append_to menu_items, '[Settings]', 'users', 'index'
36 + append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
36 37 end
37 - append_to menu_items, '[Log out]', 'main', 'login'
38 + append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
38 39
39 40 menu_items
40 41 end
41 42
42 43 def append_to(option,label, controller, action)
43 44 option << ' ' if option!=''
44 45 option << link_to_unless_current(label,
45 46 :controller => controller,
46 47 :action => action)
47 48 end
48 49
49 50 def format_short_time(time)
50 51 now = Time.now.gmtime
51 52 st = ''
52 53 if (time.yday != now.yday) or
53 54 (time.year != now.year)
54 55 st = time.strftime("%x ")
55 56 end
56 57 st + time.strftime("%X")
57 58 end
58 59
59 60 def read_textfile(fname,max_size=2048)
60 61 begin
61 62 File.open(fname).read(max_size)
62 63 rescue
63 64 nil
64 65 end
65 66 end
66 67
67 68 def user_title_bar(user)
68 69 header = ''
69 70 time_left = ''
70 71
71 72 #
72 73 # if the contest is over
73 74 if Configuration[SYSTEM_MODE_CONF_KEY]=='contest'
74 75 if user.site!=nil and user.site.finished?
75 76 header = <<CONTEST_OVER
76 77 <tr><td colspan="2" align="center">
77 78 <span class="contest-over-msg">THE CONTEST IS OVER</span>
78 79 </td></tr>
79 80 CONTEST_OVER
80 81 end
82 + if !user.site.started
83 + time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
84 + else
81 85 if user.site!=nil
82 - time_left = ". Time left: #{Time.at(user.site.time_left).gmtime.strftime("%X")}"
86 + time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
87 + " #{Time.at(user.site.time_left).gmtime.strftime("%X")}"
88 + end
83 89 end
84 90 end
85 91
86 92 #
87 93 # if the contest is in the anaysis mode
88 94 if Configuration[SYSTEM_MODE_CONF_KEY]=='analysis'
89 95 header = <<ANALYSISMODE
90 96 <tr><td colspan="2" align="center">
91 97 <span class="contest-over-msg">ANALYSIS MODE</span>
92 98 </td></tr>
93 99 ANALYSISMODE
94 100 end
95 101
96 102 contest_name = Configuration['contest.name']
97 103
98 104 #
99 105 # build real title bar
100 106 <<TITLEBAR
101 107 <div class="title">
102 108 <table>
103 109 #{header}
104 110 <tr>
105 111 <td class="left-col">
106 112 #{user.full_name}<br/>
107 - Current time is #{format_short_time(Time.new.gmtime)} UTC
113 + #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
108 114 #{time_left}
109 115 <br/>
110 116 </td>
111 117 <td class="right-col">#{contest_name}</td>
112 118 </tr>
113 119 </table>
114 120 </div>
115 121 TITLEBAR
116 122 end
117 123
118 124 end
@@ -1,15 +1,21
1 1 class Announcement < ActiveRecord::Base
2 2
3 - def self.find_published
3 + def self.find_published(contest_started=false)
4 + if contest_started
4 5 Announcement.find(:all,
5 6 :conditions => "(published = 1) AND (frontpage = 0)",
6 7 :order => "created_at DESC")
8 + else
9 + Announcement.find(:all,
10 + :conditions => "(published = 1) AND (frontpage = 0) AND (contest_only = 0)",
11 + :order => "created_at DESC")
12 + end
7 13 end
8 14
9 15 def self.find_for_frontpage
10 16 Announcement.find(:all,
11 17 :conditions => "(published = 1) AND (frontpage = 1)",
12 18 :order => "created_at DESC")
13 19 end
14 20
15 21 end
@@ -1,119 +1,127
1 1 require 'yaml'
2 2
3 3 #
4 4 # This class also contains various login of the system.
5 5 #
6 6 class Configuration < ActiveRecord::Base
7 7
8 8 SYSTEM_MODE_CONF_KEY = 'system.mode'
9 + TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
9 10
10 11 # set @@cache = true to only reload once.
11 12 @@cache = false
12 13
13 14 @@configurations = nil
14 15 @@task_grading_info = nil
15 16
16 17 def self.get(key)
17 18 if @@cache
18 19 if @@configurations == nil
19 20 self.read_config
20 21 end
21 22 return @@configurations[key]
22 23 else
23 24 return Configuration.read_one_key(key)
24 25 end
25 26 end
26 27
27 28 def self.[](key)
28 29 self.get(key)
29 30 end
30 31
31 32 def self.reload
32 33 self.read_config
33 34 end
34 35
35 36 def self.clear
36 37 @@configurations = nil
37 38 end
38 39
40 + def self.cache?
41 + @@cache
42 + end
43 +
39 44 def self.enable_caching
40 45 @@cache = true
41 46 end
42 47
43 48 #
44 49 # View decision
45 50 #
46 51 def self.show_submitbox_to?(user)
47 52 mode = get(SYSTEM_MODE_CONF_KEY)
48 53 return false if mode=='analysis'
49 54 if (mode=='contest')
50 55 return false if (user.site!=nil) and
51 56 ((user.site.started!=true) or (user.site.finished?))
52 57 end
53 58 return true
54 59 end
55 60
56 61 def self.show_tasks_to?(user)
57 62 mode = get(SYSTEM_MODE_CONF_KEY)
58 63 if (mode=='contest')
59 64 return false if (user.site!=nil) and (user.site.started!=true)
60 65 end
61 66 return true
62 67 end
63 68
64 69 def self.show_grading_result
65 70 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
66 71 end
67 72
68 73 def self.allow_test_request(user)
69 74 mode = get(SYSTEM_MODE_CONF_KEY)
75 + early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
70 76 if (mode=='contest')
71 - return false if (user.site!=nil) and ((user.site.started!=true) or (user.site.time_left < 30.minutes))
77 + return false if ((user.site!=nil) and
78 + ((user.site.started!=true) or
79 + (early_timeout and (user.site.time_left < 30.minutes))))
72 80 end
73 81 return false if mode=='analysis'
74 82 return true
75 83 end
76 84
77 85 def self.task_grading_info
78 86 if @@task_grading_info==nil
79 87 read_grading_info
80 88 end
81 89 return @@task_grading_info
82 90 end
83 91
84 92 protected
85 93
86 94 def self.convert_type(val,type)
87 95 case type
88 96 when 'string'
89 97 return val
90 98
91 99 when 'integer'
92 100 return val.to_i
93 101
94 102 when 'boolean'
95 103 return (val=='true')
96 104 end
97 105 end
98 106
99 107 def self.read_config
100 108 @@configurations = {}
101 109 Configuration.find(:all).each do |conf|
102 110 key = conf.key
103 111 val = conf.value
104 112 @@configurations[key] = Configuration.convert_type(val,conf.value_type)
105 113 end
106 114 end
107 115
108 116 def self.read_one_key(key)
109 117 conf = Configuration.find_by_key(key)
110 118 if conf
111 119 return Configuration.convert_type(conf.value,conf.value_type)
112 120 else
113 121 return nil
114 122 end
115 123 end
116 124
117 125 def self.read_grading_info
118 126 f = File.open(TASK_GRADING_INFO_FILENAME)
119 127 @@task_grading_info = YAML.load(f)
@@ -1,50 +1,54
1 1 class Site < ActiveRecord::Base
2 2
3 3 belongs_to :country
4 4 has_many :users
5 5
6 6 def clear_start_time_if_not_started
7 7 if !self.started
8 8 self.start_time = nil
9 9 end
10 10 end
11 11
12 12 def time_left
13 13 contest_time = Configuration['contest.time_limit']
14 14 if tmatch = /(\d+):(\d+)/.match(contest_time)
15 15 h = tmatch[1].to_i
16 16 m = tmatch[2].to_i
17 17
18 + contest_time = h.hour + m.minute
19 +
20 + return contest_time if !self.started
21 +
18 22 current_time = Time.now.gmtime
19 23 if self.start_time!=nil
20 - finish_time = self.start_time + h.hour + m.minute
24 + finish_time = self.start_time + contest_time
21 25 else
22 - finish_time = current_time + h.hour + m.minute
26 + finish_time = current_time + contest_time
23 27 end
24 28
25 29 if current_time > finish_time
26 30 return current_time - current_time
27 31 else
28 32 finish_time - current_time
29 33 end
30 34 else
31 35 nil
32 36 end
33 37 end
34 38
35 39 def finished?
36 40 if !self.started
37 41 return false
38 42 end
39 43
40 44 contest_time = Configuration['contest.time_limit']
41 45 if tmatch = /(\d+):(\d+)/.match(contest_time)
42 46 h = tmatch[1].to_i
43 47 m = tmatch[2].to_i
44 48 return Time.now.gmtime > (self.start_time + h.hour + m.minute)
45 49 else
46 50 false
47 51 end
48 52 end
49 53
50 54 end
@@ -1,139 +1,166
1 1 require 'digest/sha1'
2 2
3 3 class User < ActiveRecord::Base
4 4
5 5 has_and_belongs_to_many :roles
6 6
7 7 has_many :test_requests, :order => "submitted_at DESC"
8 8
9 9 has_many :messages,
10 10 :class_name => "Message",
11 11 :foreign_key => "sender_id",
12 12 :order => 'created_at DESC'
13 13
14 14 has_many :replied_messages,
15 15 :class_name => "Message",
16 16 :foreign_key => "receiver_id",
17 17 :order => 'created_at DESC'
18 18
19 19 belongs_to :site
20 20 belongs_to :country
21 21
22 22 named_scope :activated_users, :conditions => {:activated => true}
23 23
24 24 validates_presence_of :login
25 25 validates_uniqueness_of :login
26 - validates_format_of :login, :with => /^[\_a-z0-9]+$/
27 - validates_length_of :login, :within => 3..10
26 + validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
27 + validates_length_of :login, :within => 3..30
28 28
29 29 validates_presence_of :full_name
30 30 validates_length_of :full_name, :minimum => 1
31 31
32 32 validates_presence_of :password, :if => :password_required?
33 33 validates_length_of :password, :within => 4..20, :if => :password_required?
34 34 validates_confirmation_of :password, :if => :password_required?
35 35
36 - validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :allow_blank => true
36 + validates_format_of :email,
37 + :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
38 + :if => :email_validation?
39 + validate :uniqueness_of_email_from_activated_users,
40 + :if => :email_validation?
41 + validate :enough_time_interval_between_same_email_registrations,
42 + :if => :email_validation?
37 43
38 - validate :uniqueness_of_email_from_activated_users
39 - validate :enough_time_interval_between_same_email_registrations
44 + # these are for ytopc
45 + # disable for now
46 + #validates_presence_of :province
40 47
41 48 attr_accessor :password
42 49
43 50 before_save :encrypt_new_password
51 + before_save :assign_default_site
44 52
45 53 def self.authenticate(login, password)
46 54 user = find_by_login(login)
47 55 return user if user && user.authenticated?(password)
48 56 end
49 57
50 58 def authenticated?(password)
51 59 if self.activated
52 60 hashed_password == User.encrypt(password,self.salt)
53 61 else
54 62 false
55 63 end
56 64 end
57 65
58 66 def admin?
59 67 self.roles.detect {|r| r.name == 'admin' }
60 68 end
61 69
62 70 def email_for_editing
63 71 if self.email==nil
64 72 "(unknown)"
65 73 elsif self.email==''
66 74 "(blank)"
67 75 else
68 76 self.email
69 77 end
70 78 end
71 79
72 80 def email_for_editing=(e)
73 81 self.email=e
74 82 end
75 83
76 84 def alias_for_editing
77 85 if self.alias==nil
78 86 "(unknown)"
79 87 elsif self.alias==''
80 88 "(blank)"
81 89 else
82 90 self.alias
83 91 end
84 92 end
85 93
86 94 def alias_for_editing=(e)
87 95 self.alias=e
88 96 end
89 97
90 98 def activation_key
91 99 if self.hashed_password==nil
92 100 encrypt_new_password
93 101 end
94 102 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
95 103 end
96 104
97 105 def verify_activation_key(key)
98 106 key == activation_key
99 107 end
100 108
101 109 def self.random_password(length=5)
102 110 chars = 'abcdefghjkmnopqrstuvwxyz'
103 111 password = ''
104 112 length.times { password << chars[rand(chars.length - 1)] }
105 113 password
106 114 end
107 115
108 116 protected
109 117 def encrypt_new_password
110 118 return if password.blank?
111 119 self.salt = (10+rand(90)).to_s
112 120 self.hashed_password = User.encrypt(self.password,self.salt)
113 121 end
114 122
123 + def assign_default_site
124 + # have to catch error when migrating (because self.site is not available).
125 + begin
126 + if self.site==nil
127 + self.site = Site.find_by_name('default')
128 + end
129 + rescue
130 + end
131 + end
132 +
115 133 def password_required?
116 134 self.hashed_password.blank? || !self.password.blank?
117 135 end
118 136
119 137 def self.encrypt(string,salt)
120 138 Digest::SHA1.hexdigest(salt + string)
121 139 end
122 140
123 141 def uniqueness_of_email_from_activated_users
124 142 user = User.activated_users.find_by_email(self.email)
125 143 if user and (user.login != self.login)
126 144 self.errors.add_to_base("Email has already been taken")
127 145 end
128 146 end
129 147
130 148 def enough_time_interval_between_same_email_registrations
131 149 return if !self.new_record?
150 + return if self.activated
132 151 open_user = User.find_by_email(self.email,
133 152 :order => 'created_at DESC')
134 153 if open_user and open_user.created_at and
135 154 (open_user.created_at > Time.now.gmtime - 5.minutes)
136 155 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
137 156 end
138 157 end
158 +
159 + def email_validation?
160 + begin
161 + return VALIDATE_USER_EMAILS
162 + rescue
163 + return false
139 164 end
165 + end
166 + end
@@ -1,32 +1,37
1 1 <h1>Editing announcement</h1>
2 2
3 3 <%= error_messages_for :announcement %>
4 4
5 5 <% form_for(@announcement) do |f| %>
6 6 <p>
7 7 <b>Body</b><br />
8 8 <%= f.text_area :body %>
9 9 </p>
10 10
11 11 <p>
12 12 <b>Author</b><br />
13 13 <%= f.text_field :author %>
14 14 </p>
15 15
16 16 <p>
17 17 <b>Published</b><br />
18 18 <%= f.check_box :published %>
19 19 </p>
20 20
21 21 <p>
22 22 <b>Show on front page?</b><br />
23 23 <%= f.check_box :frontpage %>
24 24 </p>
25 25
26 26 <p>
27 + <b>Show only in contest?</b><br />
28 + <%= f.check_box :contest_only %>
29 + </p>
30 +
31 + <p>
27 32 <%= f.submit "Update" %>
28 33 </p>
29 34 <% end %>
30 35
31 36 <%= link_to 'Show', @announcement %> |
32 37 <%= link_to 'Back', announcements_path %>
@@ -1,32 +1,31
1 1 <% content_for :head do %>
2 - <%= stylesheet_link_tag 'scaffold' %>
3 2 <%= javascript_include_tag :defaults %>
4 3 <% end %>
5 4
6 5 <h1>Listing announcements</h1>
7 6
8 7 <%= link_to 'New announcement', new_announcement_path %>
9 8
10 9 <table>
11 10 <tr>
12 11 <th>Body</th>
13 12 <th>Author</th>
14 13 <th>Published</th>
15 14 </tr>
16 15
17 16 <% for announcement in @announcements %>
18 17 <tr>
19 18 <% @announcement = announcement %>
20 19 <td><%=h announcement.body %></td>
21 20 <td><%=h announcement.author %></td>
22 21 <td><%= in_place_editor_field :announcement, :published, {}, :rows => 1 %></td>
23 22 <td><%= link_to 'Show', announcement %></td>
24 23 <td><%= link_to 'Edit', edit_announcement_path(announcement) %></td>
25 24 <td><%= link_to 'Destroy', announcement, :confirm => 'Are you sure?', :method => :delete %></td>
26 25 </tr>
27 26 <% end %>
28 27 </table>
29 28
30 29 <br />
31 30
32 31 <%= link_to 'New announcement', new_announcement_path %>
@@ -1,31 +1,36
1 1 <h1>New announcement</h1>
2 2
3 3 <%= error_messages_for :announcement %>
4 4
5 5 <% form_for(@announcement) do |f| %>
6 6 <p>
7 7 <b>Body</b><br />
8 8 <%= f.text_area :body %>
9 9 </p>
10 10
11 11 <p>
12 12 <b>Author</b><br />
13 13 <%= f.text_field :author %>
14 14 </p>
15 15
16 16 <p>
17 17 <b>Published</b><br />
18 18 <%= f.check_box :published %>
19 19 </p>
20 20
21 21 <p>
22 22 <b>Show on front page?</b><br />
23 23 <%= f.check_box :frontpage %>
24 24 </p>
25 25
26 26 <p>
27 + <b>Show only in contest?</b><br />
28 + <%= f.check_box :contest_only %>
29 + </p>
30 +
31 + <p>
27 32 <%= f.submit "Create" %>
28 33 </p>
29 34 <% end %>
30 35
31 36 <%= link_to 'Back', announcements_path %>
@@ -1,23 +1,27
1 1 <p>
2 2 <b>Author:</b>
3 3 <%=h @announcement.author %>
4 4 </p>
5 5
6 6 <p>
7 7 <b>Body:</b>
8 8 <%=h @announcement.body %>
9 9 </p>
10 10
11 11 <p>
12 12 <b>Published:</b>
13 13 <%=h @announcement.published %>
14 14 </p>
15 15
16 16 <p>
17 17 <b>Show on front page:</b>
18 18 <%=h @announcement.frontpage %>
19 19 </p>
20 20
21 + <p>
22 + <b>Show only in contest:</b>
23 + <%=h @announcement.contest_only %>
24 + </p>
21 25
22 26 <%= link_to 'Edit', edit_announcement_path(@announcement) %> |
23 27 <%= link_to 'Back', announcements_path %>
@@ -1,30 +1,31
1 1 - content_for :head do
2 2 = javascript_include_tag :defaults
3 3
4 - %h1 Grader configuration
4 + %h1 System configuration
5 5
6 6 %table.info
7 7 %tr.info-head
8 8 %th Key
9 9 %th Type
10 10 %th Value
11 11
12 12 - @configurations.each do |conf|
13 13 - @configuration = conf
14 14 %tr
15 15 %td
16 16 = in_place_editor_field :configuration, :key, {}, :rows=>1
17 17 %td
18 18 = in_place_editor_field :configuration, :value_type, {}, :rows=>1
19 19 %td
20 20 = in_place_editor_field :configuration, :value, {}, :rows=>1
21 21
22 + - if Configuration.cache?
22 23 %br/
23 24 Your config is saved, but it does not automatically take effect.
24 25 %br/
25 26 If you have one mongrel process running, you can
26 27 = link_to '[click]', :action => 'reload'
27 28 here to reload.
28 29 %br/
29 30 If you have more than one process running, you should restart
30 31 them manually.
@@ -1,25 +1,27
1 1 - content_for :head do
2 2 = stylesheet_link_tag 'graders'
3 3 <meta http-equiv ="refresh" content="10"/>
4 4
5 - %h2 (Under Experiments)
5 + %h1 Grader information
6 6
7 7 - form_for :clear, nil, :url => {:action => 'clear_all'} do |f|
8 8 = submit_tag 'Clear all data'
9 9
10 + - if @last_task
10 11 Last task:
11 12 = link_to "#{@last_task.id}", :action => 'view', :id => @last_task.id, :type => 'Task'
12 13
13 14 %br/
14 15
16 + - if @last_test_request
15 17 Last test_request:
16 18 = link_to "#{@last_test_request.id}", :action => 'view', :id => @last_test_request.id, :type => 'TestRequest'
17 19
18 20
19 21 %h3 Current graders
20 22
21 23 = render :partial => 'grader_list', :locals => {:grader_list => @grader_processes}
22 24
23 25 %h3 Stalled graders
24 26
25 27 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
@@ -1,4 +1,4
1 1 .announcement
2 2 = markdown(announcement.body)
3 - .pub-info
4 - %p= "#{announcement.author}, #{announcement.created_at}"
3 + -#.pub-info
4 + -# %p= "#{announcement.author}, #{announcement.created_at}"
@@ -1,18 +1,18
1 1 <tr class="info-<%= (problem_counter%2==0) ? "even" : "odd" %>">
2 2 <td>
3 3 <%= "#{problem_counter+1}" %>
4 4 </td>
5 5 <td>
6 6 <%= "#{problem.full_name} (#{problem.name})" %>
7 - <%= link_to '[desc]', problem.url, :popup => true if (problem.url!=nil) and (problem.url!='') %>
7 + <%= link_to "[#{t 'main.problem_desc'}]", problem.url, :popup => true if (problem.url!=nil) and (problem.url!='') %>
8 8 </td>
9 9 <td align="center">
10 10 <%= @prob_submissions[problem_counter][:count] %>
11 11 </td>
12 12 <td>
13 13 <%= render :partial => 'submission_short',
14 14 :locals => {
15 15 :submission => @prob_submissions[problem_counter][:submission],
16 16 :problem_name => problem.name }%>
17 17 </td>
18 18 </tr>
@@ -1,8 +1,8
1 1 <% form_tag({:action => 'submit'}, :multipart => true) do %>
2 2 Problem: <%= select 'submission', 'problem_id',
3 - [['Specified in header','-1']] +
3 + [[(t 'main.specified_in_header'),'-1']] +
4 4 @problems.collect {|p| [p.full_name, p.id]},
5 5 :selected => '-1' %>
6 6 File: <%= file_field_tag 'file' %>
7 7 <%= submit_tag 'Submit' %>
8 8 <% end %>
@@ -1,23 +1,26
1 1
2 2 - if submission==nil
3 3 = "-"
4 4 - else
5 5 - if submission.graded_at==nil
6 - Submitted at
7 - = format_short_time(submission.submitted_at)
6 + =t 'main.submitted_at'
7 + = format_short_time(submission.submitted_at.localtime)
8 8 - else
9 - = "Graded at #{format_short_time(submission.graded_at)}, "
10 - = "score: #{(submission.points*100/submission.problem.full_score).to_i} " if Configuration['ui.show_score']
9 + = t 'main.graded_at'
10 + = "#{format_short_time(submission.graded_at.localtime)}, "
11 + - if Configuration['ui.show_score']
12 + = t 'main.score'
13 + = "#{(submission.points*100/submission.problem.full_score).to_i} "
11 14 = " ["
12 15 %tt
13 16 = submission.grader_comment
14 17 = "]"
15 18 - if Configuration.show_grading_result
16 19 = " | "
17 20 = link_to '[detailed result]', :action => 'result', :id => submission.id
18 21 = " | "
19 - = link_to('[msg]', {:action => 'compiler_msg', :id => submission.id}, {:popup => true})
22 + = link_to("[#{t 'main.cmp_msg'}]", {:action => 'compiler_msg', :id => submission.id}, {:popup => true})
20 23 = " | "
21 - = link_to('[src]',{:action => 'source', :id => submission.id})
24 + = link_to("[#{t 'main.src_link'}]",{:action => 'source', :id => submission.id})
22 25 = " | "
23 - = link_to '[submissions]', :action => 'submission', :id => problem_name
26 + = link_to "[#{t 'main.submissions_link'}]", :action => 'submission', :id => problem_name
@@ -1,56 +1,47
1 1 = user_title_bar(@user)
2 2
3 3 .announcementbox
4 4 %span{:class => 'title'}
5 - How to submit
5 + =t 'help.how_to_submit'
6 6 .announcement
7 7 %p
8 - You <b>must</b> specify the language you are using
9 - in your program header. You can optionally
10 - specify the task you are submitting to.
8 + =t 'help.must_specify_language'
11 9
12 10 %p
13 - The possible language options are
14 - <tt>C</tt>, <tt>C++</tt>, and <tt>Pascal</tt>.
15 - The follow are examples.
11 + =t 'help.list_available_language'
16 12
17 13 %table{:border => '1'}
18 14 %tr
19 - %th{:width => '100px'} C
20 - %th{:width => '100px'} C++
21 - %th{:width => '100px'} Pascal
15 + %th{:width => '150px'} C
16 + %th{:width => '150px'} C++
17 + %th{:width => '150px'} Pascal
22 18 %tr
23 19 %td= "<tt>/*<br/>LANG: C<br/>*/</tt>"
24 20 %td= "<tt>/*<br/>LANG: C++<br/>*/</tt>"
25 21 %td= "<tt>{<br/>LANG: Pascal<br/>}</tt>"
26 22
27 23 %p
28 - The server <b>will not</b> accept your submission,
29 - if you do not specify the language.
24 + =t 'help.accept_only_language_specified'
30 25
31 26 %p
32 - Optionally, you can also specify
33 - the task with <tt>TASK:</tt> <i>taskname</i>.
34 - On the first page, the taskname for each task is
35 - shown in parentheses.
27 + =t 'help.specifying_task'
36 28
37 29 %p
38 - For example, suppose you are using <tt>C++</tt>
39 - to write task <b>mobiles</b>, you put
30 + =t 'help.example_cpp'
40 31
41 32 %table{:border => '1'}
42 33 %tr
43 - %td{:width => '100px'}
34 + %td{:width => '300px'}
44 35 %tt <tt>/*<br/>LANG: C++<br/>TASK: mobiles<br/>*/</tt>
45 36
46 37 %p
47 - on top of your source code.
48 - If you are using <tt>Pascal</tt> to write the same task,
49 - you'll use
38 + =t 'help.example_pas'
50 39
51 40 %table{:border => '1'}
52 41 %tr
53 - %td{:width => '100px'}
42 + %td{:width => '300px'}
54 43 %tt <tt>{<br/>LANG: Pascal<br/>TASK: mobiles<br/>}</tt>
55 44
45 + %p
46 + = (t('help.ask_questions_at_messages',:message_link_name => (t 'menu.messages'),:url => url_for(:controller => 'messages', :action => 'list')))
56 47
@@ -1,30 +1,30
1 1 = user_title_bar(@user)
2 2
3 3 - if @announcements.length!=0
4 4 .announcementbox
5 5 %span{:class => 'title'}
6 6 Announcements
7 7 = render :partial => 'announcement', :collection => @announcements
8 8
9 9 - if Configuration.show_submitbox_to?(@user)
10 10 .submitbox
11 11 = error_messages_for 'submission'
12 12 = render :partial => 'submission_box'
13 13
14 14
15 15 %hr/
16 16
17 17 - if (@user.site!=nil) and (@user.site.started!=true)
18 - %p The contest at your site will start soon. Please wait.
18 + %p=t 'main.start_soon'
19 19
20 20 - if Configuration.show_tasks_to?(@user)
21 21 %table.info
22 22 %tr.info-head
23 23 %th
24 24 %th Tasks
25 25 %th # of sub(s)
26 26 %th Results
27 27 = render :partial => 'problem', :collection => @problems
28 28
29 29 %hr/
30 30
@@ -1,70 +1,42
1 1 %h1= Configuration['ui.front.title']
2 2
3 3 - if @announcements.length!=0
4 4 .announcementbox
5 5 %span{:class => 'title'}
6 6 Announcements
7 7 = render :partial => 'announcement', :collection => @announcements
8 8
9 9 %b= Configuration['ui.front.welcome_message']
10 10 %br/
11 11
12 12 - if !@hidelogin
13 - Please login to see the problem list.
13 + =t 'login.message'
14 14 %br/
15 15 %br/
16 16
17 17 - if flash[:notice]
18 18 %hr/
19 19 %b= flash[:notice]
20 20 %hr/
21 21
22 22 %div{ :style => "border: solid 1px gray; padding: 2px; background: #f0f0f0;"}
23 23 - form_tag :controller => 'login', :action => 'login' do
24 24 %table
25 25 %tr
26 - %td{:align => "right"} Login:
26 + %td{:align => "right"}
27 + ="#{t 'login_label'}:"
27 28 %td= text_field_tag 'login'
28 29 %tr
29 - %td{:align => "right"} Password:
30 + %td{:align => "right"}
31 + ="#{t 'password_label'}:"
30 32 %td= password_field_tag
31 - = submit_tag 'Login'
33 + = submit_tag t('login.login_submit')
32 34 %br/
33 35
34 36 - if Configuration['system.online_registration']
35 - Want to participate?
37 + =t 'login.participation'
36 38 %b
37 - Please
38 - = link_to 'register.', :controller => :users, :action => :new
39 + = "#{t 'login.please'} "
40 + = link_to "#{t 'login.register'}", :controller => :users, :action => :new
39 41 %br/
40 42
41 - - if (Configuration['system.mode']=='contest') and (Configuration['contest.multisites'])
42 - %script{:type => 'text/javascript'}
43 - var siteList = new Array();
44 - - @countries.each do |country|
45 - = "siteList[#{country.id}] = new Array();"
46 - - country.sites.each do |site|
47 - = "siteList[#{country.id}][#{site.id}] = \"#{site.name}\";"
48 -
49 - var allSiteList = new Array();
50 - - @site_select.each do |sel|
51 - = "allSiteList[#{sel[1]}]=\"#{sel[0]}\";"
52 -
53 - %script{:type => 'text/javascript', :src => '/javascripts/site_update.js'}
54 -
55 - %div{ :style => "border: solid 1px gray; padding: 2px; background: #f0f0f0;"}
56 - %b For Site Administrator.
57 - %br/
58 - Please select your country and site and login.
59 - - form_for :login, nil, :url => {:controller => 'login', :action => 'site_login'} do |f|
60 - Country:
61 - = select :site_country, :id, @country_select_with_all, {}, {:onchange => "updateSiteList();", :onclick => "updateSiteList();" }
62 - Site:
63 - = select :login, :site_id, @site_select
64 - %br/
65 - Password:
66 - = f.password_field :password
67 - = submit_tag "Site Administrator Login"
68 -
69 - %script{:type => 'text/javascript'}
70 - updateSiteList();
@@ -1,46 +1,45
1 1 <% content_for :head do %>
2 - <%= stylesheet_link_tag 'scaffold' %>
3 2 <%= stylesheet_link_tag 'problems' %>
4 3 <%= javascript_include_tag :defaults %>
5 4 <% end %>
6 5
7 6 <h1>Listing problems</h1>
8 7
9 8 <p>
10 9 <%= link_to 'New problem', :action => 'new' %>
11 10 <%= link_to 'Turn off all problems', :action => 'turn_all_off' %>
12 11 <%= link_to 'Turn on all problems', :action => 'turn_all_on' %>
13 12 </p>
14 13
15 14 <table>
16 15 <tr>
17 16 <th>Name</th>
18 17 <th>Full name</th>
19 18 <th>Full score</th>
20 19 <th>Date added</th>
21 20 <th>Avail?</th>
22 21 <th>Test?</th>
23 22 </tr>
24 23
25 24 <% for problem in @problems %>
26 25 <tr id="prob-<%= problem.id %>" name="prob-<%= problem.id %>" class="<%= (problem.available) ? "available" : "not-available" %>">
27 26 <% @problem=problem %>
28 27 <td><%= in_place_editor_field :problem, :name, {}, :rows=>1 %></td>
29 28 <td><%= in_place_editor_field :problem, :full_name, {}, :rows=>1 %></td>
30 29 <td><%= in_place_editor_field :problem, :full_score, {}, :rows=>1 %></td>
31 30 <td><%= problem.date_added %></td>
32 31 <td id="prob-<%= problem.id %>-avail"><%= problem.available %></td>
33 32 <td><%= problem.test_allowed %></td>
34 33
35 34 <td><%= link_to_remote '[Toggle]', :url => {:action => 'toggle', :id => problem.id } %></td>
36 35 <td><%= link_to '[Stat]', :action => 'stat', :id => problem.id %></td>
37 36 <td><%= link_to '[Show]', :action => 'show', :id => problem %></td>
38 37 <td><%= link_to '[Edit]', :action => 'edit', :id => problem %></td>
39 38 <td><%= link_to '[Destroy]', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :post %></td>
40 39 </tr>
41 40 <% end %>
42 41 </table>
43 42
44 43 <br />
45 44
46 45 <%= link_to 'New problem', :action => 'new' %>
@@ -1,26 +1,26
1 1 <h1>Problem stat: <%= @problem.name %></h1>
2 2
3 3 <i>This is just a hack. Really not efficient.</i><br/><br/>
4 4
5 5 <% if @submissions!=nil %>
6 6 <table class="info">
7 7 <tr class="info-head">
8 8 <th>user_id</th>
9 9 <th>submitted_at</th>
10 10 <th>points</th>
11 11 <th>comment</th>
12 12 </tr>
13 13 <% count = 0 %>
14 14 <% @submissions.each do |sub| %>
15 15 <tr class="<%= (count % 2 ==0) ? "info-even" : "info-odd" %>">
16 - <td><%= sub.user.full_name %></td>
16 + <td><%= sub.user.full_name if sub.user %></td>
17 17 <td><%= sub.submitted_at.to_s %></td>
18 18 <td><%= sub.points %></td>
19 19 <td><div style="font-family: monospace"><%= sub.grader_comment %></div></td>
20 20 </tr>
21 21 <% count += 1 %>
22 22 <% end %>
23 23 </table>
24 24 <% else %>
25 25 No submission
26 26 <% end %>
@@ -1,24 +1,24
1 1 %h2
2 2 Contest Administration for site:
3 - = "#{@site.name}, #{@site.country.name}"
3 + = "#{@site.name}, #{@site.country.name if @site.country}"
4 4
5 5
6 6 Current time at the server is
7 7 = "#{format_short_time(Time.new.gmtime)} UTC"
8 8 (please
9 9 = link_to 'refresh', :action => 'index'
10 10 to update)
11 11 %br/
12 12 %br/
13 13
14 14 - form_tag :action => 'start' do
15 15 When you're ready, you can click the button below to start the contest.
16 16 %br/
17 17 Please make sure that the contestants are ready.
18 18 After the contest is started, it <b>cannot</b> be paused or stopped.
19 19 %br/
20 20 = submit_tag 'Start the Contest.', :onclick => "return confirm('Are you sure?');"
21 21
22 22 %br/
23 23 %br/
24 24 = link_to '[log out]', :action => 'logout'
@@ -1,31 +1,31
1 1 %h2
2 2 Contest Administration for site:
3 - = "#{@site.name}, #{@site.country.name}"
3 + = "#{@site.name}, #{@site.country.name if @site.country}"
4 4
5 5 - curr_time = Time.new.gmtime
6 6
7 7 - if @site.finished?
8 8 %h3 Contest ended.
9 9 - else
10 10 %h3 Contest started.
11 11
12 12 Current time at the server is
13 13 = "#{format_short_time(curr_time)} UTC"
14 14 (please
15 15 = link_to 'refresh', :action => 'index'
16 16 to update)
17 17 %br/
18 18 %br/
19 19
20 20 The contest at your site has been started at
21 21 = "#{format_short_time(@site.start_time)} UTC"
22 22
23 23 %br/
24 24
25 25 %h3
26 26 Time left:
27 27 = "#{Time.at(@site.time_left).gmtime.strftime("%X")}"
28 28
29 29 %br/
30 30 %br/
31 31 = link_to '[log out]', :action => 'logout'
@@ -1,27 +1,32
1 1 <h1>Editing site</h1>
2 2
3 3 <%= error_messages_for :site %>
4 4
5 5 <% form_for(@site) do |f| %>
6 6 <p>
7 7 <b>Name</b><br />
8 8 <%= f.text_field :name %>
9 9 </p>
10 10
11 11 <p>
12 + <b>Password</b><br />
13 + <%= f.text_field :password %>
14 + </p>
15 +
16 + <p>
12 17 <b>Started</b><br />
13 18 <%= f.check_box :started %>
14 19 </p>
15 20
16 21 <p>
17 22 <b>Start time</b><br />
18 23 <%= f.datetime_select :start_time %>
19 24 </p>
20 25
21 26 <p>
22 27 <%= f.submit "Update" %>
23 28 </p>
24 29 <% end %>
25 30
26 31 <%= link_to 'Show', @site %> |
27 32 <%= link_to 'Back', sites_path %>
@@ -1,27 +1,29
1 1 <h1>Listing sites</h1>
2 2
3 3 <table>
4 4 <tr>
5 5 <th>Name</th>
6 + <th>Password</th>
6 7 <th>Started</th>
7 8 <th>Start time</th>
8 9 </tr>
9 10
10 11 <% for site in @sites %>
11 12 <% background = "white" %>
12 13 <% background = "grey" if (site.started==true) and (site.finished? == true) %>
13 14 <% background = "lightgreen" if (site.started==true) and (site.finished? != true) %>
14 15 <tr style="background: <%= background %>;">
15 16 <td><%=h site.name %></td>
17 + <td><%=h site.password %></td>
16 18 <td><%=h site.started %></td>
17 19 <td><%=h site.start_time %></td>
18 20 <td><%= link_to 'Show', site %></td>
19 21 <td><%= link_to 'Edit', edit_site_path(site) %></td>
20 22 <td><%= link_to 'Destroy', site, :confirm => 'Are you sure?', :method => :delete %></td>
21 23 </tr>
22 24 <% end %>
23 25 </table>
24 26
25 27 <br />
26 28
27 29 <%= link_to 'New site', new_site_path %>
@@ -1,26 +1,31
1 1 <h1>New site</h1>
2 2
3 3 <%= error_messages_for :site %>
4 4
5 5 <% form_for(@site) do |f| %>
6 6 <p>
7 7 <b>Name</b><br />
8 8 <%= f.text_field :name %>
9 9 </p>
10 10
11 11 <p>
12 + <b>Password</b><br />
13 + <%= f.text_field :password %>
14 + </p>
15 +
16 + <p>
12 17 <b>Started</b><br />
13 18 <%= f.check_box :started %>
14 19 </p>
15 20
16 21 <p>
17 22 <b>Start time</b><br />
18 23 <%= f.datetime_select :start_time %>
19 24 </p>
20 25
21 26 <p>
22 27 <%= f.submit "Create" %>
23 28 </p>
24 29 <% end %>
25 30
26 31 <%= link_to 'Back', sites_path %>
@@ -1,18 +1,23
1 1 <p>
2 2 <b>Name:</b>
3 3 <%=h @site.name %>
4 4 </p>
5 5
6 6 <p>
7 + <b>Password:</b>
8 + <%=h @site.password %>
9 + </p>
10 +
11 + <p>
7 12 <b>Started:</b>
8 13 <%=h @site.started %>
9 14 </p>
10 15
11 16 <p>
12 17 <b>Start time:</b>
13 18 <%=h @site.start_time %>
14 19 </p>
15 20
16 21
17 22 <%= link_to 'Edit', edit_site_path(@site) %> |
18 23 <%= link_to 'Back', sites_path %>
@@ -1,112 +1,99
1 1 <%= user_title_bar(@user) %>
2 2
3 - <h2>Test Interface</h2>
3 + <h2><%=t 'test.title' %></h2>
4 4
5 - <p>
6 - <b>Note:</b> Test interface will be disabled in the last 30 minutes
7 - of the contest time on your site.
8 - </p>
5 + <div class="test-desc">
6 + <%=t 'test.intro' %><br/>
7 + <% if Configuration['contest.test_request.early_timeout'] %>
8 + <%=t 'test.disabled_at_end_announcement' %>
9 + <% end %>
10 + </div>
9 11
10 12 <% if @problems.length==0 %>
11 13 There is no submission
12 14 <% else %>
13 15
14 16 <script type="text/javascript">
15 17 var submissionCount = new Array();
16 18 <% @submissions.each do |submission| %>
17 19 submissionCount[<%= submission.problem_id %>]=<%= submission.number %>;
18 20 <% end %>
19 21
20 22 function updateSubmissionList() {
21 23 currentProb = document.getElementById("test_request_problem_id").value;
22 24 count = submissionCount[currentProb];
23 25 submissionSelect = document.getElementById("test_request_submission_number");
24 26 old_len = submissionSelect.length;
25 27 // clear the box
26 28 for(i=0; i<old_len; i++)
27 29 submissionSelect.remove(0);
28 30 for(i=count; i>=1; i--) {
29 31 try {
30 32 submissionSelect.add(new Option(""+i,""+i,false,false),null);
31 33 } catch(ex) {
32 34 submissionSelect.add(new Option(""+i,""+i,false,false));
33 35 }
34 36 }
35 37 }
36 38 </script>
37 39
38 40 <% if Configuration.show_submitbox_to?(@user) and Configuration.allow_test_request(@user) %>
39 41 <div class="submitbox">
40 42 <%= error_messages_for 'submitted_test_request' %>
41 43 <% form_for :test_request, nil,
42 44 :url => { :action => 'submit'},
43 45 :html => { :multipart => true } do |f| %>
44 46 <table>
45 47 <tr>
46 48 <td>Task:</td>
47 49 <td>
48 50 <%= select(:test_request,
49 51 :problem_id,
50 52 @problems.collect {|p| [p.name, p.id]}, {},
51 53 { :onclick => "updateSubmissionList();" }) %>
52 54 </td>
53 55 </tr>
54 56 <tr>
55 57 <td>Submission:</td>
56 58 <td>
57 59 <%= select(:test_request,
58 60 :submission_number,
59 61 ((1..@submissions[0].number).collect {|n| [n,n]}).reverse) %>
60 62 </td>
61 63 </tr>
62 64 <tr>
63 65 <td>Input data:</td>
64 66 <td>
65 67 <%= f.file_field :input_file %>
66 68 </td>
67 69 <td>
68 70 (combined size should not exceed 2MB)
69 71 </td>
70 72 </tr>
71 73 <tr>
72 - <td>
73 - Additional file<sup><span style="color:red">*</span></sup>:
74 - </td>
75 - <td>
76 - <%= f.file_field :additional_file %>
77 - </td>
78 - <td>
79 - <small>
80 - * This option works <u>only</u> for task beads.
81 - You can use this to submit <tt>questions.txt</tt>.<br/>
82 - The file shall be copied to the execution directory before your program runs.
83 - </small>
84 - </td>
85 - </tr>
86 - <tr>
87 74 <td colspan="2">
88 75 <%= submit_tag 'submit' %>
89 76 </td>
90 77 </tr>
91 78 </table>
92 79 <% end %>
93 80 </div>
94 81 <% end %>
95 82
96 83 <h3>Previous requests</h3>
97 84
98 85 <table class="info">
99 86 <tr class="info-head">
100 87 <th>at</th>
101 88 <th>problem</th>
102 89 <th>sub #</th>
103 90 <th>status</th>
104 91 <th>output (first 2kb)</th>
105 92 <th>compiler message</th>
106 93 <th>detail</th>
107 94 </tr>
108 95 <%= render :partial => 'test_request', :collection => @test_requests %>
109 96 </table>
110 97
111 98 <% end %>
112 99
@@ -1,38 +1,40
1 1 = user_title_bar(@user)
2 2
3 3 %div{:style => "text-align: center; font-size: 12px"}
4 4 Problem:
5 5 - if @test_request.problem!=nil
6 6 = "#{@test_request.problem.full_name}"
7 7 - else
8 8 = "(n/a)"
9 9 %br/
10 10 = "Submission: #{@test_request.submission.number}"
11 11 %br/
12 12 = "Test submitted at: #{format_short_time(@test_request.submitted_at)}"
13 13 %br/
14 14 = "Execution time: #{@test_request.running_time} s."
15 15 %br/
16 16 = "Memory usage: #{@test_request.memory_usage}kb"
17 17 %br/
18 18 %b= @test_request.exit_status
19 19 %br/
20 20
21 21 - if @test_request.compiler_message!=nil and @test_request.compiler_message!=''
22 22 %b Compiler Message
23 23 %div{:style => "border: 1px solid black; background: lightgrey"}
24 24 = simple_format((@test_request.compiler_message or ''))
25 25
26 26 %b Input (first 2kb)
27 27 %div{:style => "border: 1px solid black; background: lightgrey"}
28 28 - if @test_request.input_file_name!=nil
29 29 %pre
30 + = ""
30 31 = h(read_textfile(@test_request.input_file_name,2048))
31 32
32 33 %b Output (first 2kb)
33 34 %div{:style => "border: 1px solid black; background: lightgrey"}
34 35 - if @test_request.output_file_name!=nil
35 36 %pre
37 + = ""
36 38 = h(read_textfile(@test_request.output_file_name,2048))
37 39 - else
38 40 (no output)
@@ -1,19 +1,22
1 1 <%= error_messages_for 'user' %>
2 2
3 3 <!--[form:user]-->
4 4 <p><label for="user_name">Login</label><br/>
5 5 <%= text_field 'user', 'login' %></p>
6 6
7 7 <p><label for="user_name">Full name</label><br/>
8 8 <%= text_field 'user', 'full_name' %></p>
9 9
10 10 <p><label for="password">Password</label><br/>
11 11 <%= password_field 'user', 'password' %></p>
12 12
13 13 <p><label for="password_confirmation">Password (confirm)</label><br/>
14 14 <%= password_field 'user', 'password_confirmation' %></p>
15 15
16 + <p><label for="user_email">E-mail</label><br/>
17 + <%= text_field 'user', 'email' %></p>
18 +
16 19 <p><label for="user_alias">Alias</label><br/>
17 20 <%= text_field 'user', 'alias' %></p>
18 21 <!--[eoform:user]-->
19 22
@@ -1,57 +1,57
1 - <% content_for :head do %>
2 - <%= stylesheet_link_tag 'scaffold' %>
3 - <% end %>
4 -
5 1 <h1>Listing users</h1>
6 2
7 3 <div class="submitbox">
8 4 <b>Quick add</b>
9 5 <% form_tag :action => 'create' do %>
10 6 <table border="0">
11 7 <tr>
12 8 <td><label for="user_login">Login</label></td>
13 9 <td><label for="user_full_name">Full name</label></td>
14 - <td><label for="user_alias">Alias</label></td>
15 10 <td><label for="user_password">Password</label></td>
16 - <td><label for="user_password_confirmation">confirm</label></td>
11 + <td><label for="user_password_confirmation">Confirm</label></td>
12 + <td><label for="user_email">Email</label></td>
17 13 </tr>
18 14 <tr>
19 15 <td><%= text_field 'user', 'login', :size => 10 %></td>
20 16 <td><%= text_field 'user', 'full_name', :size => 30 %></td>
21 - <td><%= text_field 'user', 'alias', :size => 10 %></td>
22 17 <td><%= password_field 'user', 'password', :size => 10 %></td>
23 18 <td><%= password_field 'user', 'password_confirmation', :size => 10 %></td>
19 + <td><%= text_field 'user', 'email', :size => 15 %></td>
24 20 <td><%= submit_tag "Create" %></td>
25 21 </tr></table>
26 22 <% end %>
27 23 <br/>
28 24 <b>Import from site management</b>
29 25 <% form_tag({:action => 'import'}, :multipart => true) do %>
30 26 File: <%= file_field_tag 'file' %> <%= submit_tag 'Import' %>
31 27 <% end %>
32 28
33 29 </div>
34 30 <table>
35 31 <tr>
36 32 <% for column in User.content_columns %>
33 + <% if !@hidden_columns.index(column.name) %>
37 34 <th><%= column.human_name %></th>
38 35 <% end %>
36 + <% end %>
39 37 </tr>
40 38
41 39 <% for user in @users %>
42 40 <tr>
43 41 <% for column in User.content_columns %>
42 + <% if !@hidden_columns.index(column.name) %>
44 43 <td><%=h user.send(column.name) %></td>
45 44 <% end %>
45 + <% end %>
46 46 <td><%= link_to 'Show', :action => 'show', :id => user %></td>
47 47 <td><%= link_to 'Edit', :action => 'edit', :id => user %></td>
48 48 <td><%= link_to 'Destroy', { :action => 'destroy', :id => user }, :confirm => 'Are you sure?', :method => :post %></td>
49 49 </tr>
50 50 <% end %>
51 51 </table>
52 52
53 53
54 54 <br />
55 55
56 56 <%= link_to 'New user', :action => 'new' %>
57 57 <%= link_to 'New list of users', :action => 'new_list' %>
@@ -1,30 +1,35
1 1 <h1>User grading results</h1>
2 2
3 3 <table class="info">
4 - <tr class="info-head"><th>User</th><th>Name</th>
4 + <tr class="info-head">
5 + <th>User</th>
6 + <th>Name</th>
7 + <th>Activated?</th>
5 8 <% @problems.each do |p| %>
6 9 <th><%= p.name %></th>
7 10 <% end %>
8 11 <th>Total</th>
9 12 <th>Passed</th>
10 13 </tr>
11 14 <% counter = 0 %>
12 15 <% @scorearray.each do |sc| %>
13 16 <tr class="<%= (counter %2 ==0) ? "info-even" : "info-odd" %>">
14 17 <% total = 0 %>
15 18 <% num_passed = 0 %>
16 19 <% sc.each_index do |i| %>
17 - <% if i<=1 %>
18 - <td><%= sc[i] %></td>
20 + <% if i==0 %>
21 + <td><%= sc[i].login %></td>
22 + <td><%= sc[i].full_name %></td>
23 + <td><%= sc[i].activated %></td>
19 24 <% else %>
20 25 <td><%= sc[i][0] %></td>
21 26 <% total += sc[i][0] %>
22 27 <% num_passed += 1 if sc[i][1] %>
23 28 <% end %>
24 29 <% end %>
25 30 <td><%= total %></td>
26 31 <td><%= num_passed %></td>
27 32 </tr>
28 33 <% counter += 1 %>
29 34 <% end %>
30 35 </table>
@@ -1,15 +1,17
1 1 - if @result == :successful
2 - %h1 User activated
3 - Your account has been activated.
2 + %h1
3 + =t 'registration.activation_sucessful_title'
4 + =t 'registration.account_activated'
4 5 %br/
5 - Please go ahead to
6 - = link_to 'login.', :controller => 'main', :action => 'login'
6 + =t 'go_ahead_to'
7 + = link_to((t 'login_page'), {:controller => 'main', :action => 'login'})
7 8 - else
8 - %h1 Activation failed
9 + %h1
10 + =t 'registration.activation_failed_title'
9 11 - if @result == :email_used
10 - A user with this E-mail exists.
12 + =t 'registration.errors.activation.email_exists'
11 13 - else
12 - Your activation code is invalid. Please check again.
14 + =t 'registration.errors.activation.invalid'
13 15 %br/
14 - Get back to
15 - = link_to 'home.', :controller => 'main', :action => 'login'
16 + =t 'go_back_to'
17 + = link_to((t 'home_page'), {:controller => 'main', :action => 'login'})
@@ -1,9 +1,8
1 - %h1 Errors in sending registration confirmation
1 + %h1
2 + =t 'registration.errors.email.title'
2 3
3 4 .errorExplanation
4 - %h2
5 - Your user account has been created, but the system cannot send you the
6 - confirmation e-mail.
5 + =t 'registration.errors.email.expl', :email => @admin_email
7 6
8 - Maybe there's a problem in the configuration. Please report the
9 - admin. Thank you!
7 + =t 'go_back_to'
8 + =link_to((t 'login_page'), {:controller => 'main', :action => 'login'})
@@ -1,39 +1,38
1 1 - content_for :head do
2 2 = javascript_include_tag :defaults
3 3
4 4 = user_title_bar(@user)
5 5
6 6 %h1 Your account settings
7 7
8 - %p
9 - You can edit your alias and e-mails. Just click on the text and edit it.
10 -
8 + -#%p
9 + -#You can edit your alias and e-mails. Just click on the text and edit it.
11 10
12 11 %table.uinfo
13 12 %tr
14 13 %th.uinfo Login
15 14 %td.uinfo= @user.login
16 15 %tr
17 16 %th.uinfo Full name
18 17 %td.uinfo= @user.full_name
19 - %tr
20 - %th.uinfo Alias
21 - %td.uinfo= in_place_editor_field :user, 'alias_for_editing', {}, :rows => 1
22 - %tr
23 - %th.uinfo E-mail
24 - %td.uinfo= in_place_editor_field :user, 'email_for_editing', {}, :rows => 1
18 + -#%tr
19 + -#%th.uinfo Alias
20 + -#%td.uinfo= in_place_editor_field :user, 'alias_for_editing', {}, :rows => 1
21 + -#%tr
22 + -#%th.uinfo E-mail
23 + -#%td.uinfo= in_place_editor_field :user, 'email_for_editing', {}, :rows => 1
25 24 %tr
26 25 %th.uinfo Password
27 26 %td.uinfo
28 27 - form_tag :action => 'chg_passwd', :method => 'post' do
29 28 %table
30 29 %tr
31 30 %td= password_field_tag 'passwd'
32 31 %td (new)
33 32 %tr
34 33 %td= password_field_tag 'passwd_verify'
35 34 %td (verify)
36 35 %tr
37 36 %td{:colspan => "2"}
38 37 = submit_tag 'change password'
39 38
@@ -1,29 +1,39
1 - %h1 New user registration
1 + .contest-title
2 + %h1
3 + = "#{Configuration['contest.name']}: #{t 'registration.title'}"
2 4
3 - = error_messages_for :user, :header_message => 'Errors occured during registration'
5 + .registration-desc
6 + =t 'registration.description'
7 +
8 + = error_messages_for :user, :header_message => (t 'registration.errors.header')
4 9
5 10 %table
6 11 - form_for :user, @user, :url => { :action => 'register' } do |f|
7 12 %tr
8 - %td Login:
13 + %td{:align => "right"}
14 + = "#{t 'login_label'}:"
9 15 %td= f.text_field :login
10 16 %tr
11 17 %td
12 18 %td
13 - %small Only a-z, A-Z, 0-9 and _
19 + %small
20 + =t 'registration.login_guide'
14 21 %tr
15 - %td Full name:
22 + %td{:align => "right"}
23 + = "#{t 'full_name_label'}:"
16 24 %td= f.text_field :full_name
17 25 %tr
18 - %td E-mail:
26 + %td{:align => "right"}
27 + = "#{t 'email_label'}:"
19 28 %td= f.text_field :email
20 29 %tr
21 30 %td
22 31 %td
23 32 %small
24 - Please make sure that your e-mail is correct.
25 - %br/
26 - You'll need to verify your account by email.
33 + =t 'registration.email_guide'
27 34 %tr
28 - %td{:colspan => 2}= submit_tag "Register"
35 + %td/
36 + %td
37 + = submit_tag((t 'registration.register'), :name => 'commit')
38 + = submit_tag((t 'cancel'), :name => 'cancel')
29 39
@@ -1,11 +1,11
1 - %h1 Registration successful
1 + %h1
2 + =t 'registration.successful_title'
2 3
3 - We have sent a confimation message to your e-mail.
4 + =t 'registration.email_sent'
4 5 %br/
5 - Please check at
6 - = "#{@user.email}."
6 + =t 'registration.email_verify_at', :email => @user.email
7 7 %br/
8 8 %br/
9 9
10 - Go back to
11 - = link_to 'login page.', :controller => 'main', :action => 'login'
10 + =t 'go_back_to'
11 + =link_to((t 'login_page'), {:controller => 'main', :action => 'login'})
@@ -1,77 +1,89
1 1 # Be sure to restart your web server when you modify this file.
2 2
3 3 # Uncomment below to force Rails into production mode when
4 4 # you don't control web/app server and can't set it the proper way
5 5 # ENV['RAILS_ENV'] ||= 'production'
6 6
7 7 # Specifies gem version of Rails to use when vendor/rails is not present
8 - RAILS_GEM_VERSION = '2.1.1' unless defined? RAILS_GEM_VERSION
8 + RAILS_GEM_VERSION = '2.3.2' unless defined? RAILS_GEM_VERSION
9 9
10 10 # Bootstrap the Rails environment, frameworks, and default configuration
11 11 require File.join(File.dirname(__FILE__), 'boot')
12 12
13 13 Rails::Initializer.run do |config|
14 14 # Settings in config/environments/* take precedence over those specified here
15 15
16 16 # Skip frameworks you're not going to use (only works if using vendor/rails)
17 17 # config.frameworks -= [ :action_web_service, :action_mailer ]
18 18
19 19 # Only load the plugins named here, by default all plugins in vendor/plugins are loaded
20 20 # config.plugins = %W( exception_notification ssl_requirement )
21 21
22 22 # Add additional load paths for your own custom dirs
23 23 # config.load_paths += %W( #{RAILS_ROOT}/extras )
24 24
25 25 # Force all environments to use the same logger level
26 26 # (by default production uses :info, the others :debug)
27 27 # config.log_level = :debug
28 28
29 29 # Use the database for sessions instead of the file system
30 30 # (create the session table with 'rake db:sessions:create')
31 31 config.action_controller.session_store = :active_record_store
32 32
33 33 # Use SQL instead of Active Record's schema dumper when creating the test database.
34 34 # This is necessary if your schema can't be completely dumped by the schema dumper,
35 35 # like if you have constraints or database-specific column types
36 36 # config.active_record.schema_format = :sql
37 37
38 38 # Activate observers that should always be running
39 39 # config.active_record.observers = :cacher, :garbage_collector
40 40
41 41 # Make Active Record use UTC-base instead of local time
42 - config.active_record.default_timezone = :utc
42 + config.time_zone = 'UTC'
43 +
44 + # Setting locales
45 + config.i18n.default_locale = 'th'
43 46
44 47 # See Rails::Configuration for more options
45 48
46 49 # -------------
47 50 # Required gems
48 51 # -------------
49 -
50 - # This is for rspec
51 - config.gem "rspec-rails", :lib => "spec"
52 52 config.gem "haml"
53 53 config.gem "tmail"
54 - #config.gem "BlueCloth", :lig => "bluecloth"
54 + config.gem "BlueCloth", :lib => "bluecloth"
55 +
56 + # NOTES on rspec: if you wan to test with rspec, you have to install
57 + # rspec yourself, just call: [sudo] gem install rspec-rails
58 +
55 59 end
56 60
57 61 # Add new inflection rules using the following format
58 62 # (all these examples are active by default):
59 63 # Inflector.inflections do |inflect|
60 64 # inflect.plural /^(ox)$/i, '\1en'
61 65 # inflect.singular /^(ox)en/i, '\1'
62 66 # inflect.irregular 'person', 'people'
63 67 # inflect.uncountable %w( fish sheep )
64 68 # end
65 69
66 70 # Add new mime types for use in respond_to blocks:
67 71 # Mime::Type.register "text/richtext", :rtf
68 72 # Mime::Type.register "application/x-mobile", :mobile
69 73
70 74 # Include your application configuration below
71 75
72 76 # These are where inputs and outputs of test requests are stored
73 77 TEST_REQUEST_INPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/input'
74 78 TEST_REQUEST_OUTPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/output'
75 79
80 + # To use ANALYSIS MODE, provide the testcases/testruns breakdown,
81 + # and the directory of the grading result (usually in judge's dir).
82 + TASK_GRADING_INFO_FILENAME = RAILS_ROOT + '/config/tasks.yml'
83 + GRADING_RESULT_DIR = '/home/thailandoi/ytopc/judge/result'
84 +
76 85 # Uncomment so that configuration is read only once when the server is loaded
77 86 # Configuration.enable_caching
87 +
88 + # Uncomment so that the system validates user e-mails
89 + # VALIDATE_USER_EMAILS = true
@@ -1,21 +1,20
1 1 # Settings specified here will take precedence over those in config/environment.rb
2 2
3 3 # In the development environment your application's code is reloaded on
4 4 # every request. This slows down response time but is perfect for development
5 5 # since you don't have to restart the webserver when you make code changes.
6 6 config.cache_classes = false
7 7
8 8 # Log error messages when you accidentally call methods on nil.
9 9 config.whiny_nils = true
10 10
11 11 # Enable the breakpoint server that script/breakpointer connects to
12 12 #config.breakpoint_server = true
13 13
14 14 # Show full error reports and disable caching
15 15 config.action_controller.consider_all_requests_local = true
16 16 config.action_controller.perform_caching = false
17 - config.action_view.cache_template_extensions = false
18 17 config.action_view.debug_rjs = true
19 18
20 19 # Don't care if the mailer can't send
21 20 config.action_mailer.raise_delivery_errors = false
@@ -1,19 +1,19
1 1 # Settings specified here will take precedence over those in config/environment.rb
2 2
3 3 # The test environment is used exclusively to run your application's
4 4 # test suite. You never need to work with it otherwise. Remember that
5 5 # your test database is "scratch space" for the test suite and is wiped
6 6 # and recreated between test runs. Don't rely on the data there!
7 7 config.cache_classes = true
8 8
9 9 # Log error messages when you accidentally call methods on nil.
10 10 config.whiny_nils = true
11 11
12 12 # Show full error reports and disable caching
13 13 config.action_controller.consider_all_requests_local = true
14 14 config.action_controller.perform_caching = false
15 15
16 16 # Tell ActionMailer not to deliver emails to the real world.
17 17 # The :test delivery method accumulates sent emails in the
18 18 # ActionMailer::Base.deliveries array.
19 - config.action_mailer.delivery_method = :test No newline at end of file
19 + config.action_mailer.delivery_method = :test
@@ -1,68 +1,69
1 1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 3 # then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 6 # to create the application database on another system, you should be using db:schema:load, not running
7 7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11
12 - ActiveRecord::Schema.define(:version => 20081210021333) do
12 + ActiveRecord::Schema.define(:version => 20090206145016) do
13 13
14 14 create_table "announcements", :force => true do |t|
15 15 t.string "author"
16 16 t.text "body"
17 17 t.boolean "published"
18 18 t.datetime "created_at"
19 19 t.datetime "updated_at"
20 20 t.boolean "frontpage", :default => false
21 + t.boolean "contest_only", :default => false
21 22 end
22 23
23 24 create_table "configurations", :force => true do |t|
24 25 t.string "key"
25 26 t.string "value_type"
26 27 t.string "value"
27 28 t.datetime "created_at"
28 29 t.datetime "updated_at"
29 30 end
30 31
31 32 create_table "countries", :force => true do |t|
32 33 t.string "name"
33 34 t.datetime "created_at"
34 35 t.datetime "updated_at"
35 36 end
36 37
37 38 create_table "descriptions", :force => true do |t|
38 39 t.text "body"
39 40 t.boolean "markdowned"
40 41 t.datetime "created_at"
41 42 t.datetime "updated_at"
42 43 end
43 44
44 45 create_table "grader_processes", :force => true do |t|
45 46 t.string "host", :limit => 20
46 47 t.integer "pid"
47 48 t.string "mode"
48 49 t.boolean "active"
49 50 t.datetime "created_at"
50 51 t.datetime "updated_at"
51 52 t.integer "task_id"
52 53 t.string "task_type"
53 54 end
54 55
55 56 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
56 57
57 58 create_table "languages", :force => true do |t|
58 59 t.string "name", :limit => 10
59 60 t.string "pretty_name"
60 61 t.string "ext", :limit => 10
61 62 end
62 63
63 64 create_table "messages", :force => true do |t|
64 65 t.integer "sender_id"
65 66 t.integer "receiver_id"
66 67 t.integer "replying_message_id"
67 68 t.text "body"
68 69 t.boolean "replied"
@@ -129,64 +130,64
129 130 t.integer "user_id"
130 131 t.integer "problem_id"
131 132 t.integer "language_id"
132 133 t.text "source"
133 134 t.binary "binary"
134 135 t.datetime "submitted_at"
135 136 t.datetime "compiled_at"
136 137 t.text "compiler_message"
137 138 t.datetime "graded_at"
138 139 t.integer "points"
139 140 t.text "grader_comment"
140 141 t.integer "number"
141 142 t.string "source_filename"
142 143 end
143 144
144 145 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
145 146 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
146 147
147 148 create_table "tasks", :force => true do |t|
148 149 t.integer "submission_id"
149 150 t.datetime "created_at"
150 151 t.integer "status"
151 152 t.datetime "updated_at"
152 153 end
153 154
154 155 create_table "test_requests", :force => true do |t|
155 156 t.integer "user_id"
156 157 t.integer "problem_id"
157 158 t.integer "submission_id"
158 159 t.string "input_file_name"
159 160 t.string "output_file_name"
160 161 t.string "running_stat"
161 162 t.integer "status"
162 163 t.datetime "updated_at"
163 164 t.datetime "submitted_at"
164 165 t.datetime "compiled_at"
165 166 t.text "compiler_message"
166 167 t.datetime "graded_at"
167 168 t.string "grader_comment"
168 169 t.datetime "created_at"
169 170 t.float "running_time"
170 171 t.string "exit_status"
171 172 t.integer "memory_usage"
172 173 end
173 174
174 175 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
175 176
176 177 create_table "users", :force => true do |t|
177 - t.string "login", :limit => 10
178 + t.string "login", :limit => 50
178 179 t.string "full_name"
179 180 t.string "hashed_password"
180 181 t.string "salt", :limit => 5
181 182 t.string "alias"
182 183 t.string "email"
183 184 t.integer "site_id"
184 185 t.integer "country_id"
185 186 t.boolean "activated", :default => false
186 187 t.datetime "created_at"
187 188 t.datetime "updated_at"
188 189 end
189 190
190 191 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
191 192
192 193 end
@@ -1,51 +1,52
1 1 /* Normal text */
2 - p {
3 - font-size: 12px;
2 + body {
3 + font-size: 13px;
4 + font-family: "Sans Serif";
4 5 }
5 6
6 7 /* This is the main menu bad*/
7 8 div.userbar {
8 9 border-top: thin solid grey;
9 10 border-bottom: thin solid grey;
10 11 text-align: right;
11 12 font-size: 12px;
12 13 }
13 14
14 15 /* This is the top bar, displaying user's full name */
15 16 div.title {
16 17 font-size: 12px;
17 18 background: #ddffdd;
18 19 border: 1px solid black;
19 20 padding: 2px;
20 21 margin-top: 3px;
21 22 margin-bottom: 5px;
22 23 }
23 24
24 25 div.title span.contest-over-msg {
25 26 font-size: 15px;
26 27 color: red;
27 28 font-weight: bold;
28 29 }
29 30
30 31 div.title table {
31 32 width: 100%;
32 33 }
33 34
34 35 div.title td.left-col {
35 36 text-align: left;
36 37 vertical-align: top;
37 38 }
38 39
39 40 div.title td.right-col {
40 41 text-align: right;
41 42 vertical-align: top;
42 43 }
43 44
44 45 /* Standard table with header and rows with alternating background */
45 46 table.info {
46 47 border: 1px solid black;
47 48 border-collapse: collapse;
48 49 font-size: 12px;
49 50 }
50 51
51 52 table.info th {
@@ -182,48 +183,78
182 183 padding-left: 10px;
183 184 }
184 185
185 186 div.announcement {
186 187 margin: 2px;
187 188 background: white;
188 189 padding: 1px;
189 190 padding-left: 10px;
190 191 padding-right: 10px;
191 192 }
192 193
193 194 div.announcement p {
194 195 font-size: 12px;
195 196 }
196 197
197 198 div.pub-info, div.pub-info p {
198 199 text-align: right;
199 200 font-style: italic;
200 201 font-size: 9px;
201 202 }
202 203
203 204 /******************
204 205 [Messages
205 206 ******************/
206 207
207 208 div.message {
208 209 padding-top: 5px;
209 210 padding-left: 10px;
210 211 }
211 212
212 213 div.message div.body {
213 214 border: 1px solid green;
214 215 background: #eeffee;
215 216 padding-left: 5px;
216 217 }
217 218
218 219 div.message div.reply-body {
219 220 border: 1px solid black;
220 221 background: #ffeeee;
221 222 padding-left: 5px;
222 223 }
223 224
224 225 div.message div.stat {
225 226 font-size: 10px;
226 227 color: white;
227 228 background: green;
228 229 font-weight: bold;
229 230 }
231 +
232 + /********************
233 + Registration
234 + ********************/
235 + div.contest-title {
236 + color: white;
237 + background: #007700;
238 + text-align: center;
239 + padding: 5px;
240 + }
241 +
242 + div.registration-desc {
243 + margin-top: 5px;
244 + margin-bottom: 5px;
245 + border: solid 1px gray;
246 + padding: 10px;
247 + background: #f0f0f0;
248 + }
249 +
250 + /********************
251 + [Test Interface]
252 + ********************/
253 +
254 + div.test-desc {
255 + border: solid 1px gray;
256 + background: #f0f0f0;
257 + padding: 5px;
258 + font-size: 12px;
259 + margin-bottom: 5px;
260 + }
deleted file
deleted file
deleted file
You need to be logged in to leave comments. Login now