Description:
[web] added message feature git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@194 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

r102:8fbc279e8875 - - 16 files changed: 279 inserted, 1 deleted

@@ -0,0 +1,73
1 + class MessagesController < ApplicationController
2 +
3 + before_filter :authenticate
4 +
5 + verify :method => :post, :only => ['create'],
6 + :redirect_to => { :action => 'list' }
7 +
8 + before_filter :only => ['console','show'] do |controller|
9 + controller.authorization_by_roles(['admin'])
10 + end
11 +
12 + def list
13 + @user = User.find(session[:user_id])
14 + @messages = Message.find_all_sent_by_user(@user)
15 + end
16 +
17 + def console
18 + @user = User.find(session[:user_id])
19 + @messages = Message.find_all_system_unreplied_messages
20 + end
21 +
22 + def show
23 + @message = Message.find(params[:id])
24 + end
25 +
26 + def create
27 + user = User.find(session[:user_id])
28 + @message = Message.new(params[:message])
29 + @message.sender = user
30 + if !@message.save
31 + render :action => 'list' and return
32 + else
33 + flash[:notice] = 'New message posted'
34 + redirect_to :action => 'list'
35 + end
36 + end
37 +
38 + def reply
39 + user = User.find(session[:user_id])
40 + @message = Message.new(params[:r_message])
41 + @message.sender = user
42 + if !@message.save
43 + render :action => 'show' and return
44 + else
45 + flash[:notice] = 'Message replied'
46 + rep_msg = @message.replying_message
47 + rep_msg.replied = true
48 + rep_msg.save
49 + redirect_to :action => 'console'
50 + end
51 + end
52 +
53 + protected
54 + def build_replying_message_hierarchy(user)
55 + @all_messages = {}
56 +
57 +
58 + # manually build replies hierarchy (to improve efficiency)
59 + [@messages, @replied_messages].each do |collection|
60 + collection.each do |m|
61 + @all_messages[m.id] = {:msg => m, :replies => []}
62 + end
63 + end
64 +
65 + @all_messages.each do |m|
66 + rep_id = m.replying_message_id
67 + if @all_messages[rep_id]!=nil
68 + @all_messages[rep_id][:replies] << m
69 + end
70 + end
71 + end
72 +
73 + end
@@ -0,0 +1,2
1 + module MessagesHelper
2 + end
@@ -0,0 +1,60
1 + class Message < ActiveRecord::Base
2 +
3 + belongs_to :sender, :class_name => "User"
4 + belongs_to :receiver, :class_name => "User"
5 +
6 + belongs_to :replying_message, :class_name => "Message"
7 +
8 + # commented manually do it
9 + #
10 + #has_many :replied_messages, {
11 + # :class_name => "Message",
12 + # :foreign_key => "replying_message_id"
13 + #}
14 + #
15 +
16 + attr_accessor :replied_messages
17 +
18 + def self.find_all_sent_by_user(user)
19 + messages = user.messages
20 + replied_messages = user.replied_messages
21 + Message.build_replying_message_hierarchy messages, replied_messages
22 + return messages
23 + end
24 +
25 + def self.find_all_system_unreplied_messages
26 + self.find(:all,
27 + :conditions => 'ISNULL(receiver_id) ' +
28 + 'AND (ISNULL(replied) OR replied=0)',
29 + :order => 'created_at')
30 + end
31 +
32 + def self.build_replying_message_hierarchy(*args)
33 + # manually build replies hierarchy (to improve efficiency)
34 + all_messages = {}
35 +
36 + args.each do |collection|
37 + collection.each do |m|
38 + all_messages[m.id] = m
39 + m.replied_messages = []
40 + end
41 + end
42 +
43 + all_messages.each_value do |m|
44 + rep_id = m.replying_message_id
45 + if all_messages[rep_id]!=nil
46 + all_messages[rep_id].add_replied_message(m)
47 + end
48 + end
49 + end
50 +
51 + def add_replied_message(m)
52 + if @replied_messages==nil
53 + @replied_messages = [m]
54 + else
55 + @replied_messages << m
56 + end
57 + @replied_messages
58 + end
59 +
60 + end
@@ -0,0 +1,7
1 + .message
2 + .stat
3 + = "#{message.sender.full_name} at #{message.created_at}"
4 + %div{:class => (!defined?(reply) or (reply==false)) ? "body" : "reply-body"}
5 + = simple_format(message.body)
6 + - if message.replied_messages.length!=0
7 + = render :partial => 'message', :collection => message.replied_messages, :locals => {:reply => true}
@@ -0,0 +1,6
1 + %tr
2 + %td=h short_message.sender.full_name
3 + %td= "#{short_message.created_at}"
4 + %td=h truncate(short_message.body)
5 + %td
6 + = link_to "[reply]", :action => 'show', :id => short_message.id
@@ -0,0 +1,13
1 + = user_title_bar(@user)
2 +
3 + %h1 Console: active messages
4 +
5 + = link_to '[all messages]', :action => 'list_all'
6 +
7 + %table
8 + %tr
9 + %th From
10 + %th When
11 + %th Message
12 + %th
13 + = render :partial => "short_message", :collection => @messages
@@ -0,0 +1,14
1 + = user_title_bar(@user)
2 +
3 + %h3 Your Messages
4 +
5 + - form_for 'message', nil, :url => { :action => 'create'} do |f|
6 + %p
7 + %b New message
8 + = submit_tag "Post"
9 + %br/
10 + = f.text_area :body, :rows => 5, :cols => 100
11 +
12 + %hr/
13 +
14 + = render :partial => 'message', :collection => @messages, :locals => {:reply => false}
@@ -0,0 +1,13
1 + %h3 Message
2 +
3 + .message
4 + .stat
5 + = "#{@message.sender.full_name} at #{@message.created_at}"
6 + .body= simple_format(@message.body)
7 +
8 + %h3 Your reply:
9 + - form_for 'r_message', nil, :url => { :action => 'reply'} do |f|
10 + = f.text_area :body, :rows => 5, :cols => 100
11 + = f.hidden_field :receiver_id, {:value => @message.sender_id }
12 + = f.hidden_field :replying_message_id, {:value => @message.id }
13 + = submit_tag "Post"
@@ -0,0 +1,17
1 + class CreateMessages < ActiveRecord::Migration
2 + def self.up
3 + create_table :messages do |t|
4 + t.column "sender_id", :integer
5 + t.column "receiver_id", :integer
6 + t.column "replying_message_id", :integer
7 + t.column "body", :text
8 + t.column "replied", :boolean # this is for efficiency
9 +
10 + t.timestamps
11 + end
12 + end
13 +
14 + def self.down
15 + drop_table :messages
16 + end
17 + end
@@ -0,0 +1,7
1 + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 +
3 + # one:
4 + # column: value
5 + #
6 + # two:
7 + # column: value
@@ -0,0 +1,8
1 + require File.dirname(__FILE__) + '/../test_helper'
2 +
3 + class MessagesControllerTest < ActionController::TestCase
4 + # Replace this with your real tests.
5 + def test_truth
6 + assert true
7 + end
8 + end
@@ -0,0 +1,8
1 + require File.dirname(__FILE__) + '/../test_helper'
2 +
3 + class MessageTest < ActiveSupport::TestCase
4 + # Replace this with your real tests.
5 + def test_truth
6 + assert true
7 + end
8 + end
@@ -1,73 +1,75
1 # Methods added to this helper will be available to all templates in the application.
1 # Methods added to this helper will be available to all templates in the application.
2 module ApplicationHelper
2 module ApplicationHelper
3
3
4 def user_header
4 def user_header
5 menu_items = ''
5 menu_items = ''
6 user = User.find(session[:user_id])
6 user = User.find(session[:user_id])
7
7
8 if (user!=nil) and (user.admin?)
8 if (user!=nil) and (user.admin?)
9 # admin menu
9 # admin menu
10 menu_items << "<b>Administrative task:</b> "
10 menu_items << "<b>Administrative task:</b> "
11 append_to menu_items, '[Announcements]', 'announcements', 'index'
11 append_to menu_items, '[Announcements]', 'announcements', 'index'
12 + append_to menu_items, '[Msg console]', 'messages', 'console'
12 append_to menu_items, '[Problem admin]', 'problems', 'index'
13 append_to menu_items, '[Problem admin]', 'problems', 'index'
13 append_to menu_items, '[User admin]', 'user_admin', 'index'
14 append_to menu_items, '[User admin]', 'user_admin', 'index'
14 append_to menu_items, '[User stat]', 'user_admin', 'user_stat'
15 append_to menu_items, '[User stat]', 'user_admin', 'user_stat'
15 #append_to menu_items, '[Graders]', 'graders', 'list'
16 #append_to menu_items, '[Graders]', 'graders', 'list'
16 append_to menu_items, '[Site config]', 'configurations', 'index'
17 append_to menu_items, '[Site config]', 'configurations', 'index'
17 menu_items << "<br/>"
18 menu_items << "<br/>"
18 end
19 end
19
20
20 # main page
21 # main page
21 append_to menu_items, '[Main]', 'main', 'list'
22 append_to menu_items, '[Main]', 'main', 'list'
23 + append_to menu_items, '[Messages]', 'messages', 'list'
22 append_to menu_items, '[Tasks]', 'tasks', 'list'
24 append_to menu_items, '[Tasks]', 'tasks', 'list'
23 append_to menu_items, '[Submissions]', 'main', 'submission'
25 append_to menu_items, '[Submissions]', 'main', 'submission'
24 append_to menu_items, '[Test]', 'test', 'index'
26 append_to menu_items, '[Test]', 'test', 'index'
25 append_to menu_items, '[Settings]', 'users', 'index'
27 append_to menu_items, '[Settings]', 'users', 'index'
26 append_to menu_items, '[Log out]', 'main', 'login'
28 append_to menu_items, '[Log out]', 'main', 'login'
27
29
28 menu_items
30 menu_items
29 end
31 end
30
32
31 def append_to(option,label, controller, action)
33 def append_to(option,label, controller, action)
32 option << ' ' if option!=''
34 option << ' ' if option!=''
33 option << link_to_unless_current(label,
35 option << link_to_unless_current(label,
34 :controller => controller,
36 :controller => controller,
35 :action => action)
37 :action => action)
36 end
38 end
37
39
38 def format_short_time(time)
40 def format_short_time(time)
39 now = Time.now
41 now = Time.now
40 st = ''
42 st = ''
41 if (time.yday != now.yday) or
43 if (time.yday != now.yday) or
42 (time.year != now.year)
44 (time.year != now.year)
43 st = time.strftime("%x ")
45 st = time.strftime("%x ")
44 end
46 end
45 st + time.strftime("%X")
47 st + time.strftime("%X")
46 end
48 end
47
49
48
50
49 def user_title_bar(user)
51 def user_title_bar(user)
50 if user.site!=nil and user.site.finished?
52 if user.site!=nil and user.site.finished?
51 contest_over_string = <<CONTEST_OVER
53 contest_over_string = <<CONTEST_OVER
52 <tr><td colspan="2" align="center">
54 <tr><td colspan="2" align="center">
53 <span class="contest-over-msg">THE CONTEST IS OVER</span>
55 <span class="contest-over-msg">THE CONTEST IS OVER</span>
54 </td></tr>
56 </td></tr>
55 CONTEST_OVER
57 CONTEST_OVER
56 end
58 end
57 <<TITLEBAR
59 <<TITLEBAR
58 <div class="title">
60 <div class="title">
59 <table>
61 <table>
60 #{contest_over_string}
62 #{contest_over_string}
61 <tr>
63 <tr>
62 <td class="left-col">
64 <td class="left-col">
63 #{user.full_name}<br/>
65 #{user.full_name}<br/>
64 Current time is #{format_short_time(Time.new)}<br/>
66 Current time is #{format_short_time(Time.new)}<br/>
65 </td>
67 </td>
66 <td class="right-col">APIO'08</td>
68 <td class="right-col">APIO'08</td>
67 </tr>
69 </tr>
68 </table>
70 </table>
69 </div>
71 </div>
70 TITLEBAR
72 TITLEBAR
71 end
73 end
72
74
73 end
75 end
@@ -1,78 +1,88
1 require 'digest/sha1'
1 require 'digest/sha1'
2
2
3 class User < ActiveRecord::Base
3 class User < ActiveRecord::Base
4
4
5 has_and_belongs_to_many :roles
5 has_and_belongs_to_many :roles
6
6
7 has_many :test_requests, :order => "submitted_at DESC"
7 has_many :test_requests, :order => "submitted_at DESC"
8
8
9 + has_many :messages,
10 + :class_name => "Message",
11 + :foreign_key => "sender_id",
12 + :order => 'created_at DESC'
13 +
14 + has_many :replied_messages,
15 + :class_name => "Message",
16 + :foreign_key => "receiver_id",
17 + :order => 'created_at DESC'
18 +
9 belongs_to :site
19 belongs_to :site
10
20
11 validates_presence_of :login
21 validates_presence_of :login
12 validates_presence_of :full_name
22 validates_presence_of :full_name
13 validates_length_of :full_name, :minimum => 1
23 validates_length_of :full_name, :minimum => 1
14
24
15 validates_presence_of :password, :if => :password_required?
25 validates_presence_of :password, :if => :password_required?
16 validates_length_of :password, :within => 4..20, :if => :password_required?
26 validates_length_of :password, :within => 4..20, :if => :password_required?
17 validates_confirmation_of :password, :if => :password_required?
27 validates_confirmation_of :password, :if => :password_required?
18
28
19 attr_accessor :password
29 attr_accessor :password
20
30
21 before_save :encrypt_new_password
31 before_save :encrypt_new_password
22
32
23 def self.authenticate(login, password)
33 def self.authenticate(login, password)
24 user = find_by_login(login)
34 user = find_by_login(login)
25 return user if user && user.authenticated?(password)
35 return user if user && user.authenticated?(password)
26 end
36 end
27
37
28 def authenticated?(password)
38 def authenticated?(password)
29 hashed_password == User.encrypt(password,self.salt)
39 hashed_password == User.encrypt(password,self.salt)
30 end
40 end
31
41
32 def admin?
42 def admin?
33 self.roles.detect {|r| r.name == 'admin' }
43 self.roles.detect {|r| r.name == 'admin' }
34 end
44 end
35
45
36 def email_for_editing
46 def email_for_editing
37 if self.email==nil
47 if self.email==nil
38 "(unknown)"
48 "(unknown)"
39 elsif self.email==''
49 elsif self.email==''
40 "(blank)"
50 "(blank)"
41 else
51 else
42 self.email
52 self.email
43 end
53 end
44 end
54 end
45
55
46 def email_for_editing=(e)
56 def email_for_editing=(e)
47 self.email=e
57 self.email=e
48 end
58 end
49
59
50 def alias_for_editing
60 def alias_for_editing
51 if self.alias==nil
61 if self.alias==nil
52 "(unknown)"
62 "(unknown)"
53 elsif self.alias==''
63 elsif self.alias==''
54 "(blank)"
64 "(blank)"
55 else
65 else
56 self.alias
66 self.alias
57 end
67 end
58 end
68 end
59
69
60 def alias_for_editing=(e)
70 def alias_for_editing=(e)
61 self.alias=e
71 self.alias=e
62 end
72 end
63
73
64 protected
74 protected
65 def encrypt_new_password
75 def encrypt_new_password
66 return if password.blank?
76 return if password.blank?
67 self.salt = (10+rand(90)).to_s
77 self.salt = (10+rand(90)).to_s
68 self.hashed_password = User.encrypt(self.password,self.salt)
78 self.hashed_password = User.encrypt(self.password,self.salt)
69 end
79 end
70
80
71 def password_required?
81 def password_required?
72 self.hashed_password.blank? || !self.password.blank?
82 self.hashed_password.blank? || !self.password.blank?
73 end
83 end
74
84
75 def self.encrypt(string,salt)
85 def self.encrypt(string,salt)
76 Digest::SHA1.hexdigest(salt + string)
86 Digest::SHA1.hexdigest(salt + string)
77 end
87 end
78 end
88 end
@@ -1,150 +1,160
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 # please use the migrations feature of ActiveRecord to incrementally modify your database, and
2 # please use the migrations feature of ActiveRecord to incrementally modify your database, and
3 # then regenerate this schema definition.
3 # then regenerate this schema definition.
4 #
4 #
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 # to create the application database on another system, you should be using db:schema:load, not running
6 # to create the application database on another system, you should be using db:schema:load, not running
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 #
9 #
10 # It's strongly recommended to check this file into your version control system.
10 # It's strongly recommended to check this file into your version control system.
11
11
12 - ActiveRecord::Schema.define(:version => 31) do
12 + ActiveRecord::Schema.define(:version => 32) do
13
13
14 create_table "announcements", :force => true do |t|
14 create_table "announcements", :force => true do |t|
15 t.string "author"
15 t.string "author"
16 t.text "body"
16 t.text "body"
17 t.boolean "published"
17 t.boolean "published"
18 t.datetime "created_at"
18 t.datetime "created_at"
19 t.datetime "updated_at"
19 t.datetime "updated_at"
20 end
20 end
21
21
22 create_table "configurations", :force => true do |t|
22 create_table "configurations", :force => true do |t|
23 t.string "key"
23 t.string "key"
24 t.string "value_type"
24 t.string "value_type"
25 t.string "value"
25 t.string "value"
26 t.datetime "created_at"
26 t.datetime "created_at"
27 t.datetime "updated_at"
27 t.datetime "updated_at"
28 end
28 end
29
29
30 create_table "descriptions", :force => true do |t|
30 create_table "descriptions", :force => true do |t|
31 t.text "body"
31 t.text "body"
32 t.boolean "markdowned"
32 t.boolean "markdowned"
33 t.datetime "created_at"
33 t.datetime "created_at"
34 t.datetime "updated_at"
34 t.datetime "updated_at"
35 end
35 end
36
36
37 create_table "grader_processes", :force => true do |t|
37 create_table "grader_processes", :force => true do |t|
38 t.string "host", :limit => 20
38 t.string "host", :limit => 20
39 t.integer "pid"
39 t.integer "pid"
40 t.string "mode"
40 t.string "mode"
41 t.boolean "active"
41 t.boolean "active"
42 t.datetime "created_at"
42 t.datetime "created_at"
43 t.datetime "updated_at"
43 t.datetime "updated_at"
44 t.integer "task_id"
44 t.integer "task_id"
45 end
45 end
46
46
47 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
47 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
48
48
49 create_table "languages", :force => true do |t|
49 create_table "languages", :force => true do |t|
50 t.string "name", :limit => 10
50 t.string "name", :limit => 10
51 t.string "pretty_name"
51 t.string "pretty_name"
52 t.string "ext", :limit => 10
52 t.string "ext", :limit => 10
53 end
53 end
54
54
55 + create_table "messages", :force => true do |t|
56 + t.integer "sender_id"
57 + t.integer "receiver_id"
58 + t.integer "replying_message_id"
59 + t.text "body"
60 + t.boolean "replied"
61 + t.datetime "created_at"
62 + t.datetime "updated_at"
63 + end
64 +
55 create_table "problems", :force => true do |t|
65 create_table "problems", :force => true do |t|
56 t.string "name", :limit => 30
66 t.string "name", :limit => 30
57 t.string "full_name"
67 t.string "full_name"
58 t.integer "full_score"
68 t.integer "full_score"
59 t.date "date_added"
69 t.date "date_added"
60 t.boolean "available"
70 t.boolean "available"
61 t.string "url"
71 t.string "url"
62 t.integer "description_id"
72 t.integer "description_id"
63 t.boolean "test_allowed"
73 t.boolean "test_allowed"
64 t.boolean "output_only"
74 t.boolean "output_only"
65 end
75 end
66
76
67 create_table "rights", :force => true do |t|
77 create_table "rights", :force => true do |t|
68 t.string "name"
78 t.string "name"
69 t.string "controller"
79 t.string "controller"
70 t.string "action"
80 t.string "action"
71 end
81 end
72
82
73 create_table "rights_roles", :id => false, :force => true do |t|
83 create_table "rights_roles", :id => false, :force => true do |t|
74 t.integer "right_id"
84 t.integer "right_id"
75 t.integer "role_id"
85 t.integer "role_id"
76 end
86 end
77
87
78 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
88 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
79
89
80 create_table "roles", :force => true do |t|
90 create_table "roles", :force => true do |t|
81 t.string "name"
91 t.string "name"
82 end
92 end
83
93
84 create_table "roles_users", :id => false, :force => true do |t|
94 create_table "roles_users", :id => false, :force => true do |t|
85 t.integer "role_id"
95 t.integer "role_id"
86 t.integer "user_id"
96 t.integer "user_id"
87 end
97 end
88
98
89 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
99 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
90
100
91 create_table "sessions", :force => true do |t|
101 create_table "sessions", :force => true do |t|
92 t.string "session_id"
102 t.string "session_id"
93 t.text "data"
103 t.text "data"
94 t.datetime "updated_at"
104 t.datetime "updated_at"
95 end
105 end
96
106
97 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
107 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
98 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
108 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
99
109
100 create_table "sites", :force => true do |t|
110 create_table "sites", :force => true do |t|
101 t.string "name"
111 t.string "name"
102 t.boolean "started"
112 t.boolean "started"
103 t.datetime "start_time"
113 t.datetime "start_time"
104 t.datetime "created_at"
114 t.datetime "created_at"
105 t.datetime "updated_at"
115 t.datetime "updated_at"
106 end
116 end
107
117
108 create_table "submissions", :force => true do |t|
118 create_table "submissions", :force => true do |t|
109 t.integer "user_id"
119 t.integer "user_id"
110 t.integer "problem_id"
120 t.integer "problem_id"
111 t.integer "language_id"
121 t.integer "language_id"
112 t.text "source"
122 t.text "source"
113 t.binary "binary"
123 t.binary "binary"
114 t.datetime "submitted_at"
124 t.datetime "submitted_at"
115 t.datetime "compiled_at"
125 t.datetime "compiled_at"
116 t.text "compiler_message"
126 t.text "compiler_message"
117 t.datetime "graded_at"
127 t.datetime "graded_at"
118 t.integer "points"
128 t.integer "points"
119 t.text "grader_comment"
129 t.text "grader_comment"
120 t.integer "number"
130 t.integer "number"
121 t.string "source_filename"
131 t.string "source_filename"
122 end
132 end
123
133
124 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
134 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
125 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
135 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
126
136
127 create_table "tasks", :force => true do |t|
137 create_table "tasks", :force => true do |t|
128 t.integer "submission_id"
138 t.integer "submission_id"
129 t.datetime "created_at"
139 t.datetime "created_at"
130 t.integer "status"
140 t.integer "status"
131 t.datetime "updated_at"
141 t.datetime "updated_at"
132 end
142 end
133
143
134 create_table "test_requests", :force => true do |t|
144 create_table "test_requests", :force => true do |t|
135 t.integer "user_id"
145 t.integer "user_id"
136 t.integer "problem_id"
146 t.integer "problem_id"
137 t.integer "submission_id"
147 t.integer "submission_id"
138 t.string "input_file_name"
148 t.string "input_file_name"
139 t.string "output_file_name"
149 t.string "output_file_name"
140 t.string "running_stat"
150 t.string "running_stat"
141 t.integer "status"
151 t.integer "status"
142 t.datetime "updated_at"
152 t.datetime "updated_at"
143 t.datetime "submitted_at"
153 t.datetime "submitted_at"
144 t.datetime "compiled_at"
154 t.datetime "compiled_at"
145 t.text "compiler_message"
155 t.text "compiler_message"
146 t.datetime "graded_at"
156 t.datetime "graded_at"
147 t.string "grader_comment"
157 t.string "grader_comment"
148 t.datetime "created_at"
158 t.datetime "created_at"
149 t.float "running_time"
159 t.float "running_time"
150 t.string "exit_status"
160 t.string "exit_status"
@@ -98,96 +98,124
98 }
98 }
99
99
100 th.uinfo {
100 th.uinfo {
101 background: lightgreen;
101 background: lightgreen;
102 vertical-align: top;
102 vertical-align: top;
103 text-align: right;
103 text-align: right;
104 border: 1px solid black;
104 border: 1px solid black;
105 padding: 5px;
105 padding: 5px;
106 }
106 }
107
107
108 /*******************************
108 /*******************************
109 [Submission]
109 [Submission]
110 ********************************/
110 ********************************/
111 div.compilermsgbody {
111 div.compilermsgbody {
112 font-family: monospace;
112 font-family: monospace;
113 }
113 }
114
114
115 div.task-menu {
115 div.task-menu {
116 text-align: center;
116 text-align: center;
117 font-size: 13px;
117 font-size: 13px;
118 font-weight: bold;
118 font-weight: bold;
119 border-top: 1px solid black;
119 border-top: 1px solid black;
120 border-bottom: 1px solid black;
120 border-bottom: 1px solid black;
121 margin-top: 2px;
121 margin-top: 2px;
122 margin-bottom: 4px;
122 margin-bottom: 4px;
123 }
123 }
124
124
125 /*******************************
125 /*******************************
126 [Submission]
126 [Submission]
127 ********************************/
127 ********************************/
128 table.taskdesc {
128 table.taskdesc {
129 border: 1px solid black;
129 border: 1px solid black;
130 border-collapse: collapse;
130 border-collapse: collapse;
131 width: 95%;
131 width: 95%;
132 font-size: 13px;
132 font-size: 13px;
133 }
133 }
134
134
135 table.taskdesc p {
135 table.taskdesc p {
136 font-size: 13px;
136 font-size: 13px;
137 }
137 }
138
138
139 table.taskdesc tr.name {
139 table.taskdesc tr.name {
140 border: 1px solid black;
140 border: 1px solid black;
141 background: #aaaaaa;
141 background: #aaaaaa;
142 color: white;
142 color: white;
143 font-weight: bold;
143 font-weight: bold;
144 font-size: 14px;
144 font-size: 14px;
145 text-align: center;
145 text-align: center;
146 }
146 }
147
147
148 table.taskdesc td.desc-odd {
148 table.taskdesc td.desc-odd {
149 padding: 5px;
149 padding: 5px;
150 padding-left: 20px;
150 padding-left: 20px;
151 background: #fefeee;
151 background: #fefeee;
152 }
152 }
153
153
154 table.taskdesc td.desc-even {
154 table.taskdesc td.desc-even {
155 padding: 5px;
155 padding: 5px;
156 padding-left: 20px;
156 padding-left: 20px;
157 background: #feeefe;
157 background: #feeefe;
158 }
158 }
159
159
160 /**********************
160 /**********************
161 [Announcement]
161 [Announcement]
162 ***********************/
162 ***********************/
163
163
164 div.announcementbox {
164 div.announcementbox {
165 margin-top: 10px;
165 margin-top: 10px;
166 margin-bottom: 10px;
166 margin-bottom: 10px;
167 background: green;
167 background: green;
168 padding: 1px;
168 padding: 1px;
169 }
169 }
170
170
171 div.announcementbox span.title {
171 div.announcementbox span.title {
172 font-weight: bold;
172 font-weight: bold;
173 color: white;
173 color: white;
174 padding-left: 10px;
174 padding-left: 10px;
175 }
175 }
176
176
177 div.announcement {
177 div.announcement {
178 margin: 2px;
178 margin: 2px;
179 background: white;
179 background: white;
180 padding: 1px;
180 padding: 1px;
181 padding-left: 10px;
181 padding-left: 10px;
182 padding-right: 10px;
182 padding-right: 10px;
183 }
183 }
184
184
185 div.announcement p {
185 div.announcement p {
186 font-size: 12px;
186 font-size: 12px;
187 }
187 }
188
188
189 div.pub-info, div.pub-info p {
189 div.pub-info, div.pub-info p {
190 text-align: right;
190 text-align: right;
191 font-style: italic;
191 font-style: italic;
192 font-size: 9px;
192 font-size: 9px;
193 }
193 }
194 +
195 + /******************
196 + [Messages
197 + ******************/
198 +
199 + div.message {
200 + padding-top: 5px;
201 + padding-left: 10px;
202 + }
203 +
204 + div.message div.body {
205 + border: 1px solid green;
206 + background: #eeffee;
207 + padding-left: 5px;
208 + }
209 +
210 + div.message div.reply-body {
211 + border: 1px solid black;
212 + background: #ffeeee;
213 + padding-left: 5px;
214 + }
215 +
216 + div.message div.stat {
217 + font-size: 10px;
218 + color: white;
219 + background: green;
220 + font-weight: bold;
221 + }
You need to be logged in to leave comments. Login now