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:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
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,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 |
@@ -6,22 +6,24 | |||||
|
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 |
@@ -3,12 +3,22 | |||||
|
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 |
@@ -6,13 +6,13 | |||||
|
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 => 3 |
|
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" |
@@ -49,12 +49,22 | |||||
|
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" |
@@ -188,6 +188,34 | |||||
|
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