lesli 5.1.12 → 5.1.13
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/Rakefile +3 -0
- data/app/assets/stylesheets/lesli/application.css +43 -3
- data/app/controllers/lesli/application_devise_controller.rb +9 -5
- data/app/controllers/lesli/application_lesli_controller.rb +4 -0
- data/app/controllers/lesli/items/attachments_controller.rb +200 -0
- data/app/controllers/lesli/items/discussions_controller.rb +94 -67
- data/app/controllers/lesli/items/tasks_controller.rb +132 -62
- data/app/helpers/lesli/turbo_helper.rb +0 -18
- data/app/interfaces/lesli/responder_interface.rb +58 -38
- data/app/mailers/lesli/application_lesli_mailer.rb +34 -8
- data/app/models/concerns/lesli/account_initializer.rb +11 -3
- data/app/models/concerns/lesli/account_logs.rb +5 -16
- data/app/models/concerns/lesli/items/activities.rb +29 -33
- data/app/models/concerns/lesli/items/attachments.rb +88 -0
- data/app/models/concerns/lesli/items/discussions.rb +25 -11
- data/app/models/concerns/lesli/items/ownership.rb +27 -0
- data/app/models/concerns/lesli/items/tasks.rb +26 -6
- data/app/models/concerns/lesli/user_extensions.rb +5 -9
- data/app/models/lesli/account.rb +10 -14
- data/app/models/lesli/items/activity.rb +25 -2
- data/app/models/lesli/items/attachment.rb +117 -0
- data/app/models/lesli/items/discussion.rb +6 -2
- data/app/models/lesli/items/task.rb +3 -1
- data/app/models/lesli/user.rb +12 -21
- data/app/views/lesli/abouts/welcome.html.erb +2 -5
- data/app/views/lesli/errors/not_found.html.erb +7 -21
- data/app/views/lesli/errors/unauthorized.html.erb +11 -27
- data/app/views/lesli/layouts/application-devise.html.erb +10 -9
- data/app/views/lesli/layouts/application-lesli.html.erb +1 -1
- data/app/views/lesli/partials/_application-lesli-assets.html.erb +3 -3
- data/app/views/lesli/partials/_application-lesli-header.html.erb +5 -9
- data/config/initializers/lesli.rb +4 -1
- data/config/locales/translations.en.yml +34 -0
- data/config/locales/translations.es.yml +34 -0
- data/db/seed/accounts.rb +5 -5
- data/db/seed/users.rb +8 -16
- data/db/seed/xyz.rb +38 -17
- data/lib/lesli/engine.rb +0 -4
- data/lib/lesli/router.rb +5 -2
- data/lib/lesli/version.rb +2 -2
- data/lib/migrate/items/activity_structure.rb +8 -8
- data/lib/migrate/items/attachment_structure.rb +9 -14
- data/lib/migrate/items/discussion_structure.rb +5 -5
- data/lib/migrate/items/task_structure.rb +2 -3
- data/lib/migrate/shared/account_structure.rb +1 -1
- data/lib/tasks/lesli_tasks.rake +2 -3
- data/readme.md +3 -3
- data/test/fixtures/lesli_accounts.yml +18 -0
- data/test/fixtures/lesli_users.yml +23 -0
- metadata +17 -25
- data/app/assets/stylesheets/lesli/application.tailwind.css +0 -33
- data/config/brakeman.yml +0 -44
- data/config/initializers/devise.rb +0 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e42093c64425af9e68a26e106d438eee2e69c11ead091011ad26eff30b940282
|
|
4
|
+
data.tar.gz: 5e56a9246828d3efe4e36354d7fe754a4556af9a0befd4ea9a6169614b94b521
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a7f90e00184b49ffac1f366897ae89ddbd0dbe6e488aa4952d018f432a6e73f2399f9c8fd3f9b670dbb6d1bff2b6a1660f73a79eb146f5fb08ceed7e5efb2a5b
|
|
7
|
+
data.tar.gz: 69a092763f5a8e0c55c03bd7d68aa68b511cc8a5f6bd60aedfdef9fbc601501319f12555f3c95d908e354292d3285d3289c91c01e803d72ed09669775b2f7446
|
data/Rakefile
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/*! tailwindcss v4.3.3 | MIT License | https://tailwindcss.com */
|
|
2
|
+
/*!
|
|
3
|
+
|
|
3
4
|
Lesli
|
|
4
5
|
|
|
5
|
-
Copyright (c)
|
|
6
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
7
|
|
|
7
8
|
This program is free software: you can redistribute it and/or modify
|
|
8
9
|
it under the terms of the GNU General Public License as published by
|
|
@@ -29,3 +30,42 @@ Building a better future, one line of code at a time.
|
|
|
29
30
|
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
30
31
|
// ·
|
|
31
32
|
*/
|
|
33
|
+
@layer theme, utilities;
|
|
34
|
+
@layer theme {
|
|
35
|
+
:root, :host {
|
|
36
|
+
--spacing: 0.25rem;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
@layer utilities {
|
|
40
|
+
.grid {
|
|
41
|
+
display: grid;
|
|
42
|
+
}
|
|
43
|
+
.hidden {
|
|
44
|
+
display: none;
|
|
45
|
+
}
|
|
46
|
+
.grid-cols-1 {
|
|
47
|
+
grid-template-columns: repeat(1, minmax(0, 1fr));
|
|
48
|
+
}
|
|
49
|
+
.gap-5 {
|
|
50
|
+
gap: calc(var(--spacing) * 5);
|
|
51
|
+
}
|
|
52
|
+
.py-6 {
|
|
53
|
+
padding-block: calc(var(--spacing) * 6);
|
|
54
|
+
}
|
|
55
|
+
@media (width >= 40rem) {
|
|
56
|
+
.sm\:grid-cols-2 {
|
|
57
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
58
|
+
}
|
|
59
|
+
.sm\:gap-6 {
|
|
60
|
+
gap: calc(var(--spacing) * 6);
|
|
61
|
+
}
|
|
62
|
+
.sm\:py-8 {
|
|
63
|
+
padding-block: calc(var(--spacing) * 8);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
@media (width >= 64rem) {
|
|
67
|
+
.lg\:grid-cols-4 {
|
|
68
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
@@ -1,8 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
=begin
|
|
2
4
|
|
|
3
5
|
Lesli
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
Lesli
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
10
|
|
|
7
11
|
This program is free software: you can redistribute it and/or modify
|
|
8
12
|
it under the terms of the GNU General Public License as published by
|
|
@@ -31,17 +35,17 @@ Building a better future, one line of code at a time.
|
|
|
31
35
|
=end
|
|
32
36
|
|
|
33
37
|
module Lesli
|
|
38
|
+
# Shared parent for authentication controllers rendered with the public
|
|
39
|
+
# Lesli application shell. LesliShield configures Devise to use this class.
|
|
34
40
|
class ApplicationDeviseController < ApplicationController
|
|
35
41
|
include Lesli::ResponderInterface
|
|
36
42
|
include Lesli::RequesterInterface
|
|
37
43
|
include LesliAudit::LoggerInterface if defined?(LesliAudit)
|
|
38
|
-
|
|
39
|
-
layout "lesli/layouts/application-devise"
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
layout "lesli/layouts/application-devise"
|
|
42
46
|
|
|
43
47
|
def initialize
|
|
44
|
-
@lesli = {
|
|
48
|
+
@lesli = {
|
|
45
49
|
company: {
|
|
46
50
|
name: Lesli.config.company[:name]
|
|
47
51
|
}
|
|
@@ -40,6 +40,10 @@ module Lesli
|
|
|
40
40
|
include LesliShield::AuthenticationInterface if defined?(LesliShield)
|
|
41
41
|
include LesliShield::AuthorizationInterface if defined?(LesliShield)
|
|
42
42
|
|
|
43
|
+
# Controllers from isolated engines inherit this controller, but Rails
|
|
44
|
+
# does not automatically expose Lesli's helpers to their views.
|
|
45
|
+
helper Lesli::Engine.helpers
|
|
46
|
+
|
|
43
47
|
protect_from_forgery with: :exception
|
|
44
48
|
|
|
45
49
|
before_action :set_locale
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
=begin
|
|
2
|
+
|
|
3
|
+
Lesli
|
|
4
|
+
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
|
+
|
|
7
|
+
This program is free software: you can redistribute it and/or modify
|
|
8
|
+
it under the terms of the GNU General Public License as published by
|
|
9
|
+
the Free Software Foundation, either version 3 of the License, or
|
|
10
|
+
(at your option) any later version.
|
|
11
|
+
|
|
12
|
+
This program is distributed in the hope that it will be useful,
|
|
13
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
14
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
15
|
+
GNU General Public License for more details.
|
|
16
|
+
|
|
17
|
+
You should have received a copy of the GNU General Public License
|
|
18
|
+
along with this program. If not, see http://www.gnu.org/licenses/.
|
|
19
|
+
|
|
20
|
+
Lesli · Ruby on Rails SaaS Development Framework.
|
|
21
|
+
|
|
22
|
+
Made with ♥ by LesliTech
|
|
23
|
+
Building a better future, one line of code at a time.
|
|
24
|
+
|
|
25
|
+
@contact hello@lesli.tech
|
|
26
|
+
@website https://www.lesli.tech
|
|
27
|
+
@license GPLv3 http://www.gnu.org/licenses/gpl-3.0.en.html
|
|
28
|
+
|
|
29
|
+
// · ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~ ~·~
|
|
30
|
+
// ·
|
|
31
|
+
=end
|
|
32
|
+
|
|
33
|
+
module Lesli
|
|
34
|
+
module Items
|
|
35
|
+
class AttachmentsController < ApplicationLesliController
|
|
36
|
+
include ActiveStorage::SetCurrent
|
|
37
|
+
|
|
38
|
+
before_action :set_attachable, only: %i[index create]
|
|
39
|
+
before_action :set_attachment, only: %i[show destroy]
|
|
40
|
+
|
|
41
|
+
def index
|
|
42
|
+
attachments = @attachable.attachments.with_attached_file
|
|
43
|
+
respond_with_lesli(json: attachments.map { |attachment| attachment_payload(attachment) })
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def show
|
|
47
|
+
return respond_with_not_found unless @attachment.file.attached?
|
|
48
|
+
|
|
49
|
+
redirect_to(
|
|
50
|
+
@attachment.file.url(
|
|
51
|
+
expires_in: 5.minutes,
|
|
52
|
+
disposition: :attachment,
|
|
53
|
+
filename: @attachment.file.filename
|
|
54
|
+
),
|
|
55
|
+
allow_other_host: true
|
|
56
|
+
)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def create
|
|
60
|
+
attachment = @attachable.attachments.build(attachment_params)
|
|
61
|
+
attachment.user = current_user
|
|
62
|
+
attachment.account = @attachable.lesli_item_account
|
|
63
|
+
|
|
64
|
+
if attachment.save
|
|
65
|
+
refresh_attachments
|
|
66
|
+
respond_with_lesli(
|
|
67
|
+
turbo: [
|
|
68
|
+
stream_notification_success(
|
|
69
|
+
I18n.t("lesli.items.attachments.created")
|
|
70
|
+
),
|
|
71
|
+
attachments_stream
|
|
72
|
+
],
|
|
73
|
+
json: attachment_payload(attachment),
|
|
74
|
+
redirect: return_path
|
|
75
|
+
)
|
|
76
|
+
else
|
|
77
|
+
respond_with_lesli(
|
|
78
|
+
turbo: [
|
|
79
|
+
stream_notification_danger(
|
|
80
|
+
attachment.errors.full_messages.to_sentence
|
|
81
|
+
),
|
|
82
|
+
attachments_stream(attachment: attachment)
|
|
83
|
+
],
|
|
84
|
+
json: { errors: attachment.errors },
|
|
85
|
+
redirect: return_path,
|
|
86
|
+
status: :unprocessable_content
|
|
87
|
+
)
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def destroy
|
|
92
|
+
attachable = @attachment.attachable
|
|
93
|
+
|
|
94
|
+
if @attachment.destroy
|
|
95
|
+
@attachable = attachable
|
|
96
|
+
refresh_attachments
|
|
97
|
+
respond_with_lesli(
|
|
98
|
+
turbo: [
|
|
99
|
+
stream_notification_success(
|
|
100
|
+
I18n.t("lesli.items.attachments.deleted")
|
|
101
|
+
),
|
|
102
|
+
attachments_stream
|
|
103
|
+
],
|
|
104
|
+
json: { message: I18n.t("lesli.items.attachments.deleted") },
|
|
105
|
+
redirect: return_path
|
|
106
|
+
)
|
|
107
|
+
else
|
|
108
|
+
respond_with_lesli(
|
|
109
|
+
turbo: stream_notification_danger(
|
|
110
|
+
@attachment.errors.full_messages.to_sentence
|
|
111
|
+
),
|
|
112
|
+
json: { errors: @attachment.errors },
|
|
113
|
+
redirect: return_path,
|
|
114
|
+
status: :unprocessable_content
|
|
115
|
+
)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
private
|
|
120
|
+
|
|
121
|
+
def attachment_class
|
|
122
|
+
self.class.module_parent.const_get("Attachment")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def attachable_class
|
|
126
|
+
allowed_attachable_classes.find do |klass|
|
|
127
|
+
klass.name == params.require(:attachable_type)
|
|
128
|
+
end || raise(
|
|
129
|
+
ActiveRecord::RecordNotFound,
|
|
130
|
+
"Unauthorized attachable type"
|
|
131
|
+
)
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def allowed_attachable_classes
|
|
135
|
+
[]
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def set_attachable
|
|
139
|
+
@attachable = attachable_class.find(params.require(:attachable_id))
|
|
140
|
+
ensure_attachable_access!(@attachable)
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def set_attachment
|
|
144
|
+
@attachment = attachment_class
|
|
145
|
+
.with_attached_file
|
|
146
|
+
.find(params[:id])
|
|
147
|
+
ensure_attachable_access!(@attachment.attachable)
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def ensure_attachable_access!(attachable)
|
|
151
|
+
allowed = attachable.respond_to?(:lesli_item_accessible_by?) &&
|
|
152
|
+
attachable.lesli_item_accessible_by?(current_user)
|
|
153
|
+
|
|
154
|
+
raise ActiveRecord::RecordNotFound unless allowed
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def attachment_params
|
|
158
|
+
params.require(scope_key).permit(:file, :label, :category)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def scope_key
|
|
162
|
+
ActiveSupport::Inflector.underscore(attachment_class.name).tr("/", "_")
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
def attachment_payload(attachment)
|
|
166
|
+
{
|
|
167
|
+
id: attachment.id,
|
|
168
|
+
label: attachment.label,
|
|
169
|
+
category: attachment.category,
|
|
170
|
+
filename: attachment.file.filename.to_s,
|
|
171
|
+
content_type: attachment.file.blob.content_type,
|
|
172
|
+
byte_size: attachment.file.blob.byte_size,
|
|
173
|
+
created_at: attachment.created_at,
|
|
174
|
+
user: {
|
|
175
|
+
id: attachment.user_id,
|
|
176
|
+
name: attachment.user.name
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
def attachments_stream(attachment: nil)
|
|
182
|
+
turbo_stream.replace(
|
|
183
|
+
helpers.dom_id(@attachable, :attachments)
|
|
184
|
+
) do
|
|
185
|
+
LesliView::Items::Attachments
|
|
186
|
+
.new(@attachable, attachment: attachment)
|
|
187
|
+
.render_in(view_context)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def refresh_attachments
|
|
192
|
+
@attachable.attachments.reset
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
def return_path
|
|
196
|
+
request.referer.presence || root_path
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
end
|
|
@@ -33,93 +33,120 @@ Building a better future, one line of code at a time.
|
|
|
33
33
|
module Lesli
|
|
34
34
|
module Items
|
|
35
35
|
class DiscussionsController < ApplicationLesliController
|
|
36
|
-
before_action :
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
36
|
+
before_action :set_discussable, only: :create
|
|
37
|
+
|
|
38
|
+
def create
|
|
39
|
+
comment = @discussable.add_comment!(
|
|
40
|
+
author: current_user,
|
|
41
|
+
message: discussion_params[:message]
|
|
42
|
+
)
|
|
43
|
+
refresh_discussions
|
|
44
|
+
|
|
45
|
+
message = I18n.t("lesli.items.discussions.created")
|
|
46
|
+
respond_with_lesli(
|
|
47
|
+
turbo: [
|
|
48
|
+
stream_notification_success(message),
|
|
49
|
+
discussions_stream
|
|
50
|
+
],
|
|
51
|
+
json: {
|
|
52
|
+
message: message,
|
|
53
|
+
comment: comment_payload(comment)
|
|
54
|
+
},
|
|
55
|
+
status: :created
|
|
56
|
+
)
|
|
57
|
+
rescue ActiveRecord::RecordInvalid => error
|
|
58
|
+
respond_with_comment_errors(error.record)
|
|
44
59
|
end
|
|
45
60
|
|
|
46
|
-
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def discussable_class
|
|
64
|
+
allowed_discussable_classes.find do |klass|
|
|
65
|
+
klass.name == params.require(:discussable_type)
|
|
66
|
+
end || raise(
|
|
67
|
+
ActiveRecord::RecordNotFound,
|
|
68
|
+
"Unauthorized discussable type"
|
|
69
|
+
)
|
|
47
70
|
end
|
|
48
71
|
|
|
49
|
-
def
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
discussion.user = current_user
|
|
53
|
-
discussion.account = current_user.account
|
|
54
|
-
discussion.discussable = @discussable if @discussable
|
|
55
|
-
|
|
56
|
-
if discussion.save
|
|
57
|
-
respond_with_lesli(:turbo => [
|
|
58
|
-
stream_notification_success("Discussion created"),
|
|
59
|
-
turbo_stream.prepend("#{scope_key}-lesli-items-discussions-list") do
|
|
60
|
-
LesliView::Items::Discussion.new(discussion).render_in(view_context)
|
|
61
|
-
end
|
|
62
|
-
])
|
|
63
|
-
else
|
|
64
|
-
respond_with_lesli(
|
|
65
|
-
:turbo => stream_notification_danger(discussion.errors.full_messages)
|
|
66
|
-
)
|
|
67
|
-
end
|
|
72
|
+
def allowed_discussable_classes
|
|
73
|
+
[]
|
|
68
74
|
end
|
|
69
75
|
|
|
70
|
-
def
|
|
71
|
-
@
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
turbo_stream.replace(helpers.dom_id(@discussion, scope_key)) do
|
|
76
|
-
LesliView::Items::Discussion.new(@discussion, scope_key).render_in(view_context)
|
|
77
|
-
end
|
|
78
|
-
])
|
|
76
|
+
def set_discussable
|
|
77
|
+
@discussable = discussable_class.find(
|
|
78
|
+
params.require(:discussable_id)
|
|
79
|
+
)
|
|
80
|
+
ensure_discussable_access!(@discussable)
|
|
79
81
|
end
|
|
80
82
|
|
|
81
|
-
|
|
83
|
+
def ensure_discussable_access!(discussable)
|
|
84
|
+
allowed = discussable.respond_to?(:lesli_item_accessible_by?) &&
|
|
85
|
+
discussable.lesli_item_accessible_by?(current_user)
|
|
82
86
|
|
|
83
|
-
|
|
84
|
-
|
|
87
|
+
raise ActiveRecord::RecordNotFound unless allowed
|
|
88
|
+
end
|
|
85
89
|
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
def discussion_class
|
|
91
|
+
@discussable.class.lesli_discussions_class
|
|
92
|
+
end
|
|
88
93
|
|
|
89
|
-
|
|
90
|
-
|
|
94
|
+
def scope_key
|
|
95
|
+
ActiveSupport::Inflector
|
|
96
|
+
.underscore(discussion_class.name)
|
|
97
|
+
.tr("/", "_")
|
|
98
|
+
end
|
|
91
99
|
|
|
92
|
-
|
|
93
|
-
|
|
100
|
+
def discussion_params
|
|
101
|
+
params.require(scope_key.to_sym).permit(:message)
|
|
102
|
+
end
|
|
94
103
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
render json: { error: "Unauthorized discussable type" }, status: :forbidden and return
|
|
99
|
-
end
|
|
104
|
+
def refresh_discussions
|
|
105
|
+
association_name =
|
|
106
|
+
@discussable.class.lesli_discussions_association_name
|
|
100
107
|
|
|
101
|
-
|
|
108
|
+
@discussable.public_send(association_name).reset
|
|
102
109
|
end
|
|
103
110
|
|
|
104
|
-
def
|
|
105
|
-
|
|
111
|
+
def discussions_stream(comment: nil)
|
|
112
|
+
turbo_stream.replace(
|
|
113
|
+
helpers.dom_id(@discussable, :discussions)
|
|
114
|
+
) do
|
|
115
|
+
LesliView::Items::Discussions
|
|
116
|
+
.new(@discussable, comment: comment)
|
|
117
|
+
.render_in(view_context)
|
|
118
|
+
end
|
|
106
119
|
end
|
|
107
120
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
121
|
+
def comment_payload(comment)
|
|
122
|
+
{
|
|
123
|
+
id: comment.id,
|
|
124
|
+
message: comment.message,
|
|
125
|
+
discussable_type: comment.discussable_type,
|
|
126
|
+
discussable_id: comment.discussable_id,
|
|
127
|
+
author: {
|
|
128
|
+
id: comment.user_id,
|
|
129
|
+
name: comment.author.name
|
|
130
|
+
},
|
|
131
|
+
created_at: comment.created_at,
|
|
132
|
+
updated_at: comment.updated_at
|
|
133
|
+
}
|
|
119
134
|
end
|
|
120
135
|
|
|
121
|
-
def
|
|
122
|
-
|
|
136
|
+
def respond_with_comment_errors(comment)
|
|
137
|
+
refresh_discussions
|
|
138
|
+
message = I18n.t("lesli.items.discussions.invalid")
|
|
139
|
+
respond_with_lesli(
|
|
140
|
+
turbo: [
|
|
141
|
+
stream_notification_danger(message),
|
|
142
|
+
discussions_stream(comment: comment)
|
|
143
|
+
],
|
|
144
|
+
json: {
|
|
145
|
+
message: message,
|
|
146
|
+
errors: comment.errors
|
|
147
|
+
},
|
|
148
|
+
status: :unprocessable_content
|
|
149
|
+
)
|
|
123
150
|
end
|
|
124
151
|
end
|
|
125
152
|
end
|