Skip to content

Commit 61ce8c6

Browse files
Clicking on message marks it as read
Authorization added at the controller level.
1 parent c290e00 commit 61ce8c6

File tree

9 files changed

+154
-15
lines changed

9 files changed

+154
-15
lines changed

ecommerce/communication/lib/communication.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class Configuration
55

66
def call(event_store, command_bus)
77
command_bus.register(SendMessage, OnSendMessage.new(event_store))
8+
command_bus.register(ReadMessage, OnReadMessage.new(event_store))
89
end
910
end
1011

@@ -20,6 +21,14 @@ class MessageSent < Infra::Event
2021
attribute :message, Infra::Types::String
2122
end
2223

24+
class ReadMessage < Infra::Command
25+
attribute :message_id, Infra::Types::UUID
26+
end
27+
28+
class MessageRead < Infra::Event
29+
attribute :message_id, Infra::Types::UUID
30+
end
31+
2332
class OnSendMessage
2433
def initialize(event_store)
2534
@repository = Infra::AggregateRootRepository.new(event_store)
@@ -32,6 +41,18 @@ def call(command)
3241
end
3342
end
3443

44+
class OnReadMessage
45+
def initialize(event_store)
46+
@repository = Infra::AggregateRootRepository.new(event_store)
47+
end
48+
49+
def call(command)
50+
@repository.with_aggregate(Message, command.message_id) do |message|
51+
message.read(command.message_id)
52+
end
53+
end
54+
end
55+
3556
class Message
3657
include AggregateRoot
3758

@@ -49,7 +70,14 @@ def _send(receiver_id, message)
4970
)
5071
end
5172

73+
def read(message_id)
74+
apply MessageRead.new(data: { message_id: message_id })
75+
end
76+
5277
def apply_message_sent(_)
5378
end
79+
80+
def apply_message_read(_)
81+
end
5482
end
5583
end

ecommerce/communication/test/sending_message_test.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,37 @@ class SendingMessageTest < Test
55
cover "Communication*"
66

77
def test_happy_path
8-
expected_event = MessageSent.new(data: {message_id: message_id, receiver_id: receiver_id, message: message_content})
9-
assert_events("Communication::Message$#{message_id}", expected_event) do
8+
assert_events(message_stream,
9+
message_sent_event,
10+
message_read_event) do
1011
send_message
12+
read_message
1113
end
1214
end
15+
16+
private
17+
18+
def message_stream
19+
"Communication::Message$#{message_id}"
20+
end
21+
22+
def message_sent_event
23+
MessageSent.new(
24+
data: {
25+
message_id: message_id,
26+
receiver_id: receiver_id,
27+
message: message_content
28+
}
29+
)
30+
end
31+
32+
def message_read_event
33+
MessageRead.new(
34+
data: {
35+
message_id: message_id
36+
}
37+
)
38+
end
1339
end
1440
end
1541

ecommerce/communication/test/test_helper.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ def send_message
1616
run_command(SendMessage.new(message_id: message_id, receiver_id: receiver_id, message: message_content))
1717
end
1818

19+
def read_message
20+
run_command(ReadMessage.new(message_id: message_id))
21+
end
22+
1923
def message_content
2024
"Hello, this is a test message."
2125
end

rails_application/app/controllers/client/inbox_controller.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,13 @@ class InboxController < BaseController
44
def index
55
render html: ClientInbox::Rendering::InboxList.build(view_context, cookies[:client_id]), layout: true
66
end
7+
8+
def mark_as_read
9+
ClientInbox.authorize(cookies[:client_id], params[:message_id])
10+
command_bus.call(Communication::ReadMessage.new(message_id: params[:message_id]))
11+
redirect_to client_inbox_path
12+
rescue ClientInbox::NotAuthorized
13+
head :not_found
14+
end
715
end
816
end

rails_application/app/read_models/client_inbox/configuration.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
module ClientInbox
2+
class NotAuthorized < StandardError; end
23

34
class Message < ApplicationRecord
45
self.table_name = 'client_inbox_messages'
56
end
67

8+
def self.authorize(client_id, message_id)
9+
raise NotAuthorized unless Message.exists?(client_uid: client_id, id: message_id)
10+
end
11+
712
class Configuration
813
def call(event_store)
914
event_store.subscribe(CreateMessage.new, to: [Communication::MessageSent])
15+
event_store.subscribe(ReadMessage.new, to: [Communication::MessageRead])
1016
end
1117
end
1218

@@ -18,4 +24,12 @@ def call(event)
1824
)
1925
end
2026
end
27+
28+
class ReadMessage
29+
def call(event)
30+
message = Message.find_by(id: event.data.fetch(:message_id))
31+
message.update(read: true)
32+
message.save
33+
end
34+
end
2135
end

rails_application/app/read_models/client_inbox/rendering/inbox_list.rb

Lines changed: 37 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,23 +45,53 @@ def messages_list(messages)
4545
end
4646

