Add message threads #394
This new view sorts the messages by threads based on the reply_to. Now we store only the message which started a new thread in the reply_to field to avoid recursive queries.
This commit is contained in:
parent
d56828fa4d
commit
8ac1471a89
12 changed files with 180 additions and 0 deletions
|
@ -484,3 +484,35 @@ i.package.icon-only {
|
||||||
padding-right: 6px;
|
padding-right: 6px;
|
||||||
padding-left: 7px;
|
padding-left: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove the .panel defines after updating Bootstrap to >=3.0
|
||||||
|
.panel {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
background-color: #fff;
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: 4px;
|
||||||
|
-webkit-box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
|
||||||
|
box-shadow: 0 1px 1px rgba(0, 0, 0, .05);
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-default {
|
||||||
|
border-color: #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-heading {
|
||||||
|
padding: 10px 15px;
|
||||||
|
border-bottom: 1px solid transparent;
|
||||||
|
border-top-left-radius: 3px;
|
||||||
|
border-top-right-radius: 3px
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-default > .panel-heading {
|
||||||
|
color: #333;
|
||||||
|
background-color: #f5f5f5;
|
||||||
|
border-color: #ddd
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-body {
|
||||||
|
padding: 15px;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
class MessageThreadsController < ApplicationController
|
||||||
|
|
||||||
|
before_filter -> { require_plugin_enabled FoodsoftMessages }
|
||||||
|
|
||||||
|
def index
|
||||||
|
@message_threads = Message.pub.threads.page(params[:page]).per(@per_page).order(created_at: :desc).includes(:sender)
|
||||||
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
@messages = Message.thread(params[:id]).order(:created_at)
|
||||||
|
end
|
||||||
|
end
|
|
@ -13,6 +13,9 @@ class MessagesController < ApplicationController
|
||||||
|
|
||||||
if @message.reply_to
|
if @message.reply_to
|
||||||
original_message = Message.find(@message.reply_to)
|
original_message = Message.find(@message.reply_to)
|
||||||
|
if original_message.reply_to
|
||||||
|
@message.reply_to = original_message.reply_to
|
||||||
|
end
|
||||||
if original_message.is_readable_for?(current_user)
|
if original_message.is_readable_for?(current_user)
|
||||||
@message.add_recipients [original_message.sender]
|
@message.add_recipients [original_message.sender]
|
||||||
@message.group_id = original_message.group_id
|
@message.group_id = original_message.group_id
|
||||||
|
|
|
@ -9,6 +9,8 @@ class Message < ActiveRecord::Base
|
||||||
scope :pending, -> { where(:email_state => 0) }
|
scope :pending, -> { where(:email_state => 0) }
|
||||||
scope :sent, -> { where(:email_state => 1) }
|
scope :sent, -> { where(:email_state => 1) }
|
||||||
scope :pub, -> { where(:private => false) }
|
scope :pub, -> { where(:private => false) }
|
||||||
|
scope :threads, -> { where(:reply_to => nil) }
|
||||||
|
scope :thread, -> (id) { where("id = ? OR reply_to = ?", id, id) }
|
||||||
|
|
||||||
# Values for the email_state attribute: :none, :pending, :sent, :failed
|
# Values for the email_state attribute: :none, :pending, :sent, :failed
|
||||||
EMAIL_STATE = {
|
EMAIL_STATE = {
|
||||||
|
@ -71,6 +73,10 @@ class Message < ActiveRecord::Base
|
||||||
User.where(id: recipients_ids)
|
User.where(id: recipients_ids)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def last_reply
|
||||||
|
Message.where(reply_to: self.id).order(:created_at).last
|
||||||
|
end
|
||||||
|
|
||||||
def deliver
|
def deliver
|
||||||
for user in recipients
|
for user in recipients
|
||||||
if user.receive_email?
|
if user.receive_email?
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
- if pagination
|
||||||
|
- if Message.pub.count > 20
|
||||||
|
= items_per_page
|
||||||
|
= pagination_links_remote message_threads
|
||||||
|
|
||||||
|
- unless message_threads.empty?
|
||||||
|
%table.table.table-striped
|
||||||
|
%tbody
|
||||||
|
- for message in message_threads
|
||||||
|
%tr
|
||||||
|
%td
|
||||||
|
%b= link_to message.subject, message_thread_path(message)
|
||||||
|
%td= h(message.sender_name)
|
||||||
|
- if message.last_reply
|
||||||
|
%td= format_time(message.last_reply.created_at)
|
||||||
|
%td= h(message.last_reply.sender_name)
|
||||||
|
- else
|
||||||
|
%td{:colspan => "2"}
|
||||||
|
// %td= link_to t('.reply'), new_message_path(:message => {:reply_to => message.id}), class: 'btn'
|
|
@ -0,0 +1,7 @@
|
||||||
|
- title t('.title')
|
||||||
|
|
||||||
|
- content_for :actionbar do
|
||||||
|
= link_to t('.messages'), messages_path, class: 'btn'
|
||||||
|
= link_to t('.new'), new_message_path, class: 'btn btn-primary'
|
||||||
|
#message_threads
|
||||||
|
= render 'message_threads', message_threads: @message_threads, pagination: true
|
1
plugins/messages/app/views/message_threads/index.js.haml
Normal file
1
plugins/messages/app/views/message_threads/index.js.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
$('#message_threads').html('#{j(render('message_threads', message_threads: @message_threads, pagination: true))}');
|
16
plugins/messages/app/views/message_threads/show.haml
Normal file
16
plugins/messages/app/views/message_threads/show.haml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
- if @messages.first.group
|
||||||
|
- title @messages.first.subject + ' (' + @messages.first.group.name + ')'
|
||||||
|
- else
|
||||||
|
- title @messages.first.subject
|
||||||
|
|
||||||
|
- for message in @messages
|
||||||
|
.panel.panel-default{:style => "width:40em"}
|
||||||
|
.panel-heading
|
||||||
|
%b= h(message.sender_name)
|
||||||
|
= format_time(message.created_at)
|
||||||
|
.panel-body= simple_format(h(message.body))
|
||||||
|
|
||||||
|
%p
|
||||||
|
= link_to t('.reply'), new_message_path(:message => {:reply_to => @messages.first.id}), class: 'btn'
|
||||||
|
|
|
||||||
|
= link_to t('.all_message_threads'), message_threads_path
|
|
@ -1,6 +1,7 @@
|
||||||
- title t('.title')
|
- title t('.title')
|
||||||
|
|
||||||
- content_for :actionbar do
|
- content_for :actionbar do
|
||||||
|
= link_to t('.message_threads'), message_threads_path, class: 'btn'
|
||||||
= link_to t('.new'), new_message_path, class: 'btn btn-primary'
|
= link_to t('.new'), new_message_path, class: 'btn btn-primary'
|
||||||
#messages
|
#messages
|
||||||
= render 'messages', messages: @messages, pagination: true
|
= render 'messages', messages: @messages, pagination: true
|
||||||
|
|
59
plugins/messages/config/locales/de.yml
Normal file
59
plugins/messages/config/locales/de.yml
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
de:
|
||||||
|
activerecord:
|
||||||
|
attributes:
|
||||||
|
messagegroup:
|
||||||
|
description: Beschreibung
|
||||||
|
name: Name
|
||||||
|
user_tokens: Mitglieder
|
||||||
|
models:
|
||||||
|
messagegroup: Nachrichtengruppe
|
||||||
|
admin:
|
||||||
|
messagegroups:
|
||||||
|
destroy:
|
||||||
|
error: 'Nachrichtengruppe konnte nicht als gelöscht markiert werden: %{error}'
|
||||||
|
notice: Nachrichtengruppe wurde als gelöscht markiert
|
||||||
|
edit:
|
||||||
|
title: Nachrichtengruppe bearbeiten
|
||||||
|
index:
|
||||||
|
first_paragraph: Hier kannst du %{url} anlegen, Gruppen bearbeiten und löschen.
|
||||||
|
new_messagegroup: Neue Nachrichtengruppe anlegen
|
||||||
|
new_messagegroups: neue Nachrichtengruppe
|
||||||
|
title: Nachrichtengruppen
|
||||||
|
new:
|
||||||
|
title: Nachrichtengruppe anlegen
|
||||||
|
show:
|
||||||
|
confirm: Bist Du sicher?
|
||||||
|
edit: Gruppe/Mitglieder bearbeiten
|
||||||
|
send_message: Nachricht senden
|
||||||
|
title: Nachrichtengruppe %{name}
|
||||||
|
messagegroups:
|
||||||
|
members: Mitglieder
|
||||||
|
name: Name
|
||||||
|
messagegroups:
|
||||||
|
index:
|
||||||
|
body: Du kannst jede der Nachrichtengruppen beitreten oder sie wieder verlassen.
|
||||||
|
title: Nachrichtengruppen
|
||||||
|
join:
|
||||||
|
error: 'Nachrichtengruppe konnte nicht begetreten werden: %{error}'
|
||||||
|
notice: Nachrichtengruppe wurde beigetreten
|
||||||
|
leave:
|
||||||
|
error: 'Nachrichtengruppe konnte nicht verlassen werden: %{error}'
|
||||||
|
notice: Nachrichtengruppe wurde verlassen
|
||||||
|
messagegroup:
|
||||||
|
join: Nachrichtengruppe beitreten
|
||||||
|
leave: Nachrichtengruppe verlassen
|
||||||
|
messages:
|
||||||
|
index:
|
||||||
|
message_threads: Nachrichtenverläufe
|
||||||
|
message_threads:
|
||||||
|
index:
|
||||||
|
messages: Nachrichten
|
||||||
|
new: Neue Nachricht
|
||||||
|
title: Nachrichtenverläufe
|
||||||
|
show:
|
||||||
|
all_message_threads: Alle Nachrichtenverläufe
|
||||||
|
reply: Antworten
|
||||||
|
navigation:
|
||||||
|
admin:
|
||||||
|
messagegroups: Nachrichtengruppen
|
||||||
|
messagegroups: Nachrichtengruppen
|
|
@ -43,6 +43,7 @@ en:
|
||||||
create:
|
create:
|
||||||
notice: Message is saved and will be sent.
|
notice: Message is saved and will be sent.
|
||||||
index:
|
index:
|
||||||
|
message_threads: View as threads
|
||||||
new: New message
|
new: New message
|
||||||
title: Messages
|
title: Messages
|
||||||
messages:
|
messages:
|
||||||
|
@ -74,6 +75,14 @@ en:
|
||||||
sent_on: ! 'Sent:'
|
sent_on: ! 'Sent:'
|
||||||
subject: ! 'Subject:'
|
subject: ! 'Subject:'
|
||||||
title: Show message
|
title: Show message
|
||||||
|
message_threads:
|
||||||
|
index:
|
||||||
|
messages: View as messages
|
||||||
|
new: New message
|
||||||
|
title: Message threads
|
||||||
|
show:
|
||||||
|
all_message_threads: All message threads
|
||||||
|
reply: Reply
|
||||||
messages_mailer:
|
messages_mailer:
|
||||||
foodsoft_message:
|
foodsoft_message:
|
||||||
footer: ! 'Reply: %{reply_url}
|
footer: ! 'Reply: %{reply_url}
|
||||||
|
|
|
@ -1,5 +1,20 @@
|
||||||
Rails.application.routes.draw do
|
Rails.application.routes.draw do
|
||||||
scope '/:foodcoop' do
|
scope '/:foodcoop' do
|
||||||
resources :messages, :only => [:index, :show, :new, :create]
|
resources :messages, :only => [:index, :show, :new, :create]
|
||||||
|
|
||||||
|
resources :message_threads, :only => [:index, :show]
|
||||||
|
|
||||||
|
resources :messagegroups, only: [:index] do
|
||||||
|
member do
|
||||||
|
post :join
|
||||||
|
post :leave
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
namespace :admin do
|
||||||
|
resources :messagegroups do
|
||||||
|
get :memberships, on: :member
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue