diff --git a/app/controllers/messages_controller.rb b/app/controllers/messages_controller.rb new file mode 100644 --- /dev/null +++ b/app/controllers/messages_controller.rb @@ -0,0 +1,73 @@ +class MessagesController < ApplicationController + + before_filter :authenticate + + verify :method => :post, :only => ['create'], + :redirect_to => { :action => 'list' } + + before_filter :only => ['console','show'] do |controller| + controller.authorization_by_roles(['admin']) + end + + def list + @user = User.find(session[:user_id]) + @messages = Message.find_all_sent_by_user(@user) + end + + def console + @user = User.find(session[:user_id]) + @messages = Message.find_all_system_unreplied_messages + end + + def show + @message = Message.find(params[:id]) + end + + def create + user = User.find(session[:user_id]) + @message = Message.new(params[:message]) + @message.sender = user + if !@message.save + render :action => 'list' and return + else + flash[:notice] = 'New message posted' + redirect_to :action => 'list' + end + end + + def reply + user = User.find(session[:user_id]) + @message = Message.new(params[:r_message]) + @message.sender = user + if !@message.save + render :action => 'show' and return + else + flash[:notice] = 'Message replied' + rep_msg = @message.replying_message + rep_msg.replied = true + rep_msg.save + redirect_to :action => 'console' + end + end + + protected + def build_replying_message_hierarchy(user) + @all_messages = {} + + + # manually build replies hierarchy (to improve efficiency) + [@messages, @replied_messages].each do |collection| + collection.each do |m| + @all_messages[m.id] = {:msg => m, :replies => []} + end + end + + @all_messages.each do |m| + rep_id = m.replying_message_id + if @all_messages[rep_id]!=nil + @all_messages[rep_id][:replies] << m + end + end + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -9,6 +9,7 @@ # admin menu menu_items << "Administrative task: " append_to menu_items, '[Announcements]', 'announcements', 'index' + append_to menu_items, '[Msg console]', 'messages', 'console' append_to menu_items, '[Problem admin]', 'problems', 'index' append_to menu_items, '[User admin]', 'user_admin', 'index' append_to menu_items, '[User stat]', 'user_admin', 'user_stat' @@ -19,6 +20,7 @@ # main page append_to menu_items, '[Main]', 'main', 'list' + append_to menu_items, '[Messages]', 'messages', 'list' append_to menu_items, '[Tasks]', 'tasks', 'list' append_to menu_items, '[Submissions]', 'main', 'submission' append_to menu_items, '[Test]', 'test', 'index' diff --git a/app/helpers/messages_helper.rb b/app/helpers/messages_helper.rb new file mode 100644 --- /dev/null +++ b/app/helpers/messages_helper.rb @@ -0,0 +1,2 @@ +module MessagesHelper +end diff --git a/app/models/message.rb b/app/models/message.rb new file mode 100644 --- /dev/null +++ b/app/models/message.rb @@ -0,0 +1,60 @@ +class Message < ActiveRecord::Base + + belongs_to :sender, :class_name => "User" + belongs_to :receiver, :class_name => "User" + + belongs_to :replying_message, :class_name => "Message" + + # commented manually do it + # + #has_many :replied_messages, { + # :class_name => "Message", + # :foreign_key => "replying_message_id" + #} + # + + attr_accessor :replied_messages + + def self.find_all_sent_by_user(user) + messages = user.messages + replied_messages = user.replied_messages + Message.build_replying_message_hierarchy messages, replied_messages + return messages + end + + def self.find_all_system_unreplied_messages + self.find(:all, + :conditions => 'ISNULL(receiver_id) ' + + 'AND (ISNULL(replied) OR replied=0)', + :order => 'created_at') + end + + def self.build_replying_message_hierarchy(*args) + # manually build replies hierarchy (to improve efficiency) + all_messages = {} + + args.each do |collection| + collection.each do |m| + all_messages[m.id] = m + m.replied_messages = [] + end + end + + all_messages.each_value do |m| + rep_id = m.replying_message_id + if all_messages[rep_id]!=nil + all_messages[rep_id].add_replied_message(m) + end + end + end + + def add_replied_message(m) + if @replied_messages==nil + @replied_messages = [m] + else + @replied_messages << m + end + @replied_messages + end + +end diff --git a/app/models/user.rb b/app/models/user.rb --- a/app/models/user.rb +++ b/app/models/user.rb @@ -6,6 +6,16 @@ has_many :test_requests, :order => "submitted_at DESC" + has_many :messages, + :class_name => "Message", + :foreign_key => "sender_id", + :order => 'created_at DESC' + + has_many :replied_messages, + :class_name => "Message", + :foreign_key => "receiver_id", + :order => 'created_at DESC' + belongs_to :site validates_presence_of :login diff --git a/app/views/messages/_message.html.haml b/app/views/messages/_message.html.haml new file mode 100644 --- /dev/null +++ b/app/views/messages/_message.html.haml @@ -0,0 +1,7 @@ +.message + .stat + = "#{message.sender.full_name} at #{message.created_at}" + %div{:class => (!defined?(reply) or (reply==false)) ? "body" : "reply-body"} + = simple_format(message.body) + - if message.replied_messages.length!=0 + = render :partial => 'message', :collection => message.replied_messages, :locals => {:reply => true} diff --git a/app/views/messages/_short_message.html.haml b/app/views/messages/_short_message.html.haml new file mode 100644 --- /dev/null +++ b/app/views/messages/_short_message.html.haml @@ -0,0 +1,6 @@ +%tr + %td=h short_message.sender.full_name + %td= "#{short_message.created_at}" + %td=h truncate(short_message.body) + %td + = link_to "[reply]", :action => 'show', :id => short_message.id diff --git a/app/views/messages/console.html.haml b/app/views/messages/console.html.haml new file mode 100644 --- /dev/null +++ b/app/views/messages/console.html.haml @@ -0,0 +1,13 @@ += user_title_bar(@user) + +%h1 Console: active messages + += link_to '[all messages]', :action => 'list_all' + +%table + %tr + %th From + %th When + %th Message + %th + = render :partial => "short_message", :collection => @messages diff --git a/app/views/messages/list.html.haml b/app/views/messages/list.html.haml new file mode 100644 --- /dev/null +++ b/app/views/messages/list.html.haml @@ -0,0 +1,14 @@ += user_title_bar(@user) + +%h3 Your Messages + +- form_for 'message', nil, :url => { :action => 'create'} do |f| + %p + %b New message + = submit_tag "Post" + %br/ + = f.text_area :body, :rows => 5, :cols => 100 + +%hr/ + += render :partial => 'message', :collection => @messages, :locals => {:reply => false} diff --git a/app/views/messages/show.html.haml b/app/views/messages/show.html.haml new file mode 100644 --- /dev/null +++ b/app/views/messages/show.html.haml @@ -0,0 +1,13 @@ +%h3 Message + +.message + .stat + = "#{@message.sender.full_name} at #{@message.created_at}" + .body= simple_format(@message.body) + +%h3 Your reply: +- form_for 'r_message', nil, :url => { :action => 'reply'} do |f| + = f.text_area :body, :rows => 5, :cols => 100 + = f.hidden_field :receiver_id, {:value => @message.sender_id } + = f.hidden_field :replying_message_id, {:value => @message.id } + = submit_tag "Post" diff --git a/db/migrate/032_create_messages.rb b/db/migrate/032_create_messages.rb new file mode 100644 --- /dev/null +++ b/db/migrate/032_create_messages.rb @@ -0,0 +1,17 @@ +class CreateMessages < ActiveRecord::Migration + def self.up + create_table :messages do |t| + t.column "sender_id", :integer + t.column "receiver_id", :integer + t.column "replying_message_id", :integer + t.column "body", :text + t.column "replied", :boolean # this is for efficiency + + t.timestamps + end + end + + def self.down + drop_table :messages + end +end diff --git a/db/schema.rb b/db/schema.rb --- a/db/schema.rb +++ b/db/schema.rb @@ -9,7 +9,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 31) do +ActiveRecord::Schema.define(:version => 32) do create_table "announcements", :force => true do |t| t.string "author" @@ -52,6 +52,16 @@ t.string "ext", :limit => 10 end + create_table "messages", :force => true do |t| + t.integer "sender_id" + t.integer "receiver_id" + t.integer "replying_message_id" + t.text "body" + t.boolean "replied" + t.datetime "created_at" + t.datetime "updated_at" + end + create_table "problems", :force => true do |t| t.string "name", :limit => 30 t.string "full_name" diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -191,3 +191,31 @@ font-style: italic; font-size: 9px; } + +/****************** + [Messages +******************/ + +div.message { + padding-top: 5px; + padding-left: 10px; +} + +div.message div.body { + border: 1px solid green; + background: #eeffee; + padding-left: 5px; +} + +div.message div.reply-body { + border: 1px solid black; + background: #ffeeee; + padding-left: 5px; +} + +div.message div.stat { + font-size: 10px; + color: white; + background: green; + font-weight: bold; +} diff --git a/test/fixtures/messages.yml b/test/fixtures/messages.yml new file mode 100644 --- /dev/null +++ b/test/fixtures/messages.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html + +# one: +# column: value +# +# two: +# column: value diff --git a/test/functional/messages_controller_test.rb b/test/functional/messages_controller_test.rb new file mode 100644 --- /dev/null +++ b/test/functional/messages_controller_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class MessagesControllerTest < ActionController::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end diff --git a/test/unit/message_test.rb b/test/unit/message_test.rb new file mode 100644 --- /dev/null +++ b/test/unit/message_test.rb @@ -0,0 +1,8 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class MessageTest < ActiveSupport::TestCase + # Replace this with your real tests. + def test_truth + assert true + end +end