Merge pull request #403 from foodcoops/feature/402-messagegroups

Add messagegroups
This commit is contained in:
wvengen 2016-03-07 22:36:37 +01:00
commit 14e2fd179e
29 changed files with 228 additions and 53 deletions

View file

@ -6,6 +6,7 @@
%dd=h group.contact %dd=h group.contact
%dt= heading_helper(Ordergroup, :contact_address) + ':' %dt= heading_helper(Ordergroup, :contact_address) + ':'
%dd= link_to_gmaps group.contact_address %dd= link_to_gmaps group.contact_address
- if group.is_a?(Workgroup)
%dt= t('.access') + ':' %dt= t('.access') + ':'
%dd= format_roles(group) %dd= format_roles(group)
%dt= heading_helper(Ordergroup, :user_tokens) + ':' %dt= heading_helper(Ordergroup, :user_tokens) + ':'

View file

@ -71,7 +71,7 @@ de:
group_id: Gruppe group_id: Gruppe
private: Privat private: Privat
recipient_tokens: Empfänger_innen recipient_tokens: Empfänger_innen
sent_to_all: An alle Mitglieder schicken send_to_all: An alle Mitglieder schicken
subject: Betreff subject: Betreff
order: order:
closed_by: Abgerechnet von closed_by: Abgerechnet von

View file

@ -71,7 +71,7 @@ en:
group_id: Group group_id: Group
private: Private private: Private
recipient_tokens: Recipients recipient_tokens: Recipients
sent_to_all: Send to all members send_to_all: Send to all members
subject: Subject subject: Subject
order: order:
boxfill: Fill boxes after boxfill: Fill boxes after

View file

@ -71,7 +71,7 @@ fr:
group_id: Cellule ou équipe group_id: Cellule ou équipe
private: Privé private: Privé
recipient_tokens: Destinataires recipient_tokens: Destinataires
sent_to_all: Envoyer à tous les membres send_to_all: Envoyer à tous les membres
subject: Sujet subject: Sujet
order: order:
closed_by: Décompté par closed_by: Décompté par

View file

@ -71,7 +71,7 @@ nl:
group_id: Groep group_id: Groep
private: Privé private: Privé
recipient_tokens: Geadresseerden recipient_tokens: Geadresseerden
sent_to_all: Aan alle leden sturen send_to_all: Aan alle leden sturen
subject: Onderwerp subject: Onderwerp
order: order:
closed_by: Afgerekend door closed_by: Afgerekend door

View file

@ -0,0 +1,20 @@
# encoding: utf-8
class Admin::MessagegroupsController < Admin::BaseController
inherit_resources
def index
@messagegroups = Messagegroup.order('name ASC')
# if somebody uses the search field:
@messagegroups = @messagegroups.where('name LIKE ?', "%#{params[:query]}%") unless params[:query].blank?
@messagegroups = @messagegroups.page(params[:page]).per(@per_page)
end
def destroy
@messagegroup = Messagegroup.find(params[:id])
@messagegroup.destroy
redirect_to admin_messagegroups_url, notice: t('admin.messagegroups.destroy.notice')
rescue => error
redirect_to admin_messagegroups_url, alert: t('admin.messagegroups.destroy.error', error: error.message)
end
end

View file

@ -0,0 +1,18 @@
class MessagegroupsController < ApplicationController
def index
@messagegroups = Messagegroup.order("name")
end
def join
@messagegroup = Messagegroup.find(params[:id])
@messagegroup.users << current_user
redirect_to messagegroups_url, :notice => I18n.t('messagegroups.join.notice')
end
def leave
@messagegroup = Messagegroup.find(params[:id])
@messagegroup.users.destroy(current_user)
redirect_to messagegroups_url, :notice => I18n.t('messagegroups.leave.notice')
end
end

View file

@ -24,7 +24,7 @@ class MessagesController < ApplicationController
@message.body = I18n.t('messages.model.reply_header', :user => original_message.sender.display, :when => I18n.l(original_message.created_at, :format => :short)) + "\n" @message.body = I18n.t('messages.model.reply_header', :user => original_message.sender.display, :when => I18n.l(original_message.created_at, :format => :short)) + "\n"
original_message.body.each_line{ |l| @message.body += I18n.t('messages.model.reply_indent', :line => l) } original_message.body.each_line{ |l| @message.body += I18n.t('messages.model.reply_indent', :line => l) }
else else
redirect_to new_message_url, alert: 'Nachricht ist privat!' redirect_to new_message_url, alert: I18n.t('messages.new.error_private')
end end
end end
end end