4747
def message_item(message)
48+
if message.read?
49+
read_message_item(message)
50+
else
51+
unread_message_item(message)
52+
end
53+
end
54+
55+
def unread_message_item(message)
56+
div class: "flex items-start justify-between" do
57+
div class: "flex-1" do
58+
form action: client_inbox_mark_as_read_path, method: :post, class: "block", data: { turbo: false } do
59+
input type: "hidden", name: "authenticity_token", value: form_authenticity_token
60+
input type: "hidden", name: "message_id", value: message.id
61+
h3 class: message_title_classes(message), onclick: "this.closest('form').submit();" do
62+
message.title
63+
end
64+
end
65+
66+
timestamp(message.created_at)
67+
end
68+
69+
unread_indicator
70+
end
71+
end
72+
73+
def read_message_item(message)
4874
div class: "flex items-start justify-between" do
4975
div class: "flex-1" do
76+
input type: "hidden", name: "authenticity_token", value: form_authenticity_token
77+
input type: "hidden", name: "message_id", value: message.id
5078
h3 class: message_title_classes(message) do
5179
message.title
5280
end
53-
54-
span class: "text-sm text-gray-500" do
55-
time_ago_in_words(message.created_at) + " ago"
56-
end
81+
82+
timestamp(message.created_at)
5783
end
58-
59-
unread_indicator if !message.read
84+
end
85+
end
86+
87+
def timestamp(created_at)
88+
span class: "text-sm text-gray-500" do
89+
time_ago_in_words(created_at) + " ago"
6090
end
6191
end
6292

6393
def message_title_classes(message)
64-
message.read ? "text-gray-700 text-lg" : "font-bold text-gray-900 text-lg"
94+
message.read ? "text-gray-700 text-lg" : "font-bold text-gray-900 text-lg cursor-pointer"
6595
end
6696

6797
def unread_indicator

rails_application/config/routes.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
get "clients", to: "client/clients#index"
6161
get "client/products", to: "client/products#index"
6262
get "client/inbox", to: "client/inbox#index"
63+
post "client/inbox/mark_as_read", to: "client/inbox#mark_as_read"
6364

6465
mount RailsEventStore::Browser => "/res"
6566
end
Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,52 @@
11
require_relative "../test_helper"
22

33
class ClientInboxTest < InMemoryRESIntegrationTestCase
4+
45
def test_customer_sees_inbox_messages
5-
customer_id = register_customer("Test Customer")
6+
customer_id = register_customer
67
login(customer_id)
78
get "/client/inbox"
8-
99
assert_response :success
1010
assert_select "h1", "Your Inbox"
11-
assert_message("Welcome to our platform!", /minute ago/)
11+
assert_message_unread("Welcome to our platform!", /minute ago/)
12+
message_id = ClientInbox::Message.last.id
13+
post "/client/inbox/mark_as_read", params: { message_id: message_id }
14+
follow_redirect!
15+
assert_message_read("Welcome to our platform!", /minute ago/)
16+
end
17+
18+
def test_another_customer_cant_mark_my_message_as_read_even_when_know_the_id
19+
another_customer_id = register_customer("Another Customer")
20+
customer_id = register_customer
21+
login(another_customer_id)
22+
get "/client/inbox"
23+
24+
assert_response :success
25+
assert_select "h1", "Your Inbox"
26+
assert_message_unread("Welcome to our platform!", /minute ago/)
27+
other_client_message_id = ClientInbox::Message.find_by(client_uid: customer_id)
28+
29+
post "/client/inbox/mark_as_read",
30+
params: { message_id: other_client_message_id }
31+
assert_response :missing
1232
end
1333

1434
private
1535

16-
def assert_message(title, timestamp)
17-
assert_select "h3.font-bold.text-gray-900.text-lg", 1
36+
def assert_message_unread(title, timestamp)
37+
assert_select "h3.font-bold.text-gray-900.text-lg.cursor-pointer", 1
1838
assert_select "h3.font-bold.text-gray-900.text-lg", title
1939
assert_select "span.text-sm.text-gray-500", timestamp
2040
assert_select "span.inline-block.h-2.w-2.rounded-full.bg-blue-600"
2141
end
2242

43+
def assert_message_read(title, timestamp)
44+
assert_select "h3.font-bold", false
45+
assert_select "h3.text-gray-700.text-lg", 1
46+
assert_select "h3.text-gray-700.text-lg", title
47+
assert_select "span.text-sm.text-gray-500", timestamp
48+
assert_select "span.inline-block.h-2.w-2.rounded-full.bg-blue-600", 0
49+
end
50+
2351
end
2452

rails_application/test/test_helper.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ def before_teardown
149149
result
150150
end
151151

152-
def register_customer(name)
152+
def register_customer(name="Test Customer")
153153
customer_id = SecureRandom.uuid
154154
post "/customers", params: { customer_id: customer_id, name: name }
155155
customer_id

0 commit comments

Comments
 (0)