discuss 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/MIT-LICENSE +20 -0
- data/README.md +153 -0
- data/Rakefile +34 -0
- data/app/assets/javascripts/discuss/application.js +3 -0
- data/app/assets/javascripts/discuss/chosen.jquery.js +1104 -0
- data/app/assets/javascripts/discuss/compose.coffee +21 -0
- data/app/assets/javascripts/discuss/discuss.chosen.coffee +2 -0
- data/app/assets/javascripts/discuss/discuss.coffee +2 -0
- data/app/assets/javascripts/discuss/messages.coffee +0 -0
- data/app/assets/stylesheets/discuss/application.css +13 -0
- data/app/assets/stylesheets/discuss/chosen.css +439 -0
- data/app/controllers/discuss/application_controller.rb +11 -0
- data/app/controllers/discuss/mailboxes_controller.rb +30 -0
- data/app/controllers/discuss/messages_controller.rb +85 -0
- data/app/helpers/discuss/application_helper.rb +7 -0
- data/app/models/discuss/conversation.rb +29 -0
- data/app/models/discuss/mailbox.rb +33 -0
- data/app/models/discuss/message.rb +135 -0
- data/app/services/discuss/message_sender.rb +33 -0
- data/app/views/discuss/mailboxes/show.html.haml +24 -0
- data/app/views/discuss/messages/_form.html.haml +18 -0
- data/app/views/discuss/messages/edit.html.haml +1 -0
- data/app/views/discuss/messages/new.html.haml +1 -0
- data/app/views/discuss/messages/show.html.haml +28 -0
- data/app/views/discuss/shared/_nav.haml +8 -0
- data/config/routes.rb +15 -0
- data/db/migrate/20130419055252_setup_discuss.rb +22 -0
- data/lib/discuss.rb +4 -0
- data/lib/discuss/engine.rb +9 -0
- data/lib/discuss/models/discussable.rb +29 -0
- data/lib/discuss/version.rb +3 -0
- data/lib/generators/discuss/views_generator.rb +8 -0
- data/lib/tasks/discuss_tasks.rake +4 -0
- data/test/discuss_test.rb +7 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +5 -0
- data/test/dummy/app/assets/javascripts/chosen.jquery.js +1104 -0
- data/test/dummy/app/assets/javascripts/compose.coffee +21 -0
- data/test/dummy/app/assets/javascripts/discuss.chosen.coffee +2 -0
- data/test/dummy/app/assets/javascripts/discuss.coffee +2 -0
- data/test/dummy/app/assets/javascripts/messages.coffee +0 -0
- data/test/dummy/app/assets/stylesheets/application.css +13 -0
- data/test/dummy/app/assets/stylesheets/chosen.css +439 -0
- data/test/dummy/app/assets/stylesheets/discuss.css +41 -0
- data/test/dummy/app/controllers/application_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/models/user.rb +22 -0
- data/test/dummy/app/views/layouts/application.html.erb +17 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +9 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +27 -0
- data/test/dummy/config/environments/production.rb +80 -0
- data/test/dummy/config/environments/test.rb +36 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +12 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +4 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/db/migrate/20130428235128_create_users.rb +11 -0
- data/test/dummy/db/schema.rb +24 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +16219 -0
- data/test/dummy/log/test.log +191354 -0
- data/test/dummy/public/404.html +27 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/0a28667732e1be8938cde061b6f996df +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/0ddd7cc29057a69bd29fde03bf0f4c00 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/0de2f69502366965bb7fae2623bc190c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/0ee691067e6ec8f03df58bc94badd25d +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/1b77abb6bee52fa8d68ee7e81077ff20 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/271bb8f72971af6089be8d1b85788bec +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2a499e57eb2664f139ab0e74571faa77 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/32b6af14546cb11e773fb3799f041132 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/4728f8b9616c35f685674fbeecaa3c47 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/4e9a3e121da30d3a85273a5c283da214 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/5620ff4659033b350ea3031ecaeb5127 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/596293af7e4dcfa45880435ae753f876 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/614995c5e7b1b4f5b12ce060404706cc +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6b9e24a8aad25948823e1a93c8be731e +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/78a00003621b318a297e05cfedb0d1fd +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/794654d117cd2ec6a9a00e485d9f4485 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/79ae3a9f48e9b9e8ef2922c844b1895f +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9b5889bea21f2af8068646890752932c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/9fd02d20091838d6411df2d23a5364d5 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/a02345b542298f25d3f701ee680c44c0 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/a80359c0e09ddf510ce63de09a368d4c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ad2a9bfe4169e0a5bc66efd35c83fe38 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b1794788ec8ce362aceaffa31c7381e9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b284f477944d67f25c0672dba1a2dab4 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b2b1f16cf54d69c151ca7f42fb2f8381 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b4767dfdb540517d26dc8c5365736f53 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/bab78b46d2a6282e5df747dd8b6d5abf +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/c9a09977565da30179ad7fdb9f79ae0d +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d9c8047218dc90a46a6725543638de45 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/e5b181eb056bbd6ffad37ed146b0342e +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/0a28667732e1be8938cde061b6f996df +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/0ddd7cc29057a69bd29fde03bf0f4c00 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/0de2f69502366965bb7fae2623bc190c +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/1b77abb6bee52fa8d68ee7e81077ff20 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/271bb8f72971af6089be8d1b85788bec +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/32b6af14546cb11e773fb3799f041132 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/4728f8b9616c35f685674fbeecaa3c47 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/5620ff4659033b350ea3031ecaeb5127 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/596293af7e4dcfa45880435ae753f876 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/78a00003621b318a297e05cfedb0d1fd +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/794654d117cd2ec6a9a00e485d9f4485 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/79ae3a9f48e9b9e8ef2922c844b1895f +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/9b5889bea21f2af8068646890752932c +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/9fd02d20091838d6411df2d23a5364d5 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/a02345b542298f25d3f701ee680c44c0 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/a80359c0e09ddf510ce63de09a368d4c +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/ad2a9bfe4169e0a5bc66efd35c83fe38 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/bab78b46d2a6282e5df747dd8b6d5abf +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/c9a09977565da30179ad7fdb9f79ae0d +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d9c8047218dc90a46a6725543638de45 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/features/workflow_test.rb +182 -0
- data/test/test_helper.rb +68 -0
- data/test/unit/discuss/conversation_test.rb +79 -0
- data/test/unit/discuss/mailbox_test.rb +72 -0
- data/test/unit/discuss/message_test.rb +73 -0
- data/test/unit/discuss/recipient_test.rb +56 -0
- data/test/unit/discuss/sender_test.rb +106 -0
- data/test/unit/helpers/discuss/messages_helper_test.rb +6 -0
- metadata +422 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require_dependency 'discuss/application_controller'
|
2
|
+
|
3
|
+
module Discuss
|
4
|
+
class MailboxesController < ApplicationController
|
5
|
+
before_action :check_mailbox_params, only: :show
|
6
|
+
|
7
|
+
def show
|
8
|
+
@messages = Mailbox.new(discuss_current_user).send mailbox_name
|
9
|
+
end
|
10
|
+
|
11
|
+
def empty_trash
|
12
|
+
Mailbox.new(discuss_current_user).empty_trash!
|
13
|
+
redirect_to mailbox_path(:inbox), notice: 'Trash has been emptied'
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def check_mailbox_params
|
18
|
+
redirect_to mailbox_path(:inbox) unless valid_mailbox?
|
19
|
+
end
|
20
|
+
|
21
|
+
def valid_mailbox?
|
22
|
+
%w{inbox outbox drafts trash}.include? params[:mailbox]
|
23
|
+
end
|
24
|
+
|
25
|
+
def mailbox_name
|
26
|
+
params[:mailbox]
|
27
|
+
end
|
28
|
+
helper_method :mailbox_name
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_dependency 'discuss/application_controller'
|
2
|
+
|
3
|
+
module Discuss
|
4
|
+
class MessagesController < ApplicationController
|
5
|
+
before_action :message, only: [:show, :update, :destroy]
|
6
|
+
before_action :can_view_message, only: [:show, :edit, :destroy]
|
7
|
+
|
8
|
+
def new
|
9
|
+
@message = discuss_current_user.messages.new
|
10
|
+
end
|
11
|
+
|
12
|
+
def show
|
13
|
+
redirect_to edit_message_path(message) unless message.received? || message.sent?
|
14
|
+
end
|
15
|
+
|
16
|
+
def create
|
17
|
+
@message = Message.new(message_params.merge(user: discuss_current_user))
|
18
|
+
if @message.save
|
19
|
+
send_message
|
20
|
+
else
|
21
|
+
render :new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# [e] avoiding validation exception. Should be done nicer
|
26
|
+
def reply
|
27
|
+
@message = Message.find(params[:message_id])
|
28
|
+
if params[:message][:body]
|
29
|
+
@message.reply! message_params.merge(user: discuss_current_user)
|
30
|
+
redirect_to mailbox_path(:inbox), notice: 'Reply sent'
|
31
|
+
else
|
32
|
+
redirect_to message, alert: "Don't you want to say something?"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def edit
|
37
|
+
redirect_to message unless message.unsent?
|
38
|
+
end
|
39
|
+
|
40
|
+
def update
|
41
|
+
message.update(message_params)
|
42
|
+
send_message
|
43
|
+
end
|
44
|
+
|
45
|
+
def trash
|
46
|
+
@message = Message.find(params[:message_id])
|
47
|
+
@message.trash!
|
48
|
+
redirect_to mailbox_path(:inbox), notice: 'Message moved to trash'
|
49
|
+
end
|
50
|
+
|
51
|
+
def destroy
|
52
|
+
message.delete!
|
53
|
+
redirect_to mailbox_path(:inbox), notice: 'Message deleted'
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
def message
|
58
|
+
@message ||= Message.find(params[:id])
|
59
|
+
end
|
60
|
+
helper_method :message
|
61
|
+
|
62
|
+
def message_params
|
63
|
+
params.require(:message).permit(:subject, :body, :draft, draft_recipient_ids: [])
|
64
|
+
end
|
65
|
+
|
66
|
+
def send_message
|
67
|
+
message.send!
|
68
|
+
notice = message.sent? ? 'Yay! Message sent' : 'Draft saved'
|
69
|
+
redirect_to mailbox_path(:inbox), notice: notice
|
70
|
+
end
|
71
|
+
|
72
|
+
def mailbox_name
|
73
|
+
params[:mailbox] || message.mailbox.to_s
|
74
|
+
end
|
75
|
+
helper_method :mailbox_name
|
76
|
+
|
77
|
+
def can_view_message
|
78
|
+
redirect_to mailbox_path(:inbox), notice: 'Unauthorised!' unless mine?
|
79
|
+
end
|
80
|
+
|
81
|
+
def mine?
|
82
|
+
message.user == discuss_current_user
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# conversation should be in the context of a user,
|
2
|
+
# so we grab only the messages the user owns
|
3
|
+
# but we are defaulting to the message user just in case
|
4
|
+
module Discuss
|
5
|
+
class Conversation
|
6
|
+
attr_accessor :message, :user
|
7
|
+
|
8
|
+
def initialize(message, user=nil)
|
9
|
+
@message = message
|
10
|
+
@user = user || message.user
|
11
|
+
end
|
12
|
+
|
13
|
+
def root
|
14
|
+
message.root
|
15
|
+
end
|
16
|
+
|
17
|
+
def for_user
|
18
|
+
all.by_user(user)
|
19
|
+
end
|
20
|
+
|
21
|
+
def all
|
22
|
+
root.subtree
|
23
|
+
end
|
24
|
+
|
25
|
+
def trash_conversation!
|
26
|
+
for_user.each { |message| message.trash! }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# @mailbox ||= Mailbox.new(current_user)
|
2
|
+
|
3
|
+
module Discuss
|
4
|
+
class Mailbox
|
5
|
+
attr_accessor :user
|
6
|
+
|
7
|
+
def initialize(user)
|
8
|
+
@user = user
|
9
|
+
end
|
10
|
+
|
11
|
+
def inbox
|
12
|
+
Message.inbox(user)
|
13
|
+
end
|
14
|
+
|
15
|
+
def outbox
|
16
|
+
Message.outbox(user)
|
17
|
+
end
|
18
|
+
|
19
|
+
def drafts
|
20
|
+
Message.drafts(user)
|
21
|
+
end
|
22
|
+
|
23
|
+
def trash
|
24
|
+
Message.trash(user)
|
25
|
+
end
|
26
|
+
|
27
|
+
def empty_trash!
|
28
|
+
trash.each { |message| message.delete! }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Discuss
|
4
|
+
class Message < ActiveRecord::Base
|
5
|
+
has_ancestry
|
6
|
+
|
7
|
+
attr_accessor :draft
|
8
|
+
serialize :draft_recipient_ids, Array
|
9
|
+
|
10
|
+
belongs_to :user
|
11
|
+
|
12
|
+
validates :body, :user_id, presence: true
|
13
|
+
validate :lock_down_attributes, on: :update
|
14
|
+
|
15
|
+
scope :ordered, -> { order('created_at asc') }
|
16
|
+
scope :active, -> { not_trashed.not_deleted }
|
17
|
+
|
18
|
+
scope :draft, -> { where('sent_at is NULL') }
|
19
|
+
scope :not_draft, -> { where('sent_at is not NULL') }
|
20
|
+
|
21
|
+
scope :sent, -> { where('sent_at is not NULL') }
|
22
|
+
scope :unsent, -> { where('sent_at is NULL') }
|
23
|
+
|
24
|
+
scope :received, -> { where('received_at is not NULL') }
|
25
|
+
scope :not_received, -> { where('received_at is NULL') }
|
26
|
+
|
27
|
+
scope :trashed, -> { where('trashed_at is not NULL') }
|
28
|
+
scope :not_trashed, -> { where('trashed_at is NULL') }
|
29
|
+
|
30
|
+
scope :deleted, -> { where('deleted_at is not NULL') }
|
31
|
+
scope :not_deleted, -> { where('deleted_at is NULL') }
|
32
|
+
|
33
|
+
scope :by_user, lambda { |user| where(user_id: user.id) }
|
34
|
+
scope :inbox, lambda { |user| by_user(user).active.received }
|
35
|
+
scope :outbox, lambda { |user| by_user(user).active.sent }
|
36
|
+
scope :drafts, lambda { |user| by_user(user).active.draft.not_received }
|
37
|
+
scope :trash, lambda { |user| by_user(user).trashed.not_deleted }
|
38
|
+
|
39
|
+
def active?
|
40
|
+
!trashed? && !deleted?
|
41
|
+
end
|
42
|
+
|
43
|
+
def sender
|
44
|
+
sent? ? user : parent.user
|
45
|
+
end
|
46
|
+
|
47
|
+
def recipients
|
48
|
+
sent? ? children.collect(&:user) : parent.recipients
|
49
|
+
end
|
50
|
+
|
51
|
+
def recipients= users
|
52
|
+
users.each { |u| draft_recipient_ids << u.id }
|
53
|
+
end
|
54
|
+
|
55
|
+
def recipient_list
|
56
|
+
draft_recipient_ids.reject(&:blank?).map {|id| User.find id}
|
57
|
+
end
|
58
|
+
|
59
|
+
def mailbox
|
60
|
+
case
|
61
|
+
when sent? then :outbox
|
62
|
+
when received? then :inbox
|
63
|
+
when !new_record? && unsent? then :drafts
|
64
|
+
when trashed? then :trash
|
65
|
+
else
|
66
|
+
:compose
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
def send!
|
71
|
+
lock.synchronize do
|
72
|
+
Discuss::MessageSender.new(self).run unless draft?
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def reply! options={}
|
77
|
+
if parent
|
78
|
+
reply = children.create!(subject: options.fetch(:subject, subject),
|
79
|
+
body: options.fetch(:body, nil),
|
80
|
+
user: user,
|
81
|
+
recipients: [parent.user])
|
82
|
+
reply.send!
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def receive!
|
87
|
+
update(received_at: Time.zone.now)
|
88
|
+
end
|
89
|
+
|
90
|
+
def read!
|
91
|
+
update(read_at: Time.zone.now)
|
92
|
+
end
|
93
|
+
|
94
|
+
def trash!
|
95
|
+
update(trashed_at: Time.zone.now)
|
96
|
+
end
|
97
|
+
|
98
|
+
def delete!
|
99
|
+
update(deleted_at: Time.zone.now)
|
100
|
+
end
|
101
|
+
|
102
|
+
%w[sent received trashed deleted read].each do |act|
|
103
|
+
define_method "#{act}?" do
|
104
|
+
self.send(:"#{act}_at").present?
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def uneditable?
|
109
|
+
!editable?
|
110
|
+
end
|
111
|
+
|
112
|
+
def unsent?
|
113
|
+
!sent?
|
114
|
+
end
|
115
|
+
|
116
|
+
# passed in from the compose form
|
117
|
+
def draft?
|
118
|
+
self.draft == '1'
|
119
|
+
end
|
120
|
+
|
121
|
+
def sent_date
|
122
|
+
sent_at || received_at
|
123
|
+
end
|
124
|
+
|
125
|
+
private
|
126
|
+
def lock_down_attributes
|
127
|
+
return if editable?
|
128
|
+
errors.add(:base, 'Cannot edit') unless deleted_at_changed? || trashed_at_changed? || read_at_changed?
|
129
|
+
end
|
130
|
+
|
131
|
+
def lock
|
132
|
+
@lock ||= Mutex.new
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Discuss::MessageSender
|
2
|
+
attr_reader :message, :recipients
|
3
|
+
|
4
|
+
delegate :body, to: :message
|
5
|
+
delegate :subject, to: :message
|
6
|
+
|
7
|
+
def initialize message
|
8
|
+
@message = message
|
9
|
+
@recipients = message.recipient_list
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
deliver!
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
def set_as_sent
|
18
|
+
message.update_column(:sent_at, Time.zone.now)
|
19
|
+
message.update_column(:editable, false)
|
20
|
+
end
|
21
|
+
|
22
|
+
def deliver!
|
23
|
+
if recipients.any? && message.unsent?
|
24
|
+
set_as_sent
|
25
|
+
recipients.each { |user| deliver_to user }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def deliver_to user
|
30
|
+
attrs = {subject: subject, body: body, user: user, received_at: Time.zone.now, editable: false }
|
31
|
+
message.children.create(attrs)
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
%section#discuss(class="mailboxes #{mailbox_name}")
|
2
|
+
%h2= mailbox_name.humanize
|
3
|
+
|
4
|
+
.summary= pluralize(@messages.size, 'message')
|
5
|
+
|
6
|
+
= render 'discuss/shared/nav'
|
7
|
+
|
8
|
+
%section.messages
|
9
|
+
- if @messages.any?
|
10
|
+
%table
|
11
|
+
%tbody
|
12
|
+
- @messages.each do |message|
|
13
|
+
%tr[message]
|
14
|
+
%td.user
|
15
|
+
= link_to message_person(mailbox_name, message), mailbox_message_path(message.mailbox, message)
|
16
|
+
%td.preview
|
17
|
+
= link_to message.try(:subject), mailbox_message_path(message.mailbox, message)
|
18
|
+
= link_to truncate(message.body, length: 50), mailbox_message_path(message.mailbox, message)
|
19
|
+
%td.sent_at
|
20
|
+
= message.created_at.to_date
|
21
|
+
|
22
|
+
- if mailbox_name == 'trash'
|
23
|
+
= form_tag empty_trash_path do
|
24
|
+
= submit_tag 'Empty trash'
|
@@ -0,0 +1,18 @@
|
|
1
|
+
%section#discuss(class = "#{mailbox_name}")
|
2
|
+
%h2= mailbox_name.humanize
|
3
|
+
= render 'discuss/shared/nav'
|
4
|
+
|
5
|
+
.compose.message
|
6
|
+
= simple_form_for @message do |f|
|
7
|
+
- if @message.errors.any?
|
8
|
+
%p.errors This message has #{pluralize(@message.errors.count, 'error')}
|
9
|
+
|
10
|
+
- # TODO review User.all query
|
11
|
+
- # TODO if no first_name and last_name, display user's email
|
12
|
+
= f.input :draft_recipient_ids, collection: User.all.reject{|u| u == discuss_current_user }, input_html: {class: 'chosen', multiple: true}, label: 'Recipients'
|
13
|
+
= f.input :subject
|
14
|
+
= f.input :body, required: false, label: 'Your message'
|
15
|
+
= f.input :draft, as: :boolean
|
16
|
+
|
17
|
+
= f.submit 'Send message'
|
18
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'form'
|
@@ -0,0 +1 @@
|
|
1
|
+
= render 'form'
|
@@ -0,0 +1,28 @@
|
|
1
|
+
%section#discuss(class = "#{mailbox_name}")
|
2
|
+
%h2= mailbox_name.humanize
|
3
|
+
|
4
|
+
= render 'discuss/shared/nav'
|
5
|
+
|
6
|
+
.message
|
7
|
+
%ul.headers
|
8
|
+
%li.subject Subject: #{message.try(:subject)}
|
9
|
+
%li.sender Sender: #{message.sender}
|
10
|
+
%li.sent_at Date: #{message.sent_date.to_date}
|
11
|
+
- # Do we want recipient names to be links? or have any data attributes like the user.id?
|
12
|
+
%li.recipients Recipients: #{message.recipients.join(', ')}
|
13
|
+
|
14
|
+
.body= message.body
|
15
|
+
|
16
|
+
- unless message.trashed?
|
17
|
+
.move_to_trash
|
18
|
+
= simple_form_for @message, url: message_trash_path(@message), method: :post do |f|
|
19
|
+
= f.submit 'Move to trash'
|
20
|
+
|
21
|
+
- if message.received?
|
22
|
+
.compose.reply
|
23
|
+
%h3 Reply
|
24
|
+
= simple_form_for @message, url: message_reply_path(@message), method: :post do |f|
|
25
|
+
= f.input :subject, input_html: { value: "Re: #{@message.subject}" }
|
26
|
+
= f.input :body, required: false, label: 'Your message', input_html: { value: '' }
|
27
|
+
= f.input :draft, as: :boolean
|
28
|
+
= f.submit 'Reply'
|