View file

@ -7,14 +7,14 @@ class MessagesMailer < Mailer
reply_email_domain = FoodsoftConfig[:reply_email_domain] reply_email_domain = FoodsoftConfig[:reply_email_domain]
if reply_email_domain if reply_email_domain
hash = message.mail_hash_for_user recipient hash = message.mail_hash_for_user recipient
reply_to = "Foodsoft <#{FoodsoftConfig.scope}.#{message.id}.#{recipient.id}.#{hash}@#{reply_email_domain}>" reply_to = "#{I18n.t('layouts.foodsoft')} <#{FoodsoftConfig.scope}.#{message.id}.#{recipient.id}.#{hash}@#{reply_email_domain}>"
else else
reply_to = "#{show_user(message.sender)} <#{message.sender.email}>" reply_to = "#{show_user(message.sender)} <#{message.sender.email}>"
end end
mail subject: "[#{FoodsoftConfig[:name]}] " + message.subject, mail subject: "[#{FoodsoftConfig[:name]}] " + message.subject,
to: recipient.email, to: recipient.email,
from: "#{show_user(message.sender)} via Foodsoft <#{FoodsoftConfig[:email_sender]}>", from: "#{show_user(message.sender)} via #{I18n.t('layouts.foodsoft')} <#{FoodsoftConfig[:email_sender]}>",
reply_to: reply_to reply_to: reply_to
end end
end end

View file

@ -6,7 +6,7 @@ class Message < ActiveRecord::Base
belongs_to :reply_to_message, :class_name => "Message", :foreign_key => "reply_to" belongs_to :reply_to_message, :class_name => "Message", :foreign_key => "reply_to"
serialize :recipients_ids, Array serialize :recipients_ids, Array
attr_accessor :sent_to_all, :recipient_tokens attr_accessor :send_to_all, :recipient_tokens
scope :pending, -> { where(:email_state => 0) } scope :pending, -> { where(:email_state => 0) }
scope :sent, -> { where(:email_state => 1) } scope :sent, -> { where(:email_state => 1) }
@ -35,7 +35,7 @@ class Message < ActiveRecord::Base
def clean_up_recipient_ids def clean_up_recipient_ids
add_recipients Group.find(group_id).users unless group_id.blank? add_recipients Group.find(group_id).users unless group_id.blank?
self.recipients_ids = recipients_ids.uniq.reject { |id| id.blank? } unless recipients_ids.nil? 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" self.recipients_ids = User.all.collect(&:id) if send_to_all == "1"
end end
def add_recipients(users) def add_recipients(users)

View file

@ -0,0 +1,7 @@
# encoding: utf-8
class Messagegroup < Group
validates_uniqueness_of :name
protected
end

View file

@ -4,7 +4,4 @@
%section#messages %section#messages
%h2= t '.messages.title' %h2= t '.messages.title'
= render 'messages/messages', messages: Message.pub.order('created_at DESC').limit(5), pagination: false = render 'messages/messages', messages: Message.pub.order('created_at DESC').limit(5), pagination: false
%p %p= raw t '.messages.view_all.text', messages: link_to(t('.messages.view_all.messages'), messages_path), threads: link_to(t('.messages.view_all.threads'), message_threads_path)
= link_to t('.messages.view_all'), messages_path
!= ' | '
= link_to t('.message_threads.view_all'), message_threads_path

View file

@ -1,4 +1,9 @@
/ insert_before 'erb:contains("simple_fields_for :notify")' / insert_after 'erb:contains("notify.input \'upcoming_tasks\'")'
- if FoodsoftMessages.enabled? - if FoodsoftMessages.enabled?
= s.simple_fields_for :messages, defaults: { inline_label: true, label: false } do |messages| = s.simple_fields_for :messages, defaults: { inline_label: true, label: false } do |messages|
= messages.input 'send_as_email', as: :boolean, input_html: { checked: f.object.settings.messages['send_as_email'] } = messages.input 'send_as_email', as: :boolean, input_html: { checked: f.object.settings.messages['send_as_email'] }
- if Messagegroup.any?
.controls
= link_to messagegroups_path do
= t '.messagegroups'
%i.icon.icon-chevron-right

View file

@ -0,0 +1,5 @@
= simple_form_for [:admin, @messagegroup] do |f|
= render 'shared/group_form_fields', :f => f
.form-actions
= f.button :submit
= link_to t('ui.or_cancel'), :back

