turbo_chat 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +192 -607
- data/app/assets/config/turbo_chat_manifest.js +6 -0
- data/app/assets/javascripts/turbo_chat/application.js +4 -0
- data/app/assets/javascripts/{chat_gem → turbo_chat}/lifecycle_events.js +1 -1
- data/app/assets/javascripts/{chat_gem → turbo_chat}/messages.js +4 -4
- data/app/assets/javascripts/{chat_gem → turbo_chat}/realtime.js +3 -3
- data/app/controllers/turbo_chat/application_controller.rb +66 -0
- data/app/controllers/{chat_gem → turbo_chat}/chat_memberships_controller.rb +4 -4
- data/app/controllers/{chat_gem → turbo_chat}/chat_messages_controller.rb +7 -7
- data/app/controllers/{chat_gem → turbo_chat}/chats_controller/event_payload_support.rb +5 -5
- data/app/controllers/{chat_gem → turbo_chat}/chats_controller/invitation_support.rb +4 -4
- data/app/controllers/{chat_gem → turbo_chat}/chats_controller.rb +10 -10
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/config_support.rb +2 -2
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/mention_support/entry_builder.rb +1 -1
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/mention_support/permission_support.rb +2 -2
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/mention_support/token_builder.rb +1 -1
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/mention_support.rb +5 -5
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/message_rendering.rb +11 -11
- data/app/helpers/{chat_gem → turbo_chat}/application_helper/participant_support.rb +2 -2
- data/app/helpers/turbo_chat/application_helper.rb +12 -0
- data/app/models/{chat_gem → turbo_chat}/application_record.rb +1 -1
- data/app/models/{chat_gem → turbo_chat}/chat.rb +7 -7
- data/app/models/{chat_gem → turbo_chat}/chat_membership.rb +5 -5
- data/app/models/{chat_gem → turbo_chat}/chat_message/blocked_words_moderation.rb +7 -7
- data/app/models/{chat_gem → turbo_chat}/chat_message/body_length_validation.rb +2 -2
- data/app/models/{chat_gem → turbo_chat}/chat_message/broadcasting.rb +1 -1
- data/app/models/{chat_gem → turbo_chat}/chat_message/formatting.rb +3 -3
- data/app/models/{chat_gem → turbo_chat}/chat_message/mention_validation.rb +3 -3
- data/app/models/{chat_gem → turbo_chat}/chat_message/signals.rb +2 -2
- data/app/models/{chat_gem → turbo_chat}/chat_message.rb +11 -11
- data/app/views/layouts/turbo_chat/application.html.erb +20 -0
- data/app/views/turbo_chat/chat_messages/_chat_message.html.erb +1 -0
- data/app/views/{chat_gem → turbo_chat}/chat_messages/_form.html.erb +2 -2
- data/app/views/{chat_gem → turbo_chat}/chat_messages/_message.html.erb +2 -2
- data/app/views/{chat_gem → turbo_chat}/chat_messages/_signals.html.erb +1 -1
- data/app/views/{chat_gem → turbo_chat}/chats/show.html.erb +3 -3
- data/config/routes.rb +1 -1
- data/db/migrate/20260215000000_create_turbo_chat_chats.rb +8 -0
- data/db/migrate/{20260215000001_create_chat_gem_chat_memberships.rb → 20260215000001_create_turbo_chat_chat_memberships.rb} +5 -5
- data/db/migrate/{20260215000002_create_chat_gem_chat_messages.rb → 20260215000002_create_turbo_chat_chat_messages.rb} +4 -4
- data/db/migrate/20260218000011_add_closed_at_to_turbo_chat_chats.rb +6 -0
- data/db/migrate/20260218000012_add_custom_role_key_to_chat_memberships.rb +2 -2
- data/db/migrate/20260218000013_add_invitation_accepted_to_turbo_chat_chat_memberships.rb +5 -0
- data/lib/generators/turbo_chat/install/install_generator.rb +1 -1
- data/lib/generators/turbo_chat/install/templates/turbo_chat.rb +2 -0
- data/lib/tasks/turbo_chat_tasks.rake +6 -2
- data/lib/{chat_gem → turbo_chat}/configuration.rb +4 -2
- data/lib/turbo_chat/engine.rb +29 -0
- data/lib/{chat_gem → turbo_chat}/model_extensions/chat_participant.rb +6 -6
- data/lib/{chat_gem → turbo_chat}/moderation.rb +11 -11
- data/lib/{chat_gem → turbo_chat}/permission.rb +1 -1
- data/lib/{chat_gem → turbo_chat}/signals.rb +5 -5
- data/lib/turbo_chat/version.rb +1 -3
- data/lib/turbo_chat.rb +11 -15
- metadata +53 -58
- data/app/assets/config/chat_gem_manifest.js +0 -6
- data/app/assets/javascripts/chat_gem/application.js +0 -4
- data/app/controllers/chat_gem/application_controller.rb +0 -41
- data/app/helpers/chat_gem/application_helper.rb +0 -12
- data/app/views/chat_gem/chat_messages/_chat_message.html.erb +0 -1
- data/app/views/layouts/chat_gem/application.html.erb +0 -20
- data/db/migrate/20260215000000_create_chat_gem_chats.rb +0 -8
- data/db/migrate/20260218000011_add_closed_at_to_chat_gem_chats.rb +0 -6
- data/db/migrate/20260218000013_add_invitation_accepted_to_chat_gem_chat_memberships.rb +0 -5
- data/lib/chat_gem/engine.rb +0 -29
- data/lib/chat_gem/version.rb +0 -3
- data/lib/chat_gem.rb +0 -24
- data/lib/generators/chat_gem/install/install_generator.rb +0 -18
- data/lib/generators/chat_gem/install/templates/chat_gem.rb +0 -36
- data/lib/tasks/chat_gem_tasks.rake +0 -1
- /data/app/assets/javascripts/{chat_gem → turbo_chat}/shared.js +0 -0
- /data/app/assets/stylesheets/{chat_gem → turbo_chat}/application.css +0 -0
- /data/app/views/{chat_gem → turbo_chat}/chat_messages/_signal.html.erb +0 -0
- /data/app/views/{chat_gem → turbo_chat}/chat_messages/index.html.erb +0 -0
- /data/app/views/{chat_gem → turbo_chat}/chats/index.html.erb +0 -0
- /data/app/views/{chat_gem → turbo_chat}/chats/new.html.erb +0 -0
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
});
|
|
41
41
|
|
|
42
42
|
if (!canEditMessage) {
|
|
43
|
-
messageNode.dispatchEvent(new CustomEvent("chat
|
|
43
|
+
messageNode.dispatchEvent(new CustomEvent("turbo-chat:inline-edit-close"));
|
|
44
44
|
messageNode.querySelectorAll("[data-chat-message-view]").forEach(function (viewContainer) {
|
|
45
45
|
viewContainer.hidden = false;
|
|
46
46
|
});
|
|
@@ -195,7 +195,7 @@
|
|
|
195
195
|
return;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
var event = new CustomEvent("chat
|
|
198
|
+
var event = new CustomEvent("turbo-chat:mention", {
|
|
199
199
|
bubbles: true,
|
|
200
200
|
detail: {
|
|
201
201
|
chatId: container.dataset.chatId || null,
|
|
@@ -276,7 +276,7 @@
|
|
|
276
276
|
return;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
-
otherMessageNode.dispatchEvent(new CustomEvent("chat
|
|
279
|
+
otherMessageNode.dispatchEvent(new CustomEvent("turbo-chat:inline-edit-close"));
|
|
280
280
|
});
|
|
281
281
|
}
|
|
282
282
|
|
|
@@ -323,7 +323,7 @@
|
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
messageNode.dataset.chatInlineEditBound = "true";
|
|
326
|
-
messageNode.addEventListener("chat
|
|
326
|
+
messageNode.addEventListener("turbo-chat:inline-edit-close", function () {
|
|
327
327
|
setEditing(false, { restoreOriginal: true });
|
|
328
328
|
});
|
|
329
329
|
|
|
@@ -180,7 +180,7 @@
|
|
|
180
180
|
return;
|
|
181
181
|
}
|
|
182
182
|
|
|
183
|
-
var event = new CustomEvent("chat
|
|
183
|
+
var event = new CustomEvent("turbo-chat:message-sent", {
|
|
184
184
|
bubbles: true,
|
|
185
185
|
detail: {
|
|
186
186
|
chatId: element.dataset.chatId || null
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
|
|
276
276
|
signalActive = true;
|
|
277
277
|
if (!typingEventEmitted) {
|
|
278
|
-
emitTypingEvent("chat
|
|
278
|
+
emitTypingEvent("turbo-chat:typing-started");
|
|
279
279
|
typingEventEmitted = true;
|
|
280
280
|
}
|
|
281
281
|
sendTypingSignal();
|
|
@@ -320,7 +320,7 @@
|
|
|
320
320
|
|
|
321
321
|
signalActive = false;
|
|
322
322
|
if (typingEventEmitted) {
|
|
323
|
-
emitTypingEvent("chat
|
|
323
|
+
emitTypingEvent("turbo-chat:typing-ended");
|
|
324
324
|
typingEventEmitted = false;
|
|
325
325
|
}
|
|
326
326
|
postSignal({ clear: true });
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module TurboChat
|
|
2
|
+
class ApplicationController < ::ApplicationController
|
|
3
|
+
layout "turbo_chat/application"
|
|
4
|
+
|
|
5
|
+
helper_method :current_chat_participant
|
|
6
|
+
|
|
7
|
+
private
|
|
8
|
+
|
|
9
|
+
def current_chat_participant
|
|
10
|
+
participant, source = resolve_current_chat_participant
|
|
11
|
+
return participant if participant.nil? || participant.respond_to?(:active_chat_memberships)
|
|
12
|
+
|
|
13
|
+
raise ArgumentError, "#{source} must return a model that uses `acts_as_chat_participant`"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def resolve_current_chat_participant
|
|
17
|
+
if (super_method = method(:current_chat_participant).super_method)
|
|
18
|
+
return [super_method.call, "#current_chat_participant"]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
resolver = TurboChat.configuration.current_participant_resolver
|
|
22
|
+
if resolver.respond_to?(:call)
|
|
23
|
+
return [invoke_current_participant_resolver(resolver), "TurboChat current_participant_resolver"]
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if respond_to?(:current_user, true)
|
|
27
|
+
return [send(:current_user), "#current_user"]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
raise NotImplementedError, "Define #current_chat_participant, configure TurboChat.configuration.current_participant_resolver, or expose #current_user"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def invoke_current_participant_resolver(resolver)
|
|
34
|
+
case resolver.arity
|
|
35
|
+
when 0
|
|
36
|
+
resolver.call
|
|
37
|
+
when 1
|
|
38
|
+
resolver.call(self)
|
|
39
|
+
else
|
|
40
|
+
resolver.call(self, request)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def permission_for(chat = nil)
|
|
45
|
+
TurboChat.configuration.permission_adapter.new(current_chat_participant, chat)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def authorize_create_chat!
|
|
49
|
+
return if permission_for.can_create_chat?
|
|
50
|
+
|
|
51
|
+
head :forbidden
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def authorize_view_chat!(chat)
|
|
55
|
+
return if permission_for(chat).can_view_chat?
|
|
56
|
+
|
|
57
|
+
head :forbidden
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def authorize_post_message!(chat)
|
|
61
|
+
return if permission_for(chat).can_post_message?
|
|
62
|
+
|
|
63
|
+
head :forbidden
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class ChatMembershipsController < ApplicationController
|
|
3
|
-
include
|
|
3
|
+
include TurboChat::ChatsController::EventPayloadSupport
|
|
4
4
|
|
|
5
5
|
before_action :set_chat
|
|
6
6
|
before_action -> { authorize_view_chat!(@chat) }
|
|
@@ -37,7 +37,7 @@ module ChatGem
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
def set_chat
|
|
40
|
-
@chat =
|
|
40
|
+
@chat = TurboChat::Chat.find(params[:chat_id])
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def authorize_invite_member!
|
|
@@ -73,7 +73,7 @@ module ChatGem
|
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def invitation_pending_attributes
|
|
76
|
-
return {} unless
|
|
76
|
+
return {} unless TurboChat::ChatMembership.invitation_tracking_supported?
|
|
77
77
|
|
|
78
78
|
{ invitation_accepted: false }
|
|
79
79
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class ChatMessagesController < ApplicationController
|
|
3
3
|
before_action :set_chat
|
|
4
4
|
before_action -> { authorize_view_chat!(@chat) }, only: :index
|
|
@@ -37,7 +37,7 @@ module ChatGem
|
|
|
37
37
|
private
|
|
38
38
|
|
|
39
39
|
def set_chat
|
|
40
|
-
@chat =
|
|
40
|
+
@chat = TurboChat::Chat.find(params[:chat_id])
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def chat_message_params
|
|
@@ -64,7 +64,7 @@ module ChatGem
|
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
def respond_to_clear_signal_request
|
|
67
|
-
|
|
67
|
+
TurboChat::ChatMessage.clear_signals!(chat: @chat, participant: current_chat_participant)
|
|
68
68
|
respond_to do |format|
|
|
69
69
|
format.turbo_stream { render_signals_update }
|
|
70
70
|
format.html { redirect_to chat_path(@chat) }
|
|
@@ -85,15 +85,15 @@ module ChatGem
|
|
|
85
85
|
@chat_permission = permission_for(@chat)
|
|
86
86
|
@can_post_message = @chat_permission.can_post_message?
|
|
87
87
|
respond_to do |format|
|
|
88
|
-
format.turbo_stream { render "
|
|
89
|
-
format.html { render "
|
|
88
|
+
format.turbo_stream { render "turbo_chat/chats/show", status: :unprocessable_entity }
|
|
89
|
+
format.html { render "turbo_chat/chats/show", status: :unprocessable_entity }
|
|
90
90
|
end
|
|
91
91
|
end
|
|
92
92
|
|
|
93
93
|
def render_signals_update
|
|
94
94
|
render turbo_stream: turbo_stream.update(
|
|
95
95
|
view_context.dom_id(@chat, :signals),
|
|
96
|
-
partial: "
|
|
96
|
+
partial: "turbo_chat/chat_messages/signals",
|
|
97
97
|
locals: { chat: @chat }
|
|
98
98
|
)
|
|
99
99
|
end
|
|
@@ -132,7 +132,7 @@ module ChatGem
|
|
|
132
132
|
locals[:force_edit_open] = true if force_edit_open
|
|
133
133
|
render turbo_stream: turbo_stream.replace(
|
|
134
134
|
view_context.dom_id(@chat_message),
|
|
135
|
-
partial: "
|
|
135
|
+
partial: "turbo_chat/chat_messages/message",
|
|
136
136
|
locals: locals
|
|
137
137
|
), status: status
|
|
138
138
|
end
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class ChatsController < ApplicationController
|
|
3
3
|
module EventPayloadSupport
|
|
4
4
|
private
|
|
5
5
|
|
|
6
6
|
def invitation_accepted_payload
|
|
7
|
-
payload = flash[:
|
|
7
|
+
payload = flash[:turbo_chat_invitation_accepted]
|
|
8
8
|
return nil unless payload.respond_to?(:to_h)
|
|
9
9
|
|
|
10
10
|
symbolized_payload = payload.to_h.symbolize_keys
|
|
@@ -21,7 +21,7 @@ module ChatGem
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def chat_lifecycle_event_payload
|
|
24
|
-
payload = flash[:
|
|
24
|
+
payload = flash[:turbo_chat_chat_lifecycle_event]
|
|
25
25
|
return nil unless payload.respond_to?(:to_h)
|
|
26
26
|
|
|
27
27
|
symbolized_payload = payload.to_h.symbolize_keys
|
|
@@ -45,8 +45,8 @@ module ChatGem
|
|
|
45
45
|
return if action.blank? || chat.nil?
|
|
46
46
|
|
|
47
47
|
action_key = action.to_s
|
|
48
|
-
flash[:
|
|
49
|
-
eventName: "chat
|
|
48
|
+
flash[:turbo_chat_chat_lifecycle_event] = {
|
|
49
|
+
eventName: "turbo-chat:chat-#{action_key}",
|
|
50
50
|
action: action_key,
|
|
51
51
|
chatId: chat.id.to_s,
|
|
52
52
|
chatTitle: chat.title,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class ChatsController < ApplicationController
|
|
3
3
|
module InvitationSupport
|
|
4
4
|
private
|
|
@@ -17,10 +17,10 @@ module ChatGem
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def pending_invitations_for(participant)
|
|
20
|
-
return
|
|
21
|
-
return
|
|
20
|
+
return TurboChat::ChatMembership.none if participant.nil?
|
|
21
|
+
return TurboChat::ChatMembership.none unless TurboChat::ChatMembership.invitation_tracking_supported?
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
TurboChat::ChatMembership
|
|
24
24
|
.pending
|
|
25
25
|
.where(participant: participant)
|
|
26
26
|
.includes(:chat)
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class ChatsController < ApplicationController
|
|
3
|
-
include
|
|
4
|
-
include
|
|
3
|
+
include TurboChat::ChatsController::InvitationSupport
|
|
4
|
+
include TurboChat::ChatsController::EventPayloadSupport
|
|
5
5
|
|
|
6
6
|
before_action :authorize_create_chat!, only: %i[new create]
|
|
7
7
|
before_action :set_chat, only: %i[show accept decline leave close reopen]
|
|
8
8
|
|
|
9
9
|
def index
|
|
10
10
|
participant = current_chat_participant
|
|
11
|
-
@chats =
|
|
11
|
+
@chats = TurboChat::Chat.for_participant(participant).order(created_at: :desc, id: :desc)
|
|
12
12
|
@pending_invitations = pending_invitations_for(participant)
|
|
13
13
|
@invitation_accepted_event = invitation_accepted_payload
|
|
14
14
|
@chat_lifecycle_event = chat_lifecycle_event_payload
|
|
@@ -17,13 +17,13 @@ module ChatGem
|
|
|
17
17
|
def accept
|
|
18
18
|
participant = current_chat_participant
|
|
19
19
|
return head :forbidden if participant.nil?
|
|
20
|
-
return redirect_to(chats_path, alert: "Run latest
|
|
20
|
+
return redirect_to(chats_path, alert: "Run latest turbo_chat migrations to accept invitations", status: :see_other) unless TurboChat::ChatMembership.invitation_tracking_supported?
|
|
21
21
|
|
|
22
22
|
membership = @chat.chat_memberships.pending.find_by(participant: participant)
|
|
23
23
|
return redirect_to(chats_path, alert: "Invitation not found", status: :see_other) if membership.nil?
|
|
24
24
|
|
|
25
25
|
membership.accept_invitation!
|
|
26
|
-
flash[:
|
|
26
|
+
flash[:turbo_chat_invitation_accepted] = {
|
|
27
27
|
chatId: @chat.id,
|
|
28
28
|
chatTitle: @chat.title,
|
|
29
29
|
chatMembershipId: membership.id
|
|
@@ -35,7 +35,7 @@ module ChatGem
|
|
|
35
35
|
def decline
|
|
36
36
|
participant = current_chat_participant
|
|
37
37
|
return head :forbidden if participant.nil?
|
|
38
|
-
return redirect_to(chats_path, alert: "Run latest
|
|
38
|
+
return redirect_to(chats_path, alert: "Run latest turbo_chat migrations to decline invitations", status: :see_other) unless TurboChat::ChatMembership.invitation_tracking_supported?
|
|
39
39
|
|
|
40
40
|
membership = @chat.chat_memberships.pending.find_by(participant: participant)
|
|
41
41
|
return redirect_to(chats_path, alert: "Invitation not found", status: :see_other) if membership.nil?
|
|
@@ -46,11 +46,11 @@ module ChatGem
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
def new
|
|
49
|
-
@chat =
|
|
49
|
+
@chat = TurboChat::Chat.new
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def create
|
|
53
|
-
@chat =
|
|
53
|
+
@chat = TurboChat::Chat.new(chat_params)
|
|
54
54
|
|
|
55
55
|
if @chat.save
|
|
56
56
|
membership = @chat.chat_memberships.create!(participant: current_chat_participant, role: :admin)
|
|
@@ -115,7 +115,7 @@ module ChatGem
|
|
|
115
115
|
private
|
|
116
116
|
|
|
117
117
|
def set_chat
|
|
118
|
-
@chat =
|
|
118
|
+
@chat = TurboChat::Chat.find(params[:id])
|
|
119
119
|
end
|
|
120
120
|
|
|
121
121
|
def chat_params
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
module ApplicationHelper
|
|
3
3
|
module ConfigSupport
|
|
4
4
|
def chat_mention_filter_exclude_self?
|
|
@@ -24,7 +24,7 @@ module ChatGem
|
|
|
24
24
|
private
|
|
25
25
|
|
|
26
26
|
def chat_config_value(method_name, default: nil)
|
|
27
|
-
configuration =
|
|
27
|
+
configuration = TurboChat.configuration
|
|
28
28
|
return default unless configuration.respond_to?(method_name)
|
|
29
29
|
|
|
30
30
|
configuration.public_send(method_name)
|
data/app/helpers/{chat_gem → turbo_chat}/application_helper/mention_support/permission_support.rb
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
module ApplicationHelper
|
|
3
3
|
module MentionSupport
|
|
4
4
|
module PermissionSupport
|
|
@@ -10,7 +10,7 @@ module ChatGem
|
|
|
10
10
|
participant = current_chat_participant
|
|
11
11
|
return nil if participant.nil?
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
TurboChat.configuration.permission_adapter.new(participant, chat)
|
|
14
14
|
rescue StandardError
|
|
15
15
|
nil
|
|
16
16
|
end
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
module ApplicationHelper
|
|
3
3
|
module MentionSupport
|
|
4
|
-
include
|
|
5
|
-
include
|
|
6
|
-
include
|
|
4
|
+
include TurboChat::ApplicationHelper::MentionSupport::TokenBuilder
|
|
5
|
+
include TurboChat::ApplicationHelper::MentionSupport::EntryBuilder
|
|
6
|
+
include TurboChat::ApplicationHelper::MentionSupport::PermissionSupport
|
|
7
7
|
|
|
8
8
|
def chat_mention_options(chat:, permission: nil)
|
|
9
9
|
mention_permission = permission || mention_permission_for(chat)
|
|
@@ -66,7 +66,7 @@ module ChatGem
|
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
def chat_mentions_enabled_for?(chat:, permission: nil)
|
|
69
|
-
return false unless
|
|
69
|
+
return false unless TurboChat.configuration.enable_mentions
|
|
70
70
|
|
|
71
71
|
mention_permission = permission || mention_permission_for(chat)
|
|
72
72
|
return true if mention_permission.nil?
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
module ApplicationHelper
|
|
3
3
|
module MessageRendering
|
|
4
4
|
def chat_message_css_classes(chat_message:, own_message:)
|
|
@@ -26,18 +26,18 @@ module ChatGem
|
|
|
26
26
|
|
|
27
27
|
def render_chat_message_body(chat_message)
|
|
28
28
|
body = chat_message.body.to_s
|
|
29
|
-
return content_tag(:p, decorate_plain_message_text(body).html_safe, class: "chat-body") unless
|
|
29
|
+
return content_tag(:p, decorate_plain_message_text(body).html_safe, class: "chat-body") unless TurboChat.configuration.render_message_html
|
|
30
30
|
|
|
31
31
|
sanitized_html = sanitize(
|
|
32
32
|
body,
|
|
33
|
-
tags: Array(
|
|
34
|
-
attributes: Array(
|
|
33
|
+
tags: Array(TurboChat.configuration.message_html_tags),
|
|
34
|
+
attributes: Array(TurboChat.configuration.message_html_attributes)
|
|
35
35
|
)
|
|
36
36
|
content_tag(:div, sanitized_html, class: "chat-body")
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def chat_message_mention_tokens(chat_message)
|
|
40
|
-
return [] unless
|
|
40
|
+
return [] unless TurboChat.configuration.enable_mentions
|
|
41
41
|
return [] if chat_message.nil?
|
|
42
42
|
|
|
43
43
|
chat_message.body.to_s.scan(MENTION_PATTERN).uniq
|
|
@@ -46,7 +46,7 @@ module ChatGem
|
|
|
46
46
|
private
|
|
47
47
|
|
|
48
48
|
def resolve_custom_message_css_classes(chat_message:, own_message:)
|
|
49
|
-
resolver =
|
|
49
|
+
resolver = TurboChat.configuration.message_css_class_resolver
|
|
50
50
|
return [] unless resolver.respond_to?(:call)
|
|
51
51
|
|
|
52
52
|
classes = case resolver.arity
|
|
@@ -69,12 +69,12 @@ module ChatGem
|
|
|
69
69
|
role_color = resolve_role_message_hex_color(chat_message: chat_message, own_message: own_message)
|
|
70
70
|
return role_color if role_color.present?
|
|
71
71
|
|
|
72
|
-
base_color = own_message ?
|
|
72
|
+
base_color = own_message ? TurboChat.configuration.own_message_hex_color : TurboChat.configuration.other_message_hex_color
|
|
73
73
|
normalize_hex_color(base_color)
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def resolve_role_message_hex_color(chat_message:, own_message:)
|
|
77
|
-
role_colors =
|
|
77
|
+
role_colors = TurboChat.configuration.role_message_hex_colors
|
|
78
78
|
return nil unless role_colors.is_a?(Hash)
|
|
79
79
|
|
|
80
80
|
role_key = chat_message_role_key(chat_message)
|
|
@@ -140,13 +140,13 @@ module ChatGem
|
|
|
140
140
|
|
|
141
141
|
def decorate_plain_message_text(body)
|
|
142
142
|
formatted = ERB::Util.html_escape(body.to_s)
|
|
143
|
-
formatted = apply_emoji_aliases(formatted) if
|
|
144
|
-
formatted = apply_mention_highlights(formatted) if
|
|
143
|
+
formatted = apply_emoji_aliases(formatted) if TurboChat.configuration.enable_emoji_aliases
|
|
144
|
+
formatted = apply_mention_highlights(formatted) if TurboChat.configuration.enable_mentions
|
|
145
145
|
formatted.gsub(/\r\n?|\n/, "<br>")
|
|
146
146
|
end
|
|
147
147
|
|
|
148
148
|
def apply_emoji_aliases(text)
|
|
149
|
-
emoji_aliases =
|
|
149
|
+
emoji_aliases = TurboChat.configuration.effective_emoji_aliases
|
|
150
150
|
return text if emoji_aliases.empty?
|
|
151
151
|
|
|
152
152
|
text.gsub(EMOJI_ALIAS_PATTERN) do |match|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
module ApplicationHelper
|
|
3
3
|
module ParticipantSupport
|
|
4
4
|
def chat_participant_name(participant)
|
|
@@ -34,7 +34,7 @@ module ChatGem
|
|
|
34
34
|
return false
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
adapter =
|
|
37
|
+
adapter = TurboChat.configuration.permission_adapter
|
|
38
38
|
return false unless adapter.respond_to?(:new)
|
|
39
39
|
|
|
40
40
|
permission = adapter.new(participant, chat_message.chat)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
module TurboChat
|
|
2
|
+
module ApplicationHelper
|
|
3
|
+
HEX_COLOR_PATTERN = /\A#(?:\h{3}|\h{6}|\h{8})\z/.freeze
|
|
4
|
+
EMOJI_ALIAS_PATTERN = /:([a-z0-9_+\-]{2,32}):/i.freeze
|
|
5
|
+
MENTION_PATTERN = /(?<![[:alnum:]_])@[[:alpha:]][[:alnum:]_]{0,31}/.freeze
|
|
6
|
+
|
|
7
|
+
include TurboChat::ApplicationHelper::ConfigSupport
|
|
8
|
+
include TurboChat::ApplicationHelper::ParticipantSupport
|
|
9
|
+
include TurboChat::ApplicationHelper::MessageRendering
|
|
10
|
+
include TurboChat::ApplicationHelper::MentionSupport
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class Chat < ApplicationRecord
|
|
3
3
|
has_many :chat_memberships,
|
|
4
|
-
class_name: "
|
|
4
|
+
class_name: "TurboChat::ChatMembership",
|
|
5
5
|
dependent: :destroy,
|
|
6
6
|
inverse_of: :chat
|
|
7
7
|
|
|
8
8
|
has_many :chat_messages,
|
|
9
|
-
class_name: "
|
|
9
|
+
class_name: "TurboChat::ChatMessage",
|
|
10
10
|
dependent: :destroy,
|
|
11
11
|
inverse_of: :chat
|
|
12
12
|
|
|
@@ -16,7 +16,7 @@ module ChatGem
|
|
|
16
16
|
return none if participant.nil?
|
|
17
17
|
|
|
18
18
|
joins(:chat_memberships)
|
|
19
|
-
.merge(
|
|
19
|
+
.merge(TurboChat::ChatMembership.active.where(participant: participant))
|
|
20
20
|
.distinct
|
|
21
21
|
}
|
|
22
22
|
scope :opened, -> { where(closed_at: nil) }
|
|
@@ -25,7 +25,7 @@ module ChatGem
|
|
|
25
25
|
scope :active, lambda { |window: nil|
|
|
26
26
|
cutoff = Time.current - activity_window_seconds(window)
|
|
27
27
|
joins(:chat_messages)
|
|
28
|
-
.merge(
|
|
28
|
+
.merge(TurboChat::ChatMessage.message.where("#{TurboChat::ChatMessage.table_name}.created_at >= ?", cutoff))
|
|
29
29
|
.distinct
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -61,7 +61,7 @@ module ChatGem
|
|
|
61
61
|
end.reverse
|
|
62
62
|
end
|
|
63
63
|
|
|
64
|
-
def visible_messages(limit:
|
|
64
|
+
def visible_messages(limit: TurboChat.configuration.message_history_limit)
|
|
65
65
|
relation = chat_messages.messages_only
|
|
66
66
|
normalized_limit = normalize_message_limit(limit)
|
|
67
67
|
limited_relation = if normalized_limit.nil?
|
|
@@ -106,7 +106,7 @@ module ChatGem
|
|
|
106
106
|
end
|
|
107
107
|
|
|
108
108
|
def self.activity_window_seconds(window = nil)
|
|
109
|
-
value = window.nil? ?
|
|
109
|
+
value = window.nil? ? TurboChat.configuration.active_chat_window : window
|
|
110
110
|
seconds = value.to_i
|
|
111
111
|
return seconds if seconds.positive?
|
|
112
112
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
module
|
|
1
|
+
module TurboChat
|
|
2
2
|
class ChatMembership < ApplicationRecord
|
|
3
|
-
belongs_to :chat, class_name: "
|
|
3
|
+
belongs_to :chat, class_name: "TurboChat::Chat", inverse_of: :chat_memberships
|
|
4
4
|
belongs_to :participant, polymorphic: true
|
|
5
5
|
|
|
6
6
|
enum :role, { member: 0, moderator: 1, admin: 2 }, default: :member
|
|
@@ -74,7 +74,7 @@ module ChatGem
|
|
|
74
74
|
end
|
|
75
75
|
|
|
76
76
|
def effective_role_definition
|
|
77
|
-
|
|
77
|
+
TurboChat.configuration.role_definition(effective_role_key)
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def effective_role_name
|
|
@@ -109,7 +109,7 @@ module ChatGem
|
|
|
109
109
|
end
|
|
110
110
|
|
|
111
111
|
def custom_role_must_exist
|
|
112
|
-
return if
|
|
112
|
+
return if TurboChat.configuration.role_definition(custom_role_key).present?
|
|
113
113
|
|
|
114
114
|
errors.add(:custom_role_key, "is not configured")
|
|
115
115
|
end
|
|
@@ -121,7 +121,7 @@ module ChatGem
|
|
|
121
121
|
def enforce_chat_participant_limit
|
|
122
122
|
return if chat.nil?
|
|
123
123
|
|
|
124
|
-
limit =
|
|
124
|
+
limit = TurboChat.configuration.max_chat_participants
|
|
125
125
|
return if limit.nil?
|
|
126
126
|
|
|
127
127
|
limit = limit.to_i
|