Extract message system to plugin.
This commit is contained in:
parent
fe0b17cdb0
commit
7556c753d0
45 changed files with 298 additions and 45 deletions
34
lib/foodsoft_messages/app/controllers/messages_controller.rb
Normal file
34
lib/foodsoft_messages/app/controllers/messages_controller.rb
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
class MessagesController < ApplicationController
|
||||
|
||||
# Renders the "inbox" action.
|
||||
def index
|
||||
@messages = Message.public.page(params[:page]).per(@per_page).order('created_at DESC').includes(:sender)
|
||||
end
|
||||
|
||||
# Creates a new message object.
|
||||
def new
|
||||
@message = Message.new(params[:message])
|
||||
if @message.reply_to and not @message.reply_to.is_readable_for?(current_user)
|
||||
redirect_to new_message_url, alert: 'Nachricht ist privat!'
|
||||
end
|
||||
end
|
||||
|
||||
# Creates a new message.
|
||||
def create
|
||||
@message = @current_user.send_messages.new(params[:message])
|
||||
if @message.save
|
||||
Resque.enqueue(MessageNotifier, FoodsoftConfig.scope, 'message_deliver', @message.id)
|
||||
redirect_to messages_url, :notice => I18n.t('messages.create.notice')
|
||||
else
|
||||
render :action => 'new'
|
||||
end
|
||||
end
|
||||
|
||||
# Shows a single message.
|
||||
def show
|
||||
@message = Message.find(params[:id])
|
||||
unless @message.is_readable_for?(current_user)
|
||||
redirect_to messages_url, alert: 'Nachricht ist privat!'
|
||||
end
|
||||
end
|
||||
end
|
||||
21
lib/foodsoft_messages/app/helpers/messages_helper.rb
Normal file
21
lib/foodsoft_messages/app/helpers/messages_helper.rb
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
module MessagesHelper
|
||||
def format_subject(message, length)
|
||||
if message.subject.length > length
|
||||
subject = truncate(message.subject, :length => length)
|
||||
body = ""
|
||||
else
|
||||
subject = message.subject
|
||||
body = truncate(message.body, :length => length - subject.length)
|
||||
end
|
||||
"<b>#{link_to(h(subject), message)}</b> <span style='color:grey'>#{h(body)}</span>".html_safe
|
||||
end
|
||||
|
||||
def link_to_new_message(options = {})
|
||||
messages_params = options[:message_params] || nil
|
||||
link_text = content_tag :id, nil, class: 'icon-envelope'
|
||||
link_text << " #{options[:text]}" if options[:text].present?
|
||||
link_to(link_text.html_safe, new_message_path(message: messages_params), class: 'btn',
|
||||
title: I18n.t('helpers.submit.message.create'))
|
||||
end
|
||||
|
||||
end
|
||||
11
lib/foodsoft_messages/app/mailers/messages_mailer.rb
Normal file
11
lib/foodsoft_messages/app/mailers/messages_mailer.rb
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
class MessagesMailer < Mailer
|
||||
# Sends an email copy of the given internal foodsoft message.
|
||||
def foodsoft_message(message, recipient)
|
||||
set_foodcoop_scope
|
||||
@message = message
|
||||
|
||||
mail subject: "[#{FoodsoftConfig[:name]}] " + message.subject,
|
||||
to: recipient.email,
|
||||
from: "#{show_user(message.sender)} <#{message.sender.email}>"
|
||||
end
|
||||
end
|
||||
92
lib/foodsoft_messages/app/models/message.rb
Normal file
92
lib/foodsoft_messages/app/models/message.rb
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
class Message < ActiveRecord::Base
|
||||
belongs_to :sender, :class_name => "User", :foreign_key => "sender_id"
|
||||
|
||||
serialize :recipients_ids, Array
|
||||
attr_accessor :sent_to_all, :group_id, :recipient_tokens, :reply_to
|
||||
|
||||
scope :pending, -> { where(:email_state => 0) }
|
||||
scope :sent, -> { where(:email_state => 1) }
|
||||
scope :public, -> { where(:private => false) }
|
||||
|
||||
# Values for the email_state attribute: :none, :pending, :sent, :failed
|
||||
EMAIL_STATE = {
|
||||
:pending => 0,
|
||||
:sent => 1,
|
||||
:failed => 2
|
||||
}
|
||||
|
||||
validates_presence_of :recipients_ids, :subject, :body
|
||||
validates_length_of :subject, :in => 1..255
|
||||
validates_inclusion_of :email_state, :in => EMAIL_STATE.values
|
||||
|
||||
before_validation :clean_up_recipient_ids, :on => :create
|
||||
|
||||
def self.deliver(message_id)
|
||||
find(message_id).deliver
|
||||
end
|
||||
|
||||
def clean_up_recipient_ids
|
||||
self.recipients_ids = recipients_ids.uniq.reject { |id| id.blank? } unless recipients_ids.nil?
|
||||
self.recipients_ids = User.all.collect(&:id) if sent_to_all == "1"
|
||||
end
|
||||
|
||||
def add_recipients(users)
|
||||
self.recipients_ids = [] if recipients_ids.blank?
|
||||
self.recipients_ids += users.collect(&:id) unless users.blank?
|
||||
end
|
||||
|
||||
def group_id=(group_id)
|
||||
@group_id = group_id
|
||||
add_recipients Group.find(group_id).users unless group_id.blank?
|
||||
end
|
||||
|
||||
def recipient_tokens=(ids)
|
||||
@recipient_tokens = ids
|
||||
add_recipients ids.split(",").collect { |id| User.find(id) }
|
||||
end
|
||||
|
||||
def reply_to=(message_id)
|
||||
@reply_to = Message.find(message_id)
|
||||
add_recipients([@reply_to.sender])
|
||||
self.subject = I18n.t('messages.model.reply_subject', :subject => @reply_to.subject)
|
||||
self.body = I18n.t('messages.model.reply_header', :user => @reply_to.sender.display, :when => I18n.l(@reply_to.created_at, :format => :short)) + "\n"
|
||||
@reply_to.body.each_line{ |l| self.body += I18n.t('messages.model.reply_indent', :line => l) }
|
||||
end
|
||||
|
||||
def mail_to=(user_id)
|
||||
user = User.find(user_id)
|
||||
add_recipients([user])
|
||||
end
|
||||
|
||||
# Returns true if this message is a system message, i.e. was sent automatically by the FoodSoft itself.
|
||||
def system_message?
|
||||
self.sender_id.nil?
|
||||
end
|
||||
|
||||
def sender_name
|
||||
system_message? ? I18n.t('layouts.foodsoft') : sender.display rescue "?"
|
||||
end
|
||||
|
||||
def recipients
|
||||
User.find(recipients_ids)
|
||||
end
|
||||
|
||||
def deliver
|
||||
for user in recipients
|
||||
if user.receive_email?
|
||||
begin
|
||||
MessagesMailer.foodsoft_message(self, user).deliver
|
||||
rescue
|
||||
Rails.logger.warn "Deliver failed for user \##{user.id}: #{user.email}"
|
||||
end
|
||||
end
|
||||
end
|
||||
update_attribute(:email_state, 1)
|
||||
end
|
||||
|
||||
def is_readable_for?(user)
|
||||
!private || sender == user || recipients_ids.include?(user.id)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_after 'erb:contains("delete")'
|
||||
= link_to t('.send_message'), new_message_path(:message => {:group_id => @ordergroup.id}), class: 'btn'
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_after 'erb:contains("delete")'
|
||||
= link_to t('.send_message'), new_message_path(:message => {:mail_to => @user.id}), class: 'btn'
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_after 'erb:contains("delete")'
|
||||
= link_to_new_message(message_params: {group_id: @workgroup.id})
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_bottom 'tbody tr'
|
||||
%td= link_to_new_message(message_params: {group_id: ordergroup.id})
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_bottom 'tbody tr'
|
||||
%td= link_to_new_message(message_params: {mail_to: user.id})
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_after 'erb:contains("tasks")'
|
||||
= link_to_new_message message_params: {group_id: workgroup.id}
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
/ insert_after 'erb:contains("tasks")'
|
||||
%li= link_to t('.write_message'), new_message_path
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
/ insert_after 'erb[silent]:contains("<dashboard_middle_mark>")'
|
||||
- unless Message.public.empty?
|
||||
%section#messages
|
||||
%h2= t '.messages.title'
|
||||
= render 'messages/messages', messages: Message.public.order('created_at DESC').limit(5), pagination: false
|
||||
%p= link_to t('.messages.view_all'), messages_path
|
||||
14
lib/foodsoft_messages/app/views/messages/_messages.html.haml
Normal file
14
lib/foodsoft_messages/app/views/messages/_messages.html.haml
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
- if pagination
|
||||
- if Message.public.count > 20
|
||||
= items_per_page
|
||||
= pagination_links_remote messages
|
||||
|
||||
- unless messages.empty?
|
||||
%table.table.table-striped
|
||||
%tbody
|
||||
- for message in messages
|
||||
%tr
|
||||
%td= format_subject(message, 130)
|
||||
%td= h(message.sender_name)
|
||||
%td= format_time(message.created_at)
|
||||
%td= link_to t('.reply'), new_message_path(:message => {:reply_to => message.id}), class: 'btn'
|
||||
6
lib/foodsoft_messages/app/views/messages/index.html.haml
Normal file
6
lib/foodsoft_messages/app/views/messages/index.html.haml
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
- title t('.title')
|
||||
|
||||
- content_for :actionbar do
|
||||
= link_to t('.new'), new_message_path, class: 'btn btn-primary'
|
||||
#messages
|
||||
= render 'messages', messages: @messages, pagination: true
|
||||
1
lib/foodsoft_messages/app/views/messages/index.js.haml
Normal file
1
lib/foodsoft_messages/app/views/messages/index.js.haml
Normal file
|
|
@ -0,0 +1 @@
|
|||
$('#messages').html('#{j(render('messages', messages: @messages, pagination: true))}');
|
||||
46
lib/foodsoft_messages/app/views/messages/new.haml
Normal file
46
lib/foodsoft_messages/app/views/messages/new.haml
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
- content_for :javascript do
|
||||
:javascript
|
||||
$(function() {
|
||||
$('#message_recipient_tokens').tokenInput("#{users_path(:format => :json)}", {
|
||||
crossDomain: false,
|
||||
prePopulate: $('#message_recipient_tokens').data('pre'),
|
||||
hintText: '#{t '.search_user'}',
|
||||
noResultText: '#{t '.no_user_found'}',
|
||||
searchingText: '#{t '.search'}',
|
||||
theme: 'facebook'
|
||||
});
|
||||
|
||||
$('#message_sent_to_all').on('touchclick', function() {
|
||||
if ($(this).is(':checked')) {
|
||||
$('#recipients').slideUp();
|
||||
} else {
|
||||
$('#recipients').slideDown();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
- title t('.title')
|
||||
|
||||
= simple_form_for @message do |f|
|
||||
- if FoodsoftConfig[:mailing_list].blank?
|
||||
= f.input :sent_to_all, :as => :boolean
|
||||
- else
|
||||
%b= t('.list.desc', list: mail_to(FoodsoftConfig[:mailing_list])).html_safe
|
||||
%br/
|
||||
%small{:style => "color:grey"}
|
||||
= t '.list.subscribe_msg'
|
||||
%br/
|
||||
- if FoodsoftConfig[:mailing_list_subscribe].blank?
|
||||
= t('.list.subscribe', link: link_to(t('.list.wiki'), wiki_page_path('MailingListe'))).html_safe
|
||||
- else
|
||||
= t('.list.mail', email: mail_to(FoodsoftConfig[:mailing_list_subscribe])).html_safe
|
||||
|
||||
#recipients
|
||||
= f.input :recipient_tokens, :input_html => { 'data-pre' => User.where(id: @message.recipients_ids).map(&:token_attributes).to_json }
|
||||
= f.input :group_id, :as => :select, :collection => Group.undeleted.order('type DESC, name ASC').reject { |g| g.memberships.empty? }
|
||||
= f.input :private
|
||||
= f.input :subject, input_html: {class: 'input-xxlarge'}
|
||||
= f.input :body, input_html: {class: 'input-xxlarge'}
|
||||
.form-actions
|
||||
= f.submit class: 'btn btn-primary'
|
||||
= link_to t('ui.or_cancel'), :back
|
||||
21
lib/foodsoft_messages/app/views/messages/show.haml
Normal file
21
lib/foodsoft_messages/app/views/messages/show.haml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
- title t('.title')
|
||||
|
||||
%div{:style => "width:40em"}
|
||||
%table{:style => "width:25em"}
|
||||
%tr
|
||||
%td= t '.from'
|
||||
%td=h @message.sender_name
|
||||
%tr
|
||||
%td= t '.subject'
|
||||
%td
|
||||
%b=h @message.subject
|
||||
%tr
|
||||
%td= t '.sent_on'
|
||||
%td= format_time(@message.created_at)
|
||||
%hr/
|
||||
%p= simple_format(h(@message.body))
|
||||
%hr/
|
||||
%p
|
||||
= link_to t('.reply'), new_message_path(:message => {:reply_to => @message.id}), class: 'btn'
|
||||
|
|
||||
= link_to t('.all_messages'), messages_path
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
= @message.body
|
||||
======================================================================
|
||||
\
|
||||
= t '.footer', reply_url: new_message_url('message[reply_to]' => @message.id), msg_url: message_url(@message), profile_url: my_profile_url
|
||||
8
lib/foodsoft_messages/app/workers/message_notifier.rb
Normal file
8
lib/foodsoft_messages/app/workers/message_notifier.rb
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
class MessageNotifier < UserNotifier
|
||||
@queue = :foodsoft_notifier
|
||||
|
||||
def self.message_deliver(args)
|
||||
message_id = args.first
|
||||
Message.find(message_id).deliver
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Add a link
Reference in a new issue