View file

@ -0,0 +1,18 @@
- if Messagegroup.count > 20
= items_per_page
= pagination_links_remote @messagegroups
%table.table.table-striped
%thead
%tr
%th= Messagegroup.human_attribute_name :name
%th= Messagegroup.human_attribute_name :user_tokens
%th= t 'ui.actions'
%tbody
- for messagegroup in @messagegroups
%tr
%td= link_to messagegroup.name, [:admin, messagegroup]
%td= messagegroup.users.size
%td
= link_to t('ui.edit'), edit_admin_messagegroup_path(messagegroup), class: 'btn btn-mini'
= link_to t('ui.delete'), [:admin, messagegroup], :data => {:confirm => t('admin.confirm', name: messagegroup.name)},
:method => :delete, class: 'btn btn-mini btn-danger'

View file

@ -0,0 +1,3 @@
- title t '.title'
= render 'form'

View file

@ -0,0 +1,15 @@
- title t '.title'
- content_for :actionbar do
= link_to t('.new_messagegroup'), new_admin_messagegroup_path, class: 'btn btn-primary'
- content_for :sidebar do
%p= t('.first_paragraph', url: link_to(t('.new_messagegroups'), new_admin_messagegroup_path)).html_safe
%p= t '.second_paragraph'
.well.well-small
= form_tag admin_messagegroups_path, :method => :get, :remote => true,
'data-submit-onchange' => true, class: 'form-search' do
= text_field_tag :query, params[:query], class: 'input-medium search-query',
placeholder: t('admin.search_placeholder')
#messagegroups
= render "messagegroups"

View file

@ -0,0 +1 @@
$('#messagegroups').html('#{escape_javascript(render("messagegroups"))}');

View file

@ -0,0 +1,3 @@
- title t '.title'
= render 'form'

View file

@ -0,0 +1,6 @@
- title t '.title', name: @messagegroup.name
%section= render 'shared/group', group: @messagegroup
= link_to t('ui.edit'), edit_admin_messagegroup_path(@messagegroup), class: 'btn'
= link_to t('ui.delete'), [:admin, @messagegroup], :data => {:confirm => t('ui.confirm_delete', name: @messagegroup.name)}, :method => :delete, class: 'btn btn-danger'
= link_to t('.send_message'), new_message_path(:message => {:group_id => @messagegroup.id}), class: 'btn'

View file

@ -1,8 +1,6 @@
- title t('.title') - title t('.title')
- content_for :actionbar do = render 'messages/actionbar', active: 'message_threads'
= link_to t('.messages'), messages_path, class: 'btn'
= link_to t('.new'), new_message_path, class: 'btn btn-primary'
= render 'groupmessage_threads', group: nil, name: t('.other'), id: 0 = render 'groupmessage_threads', group: nil, name: t('.other'), id: 0

View file

@ -0,0 +1,8 @@
%section.well
%h3= messagegroup.name
= render :partial => 'shared/group', :locals => { :group => messagegroup }
= link_to_new_message(message_params: {group_id: messagegroup.id})
- if messagegroup.member?(current_user)
= link_to t('.leave'), leave_messagegroup_path(messagegroup), class: 'btn', method: :post
- else
= link_to t('.join'), join_messagegroup_path(messagegroup), class: 'btn', method: :post

View file

@ -0,0 +1,5 @@
- title t('.title')
%p= t('.body')
= render :partial => "messagegroup", :collection => @messagegroups

View file

@ -0,0 +1,8 @@
- content_for :actionbar do
.btn-group
= link_to message_threads_path, class: "btn #{'active' if active == 'message_threads'}" do
%i.icon.icon-align-left{title: t('.message_threads')}
= link_to messages_path, class: "btn #{'active' if active == 'messages'}" do
%i.icon.icon-align-justify{title: t('.messages')}
= link_to t('.messagegroups'), messagegroups_path, class: 'btn'
= link_to t('.new'), new_message_path, class: 'btn btn-primary'

View file

@ -1,7 +1,6 @@
- title t('.title') - title t('.title')
- content_for :actionbar do = render 'actionbar', active: 'messages'
= link_to t('.message_threads'), message_threads_path, class: 'btn'
= 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

View file

@ -10,7 +10,7 @@
theme: 'facebook' theme: 'facebook'
}); });
$('#message_sent_to_all').on('change', function() { $('#message_send_to_all').on('change', function() {
if ($(this).is(':checked')) { if ($(this).is(':checked')) {
$('#recipients').slideUp(); $('#recipients').slideUp();
} else { } else {
@ -18,7 +18,7 @@
} }
}); });
// make sure state is correct when loading // make sure state is correct when loading
$('#recipients').toggle(!$('#message_sent_to_all').is(':checked')); $('#recipients').toggle(!$('#message_send_to_all').is(':checked'));
}); });
- title t('.title') - title t('.title')
@ -30,7 +30,7 @@
%p= t('.reply_to', link: link_to(t('.message'), message_path(@message.reply_to))).html_safe %p= t('.reply_to', link: link_to(t('.message'), message_path(@message.reply_to))).html_safe
- if FoodsoftConfig[:mailing_list].blank? - if FoodsoftConfig[:mailing_list].blank?
= f.input :sent_to_all, :as => :boolean = f.input :send_to_all, :as => :boolean
- else - else
%b= t('.list.desc', list: mail_to(FoodsoftConfig[:mailing_list])).html_safe %b= t('.list.desc', list: mail_to(FoodsoftConfig[:mailing_list])).html_safe
%br/ %br/

View file

@ -18,21 +18,20 @@ de:
first_paragraph: Hier kannst du %{url} anlegen, Gruppen bearbeiten und löschen. first_paragraph: Hier kannst du %{url} anlegen, Gruppen bearbeiten und löschen.
new_messagegroup: Neue Nachrichtengruppe anlegen new_messagegroup: Neue Nachrichtengruppe anlegen
new_messagegroups: neue Nachrichtengruppe new_messagegroups: neue Nachrichtengruppe
second_paragraph: Eine Nachrichtengruppe ist wie ein Mail-Verteilen. Mitglieder können Verteiler in ihrem Profil abonnieren (und auch wieder abbestellen) an denen sie interessiert sind.
title: Nachrichtengruppen title: Nachrichtengruppen
new: new:
title: Nachrichtengruppe anlegen title: Nachrichtengruppe anlegen
show: show:
confirm: Bist Du sicher?
edit: Gruppe/Mitglieder bearbeiten
send_message: Nachricht senden send_message: Nachricht senden
title: Nachrichtengruppe %{name} title: Nachrichtengruppe %{name}
messagegroups:
members: Mitglieder
name: Name
home: home:
index: index:
message_threads: messages:
view_all: Alle Nachrichteverläufe anzeigen view_all:
text: '%{messages} oder %{threads} anzeigen'
messages:
threads:
messagegroups: messagegroups:
index: index:
body: Du kannst jede der Nachrichtengruppen beitreten oder sie wieder verlassen. body: Du kannst jede der Nachrichtengruppen beitreten oder sie wieder verlassen.
@ -47,8 +46,11 @@ de:
join: Nachrichtengruppe beitreten join: Nachrichtengruppe beitreten
leave: Nachrichtengruppe verlassen leave: Nachrichtengruppe verlassen
messages: messages:
index: actionbar:
message_threads: Nachrichtenverläufe message_threads:
messagegroups:
messages:
new: Neue Nachricht
thread: thread:
all_message_threads: Alle Nachrichtenverläufe all_message_threads: Alle Nachrichtenverläufe
reply: Antworten reply: Antworten
@ -56,8 +58,6 @@ de:
groupmessage_threads: groupmessage_threads:
show_message_threads: Alle Nachrichtenverläufe anzeigen show_message_threads: Alle Nachrichtenverläufe anzeigen
index: index:
messages: Nachrichten
new: Neue Nachricht
other: Allgemeine Nachrichten other: Allgemeine Nachrichten
title: Nachrichtenverläufe title: Nachrichtenverläufe
message_threads: message_threads:
@ -70,4 +70,3 @@ de:
navigation: navigation:
admin: admin:
messagegroups: Nachrichtengruppen messagegroups: Nachrichtengruppen
messagegroups: Nachrichtengruppen

View file

@ -6,11 +6,33 @@ en:
group_id: Group group_id: Group
private: Private private: Private
recipient_tokens: Recipients recipient_tokens: Recipients
sent_to_all: Send to all members send_to_all: Send to all members
subject: Subject subject: Subject
messagegroup:
description: Description
name: Name
user_tokens: Members
models: models:
message: Message message: Message
messagegroup: Message group
admin: admin:
messagegroups:
destroy:
error: 'Message group could not be deleted: %{error}'
notice: Message group was deleted
edit:
title: Edit message group
index:
first_paragraph: Here you can create %{url}, edit and delete them.
new_messagegroup: Create new message group
new_messagegroups: new message groups
second_paragraph: "A message group is like a mailing-list. Members can subscribe to (and unsubscribe from) the lists they're interested in, from their profile."
title: Message groups
new:
title: Create message group
show:
send_message: Send message
title: Message group %{name}
ordergroups: ordergroups:
show: show:
send_message: Send message send_message: Send message
@ -35,16 +57,35 @@ en:
home: home:
index: index:
messages: messages:
title: Newest Messages title: Newest messages
view_all: See all messages view_all:
text: 'Show %{messages} or %{threads}'
messages: all messages
threads: threads
start_nav: start_nav:
write_message: Write message write_message: Write message
messagegroups:
index:
body: 'A message group is like a mailing-list: you can join (or leave) any of them to receive the updates sent to that group.'
title: Message groups
join:
error: 'Could not join message group: %{error}'
notice: Joined message group
leave:
error: 'Messagegroup could not be left: %{error}'
notice: Left message group
messagegroup:
join: Join message group
leave: Leave message group
messages: messages:
actionbar:
message_threads: Show as threads
messagegroups: Subscribe to groups
messages: Show as list
new: New message
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
title: Messages title: Messages
messages: messages:
reply: Reply reply: Reply
@ -53,6 +94,7 @@ en:
reply_indent: ! '> %{line}' reply_indent: ! '> %{line}'
reply_subject: ! 'Re: %{subject}' reply_subject: ! 'Re: %{subject}'
new: new:
error_private: Sorry, this message is private.
hint_private: Message doesnt show in Foodsoft mail inbox hint_private: Message doesnt show in Foodsoft mail inbox
list: list:
desc: ! 'Please send messages to all using the mailing-list: %{list}' desc: ! 'Please send messages to all using the mailing-list: %{list}'
@ -77,18 +119,20 @@ en:
title: Show message title: Show message
thread: thread:
all_message_threads: All message threads all_message_threads: All message threads
reply: Reply
message_threads: message_threads:
groupmessage_threads: groupmessage_threads:
show_message_threads: show all show_message_threads: show all
index: index:
messages: View as messages
new: New message
other: General other: General
title: Message threads title: Message threads
message_threads:
last_reply_at: Last replied at
last_reply_by: Last replied by
started_at: Started at
started_by: Started by
show: show:
all_message_threads: All message threads
other: General other: General
reply: Reply
messages_mailer: messages_mailer:
foodsoft_message: foodsoft_message:
footer: ! 'Reply: %{reply_url} footer: ! 'Reply: %{reply_url}
@ -99,4 +143,9 @@ en:
' '
navigation: navigation:
admin:
messagegroups: Message groups
messages: Messages messages: Messages
shared:
user_form_fields:
messagegroups: Join or leave message groups

View file

@ -2,15 +2,25 @@ module FoodsoftMessages
class Engine < ::Rails::Engine class Engine < ::Rails::Engine
def navigation(primary, context) def navigation(primary, context)
return unless FoodsoftMessages.enabled? return unless FoodsoftMessages.enabled?
return if primary[:foodcoop].nil? unless primary[:foodcoop].nil?
sub_nav = primary[:foodcoop].sub_navigation sub_nav = primary[:foodcoop].sub_navigation
sub_nav.items << sub_nav.items <<
SimpleNavigation::Item.new(primary, :message_threads, I18n.t('navigation.messages'), context.message_threads_path) SimpleNavigation::Item.new(primary, :messages, I18n.t('navigation.messages'), context.message_threads_path)
# move to right before tasks item # move to right before tasks item
if i = sub_nav.items.index(sub_nav[:tasks]) if i = sub_nav.items.index(sub_nav[:tasks])
sub_nav.items.insert(i, sub_nav.items.delete_at(-1)) sub_nav.items.insert(i, sub_nav.items.delete_at(-1))
end end
end end
unless primary[:admin].nil?
sub_nav = primary[:admin].sub_navigation
sub_nav.items <<
SimpleNavigation::Item.new(primary, :messagegroups, I18n.t('navigation.admin.messagegroups'), context.admin_messagegroups_path)
# move to right before config item
if i = sub_nav.items.index(sub_nav[:config])
sub_nav.items.insert(i, sub_nav.items.delete_at(-1))
end
end
end
def default_foodsoft_config(cfg) def default_foodsoft_config(cfg)
cfg[:use_messages] = true cfg[:use_messages] = true