lesli 5.0.23 → 5.0.24
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/app/controllers/lesli/abouts_controller.rb +1 -1
- data/app/controllers/lesli/{items → item}/activities_controller.rb +1 -1
- data/app/controllers/lesli/item/discussions_controller.rb +126 -0
- data/app/controllers/lesli/item/tasks_controller.rb +126 -0
- data/app/models/concerns/lesli/item/activities.rb +106 -0
- data/app/models/concerns/lesli/item/discussions.rb +92 -0
- data/app/models/concerns/lesli/item/tasks.rb +95 -0
- data/app/models/lesli/account.rb +1 -0
- data/app/models/lesli/{items → item}/activity.rb +5 -13
- data/app/models/lesli/item/discussion.rb +10 -0
- data/{lib/tasks/lesli/docs.rake → app/models/lesli/item/task.rb} +9 -14
- data/app/views/lesli/partials/_application-lesli-header.html.erb +12 -0
- data/config/initializers/lesli_migration_helpers.rb +2 -2
- data/db/migrate/v1/0000000210_create_lesli_users.rb +1 -1
- data/lib/generators/lesli/install/install_generator.rb +1 -1
- data/lib/lesli/engine.rb +1 -1
- data/lib/lesli/router.rb +42 -43
- data/lib/lesli/version.rb +2 -2
- data/lib/migrate/common.rb +1 -1
- data/lib/migrate/items/activity_structure.rb +11 -5
- data/lib/migrate/items/discussion_structure.rb +9 -3
- data/lib/migrate/items/{action_structure.rb → task_structure.rb} +12 -6
- data/lib/migrate/shared/catalog_structure.rb +16 -0
- data/lib/tasks/lesli/db.rake +9 -0
- data/readme.md +1 -1
- metadata +15 -30
- data/app/controllers/lesli/items/actions_controller.rb +0 -122
- data/app/controllers/lesli/items/discussions_controller.rb +0 -93
- data/app/models/lesli/items/action.rb +0 -15
- data/app/models/lesli/items/discussion.rb +0 -15
- data/db/structure/00000000_locations.json +0 -32
- data/db/structure/00000020_catalogs.json +0 -0
- data/db/structure/00000201_workflows.json +0 -17
- data/db/structure/00000202_workflow_statuses.json +0 -24
- data/db/structure/00000203_workflow_associations.json +0 -14
- data/db/structure/00000204_workflow_actions.json +0 -39
- data/db/structure/00000205_workflow_checks.json +0 -27
- data/db/structure/00000300_custom_fields.json +0 -8
- data/db/structure/00000301_custom_fields.json +0 -38
- data/db/structure/00000401_custom_validations.json +0 -14
- data/db/structure/00000402_custom_validation_rules.json +0 -23
- data/db/structure/00000403_custom_validation_fields.json +0 -14
- data/lib/tasks/lesli/git.rake +0 -70
- data/lib/tasks/lesli/github.rake +0 -89
- data/lib/test/config.rb +0 -111
- data/lib/test/helpers/response_integration_helper.rb +0 -46
- data/lib/test/lesli.rb +0 -61
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a56fbd90769c845789e9fc2097da330344938d31db26be4da238adae6e18ded8
|
|
4
|
+
data.tar.gz: 840585ccd69d395bde16bbd9b41e4b33e4cd41343e09f35b12fe7f5452e6b513
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 20d6570450c48ca8c79132403144d12c7a718dd6b91c03e346899badeacad0d2627543f0f5b5dd98274edbb600b6073c2147ac27ef09a694acd0a3d257466a19
|
|
7
|
+
data.tar.gz: 6ab41da8a99d0b615071dedce1a4f020be93d4ffe85de5ae48a6fd5538182cec1194ff38b2daa79a16d901441463f5e376e67c403baf4a1e09509e1a3539c09c
|
|
@@ -50,7 +50,7 @@ module Lesli
|
|
|
50
50
|
respond_to do |format|
|
|
51
51
|
format.html {}
|
|
52
52
|
format.json do
|
|
53
|
-
lesli_engines = LesliSystem.engines.map do |engine, engine_info|
|
|
53
|
+
lesli_engines = ::LesliSystem.engines.map do |engine, engine_info|
|
|
54
54
|
{
|
|
55
55
|
:name => engine_info[:name],
|
|
56
56
|
:code => engine_info[:code],
|
|
@@ -0,0 +1,126 @@
|
|
|
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 Item
|
|
35
|
+
class DiscussionsController < ApplicationLesliController
|
|
36
|
+
before_action :set_discussion, only: %i[show update]
|
|
37
|
+
before_action :set_discussable, only: %i[index create]
|
|
38
|
+
|
|
39
|
+
def index
|
|
40
|
+
@discussions = discussion_class
|
|
41
|
+
.where(account: current_user.account)
|
|
42
|
+
.order(created_at: :desc)
|
|
43
|
+
respond_with_lesli(json: @discussions)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def show
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create
|
|
50
|
+
discussion = discussion_class.new(discussion_params)
|
|
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::Item::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
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def update
|
|
71
|
+
@discussion.done = true
|
|
72
|
+
@discussion.save
|
|
73
|
+
respond_with_lesli(:turbo => [
|
|
74
|
+
stream_notification_success("Discussion updated #{@discussable}"),
|
|
75
|
+
turbo_stream.replace(helpers.dom_id(@discussion, scope_key)) do
|
|
76
|
+
LesliView::Item::Discussion.new(@discussion, scope_key).render_in(view_context)
|
|
77
|
+
end
|
|
78
|
+
])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
# return a key to identify the engine where the tasks are running
|
|
84
|
+
def scope_key = ActiveSupport::Inflector.underscore(discussion_class.name).tr("/", "_")
|
|
85
|
+
|
|
86
|
+
# return the discussion class including the engine where the tasks are running
|
|
87
|
+
def discussion_class = self.class.module_parent.const_get("Discussion")
|
|
88
|
+
|
|
89
|
+
# validate we invoke only models that implements Lesli::Item::Discussions concern
|
|
90
|
+
def validate_discussable discussable
|
|
91
|
+
|
|
92
|
+
# 1. Attempt to resolve the class safely
|
|
93
|
+
klass = discussable.safe_constantize
|
|
94
|
+
|
|
95
|
+
# 2. VALIDATION: Check if the class is allowed to be discussable
|
|
96
|
+
# We check if the class exists AND if it includes your specific discussable trait
|
|
97
|
+
unless klass && klass.respond_to?(:is_lesli_taskable?) && klass.is_lesli_commentable?
|
|
98
|
+
render json: { error: "Unauthorized discussable type" }, status: :forbidden and return
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
klass
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def set_discussion
|
|
105
|
+
@discussion = discussion_class.where(account: current_user.account).find(params[:id])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Permite filtrar/crear para un actionable específico:
|
|
109
|
+
# params: actionable_type=LesliSupport::Ticket&actionable_id=123
|
|
110
|
+
def set_discussable
|
|
111
|
+
type = params[:discussable_type].presence
|
|
112
|
+
id = params[:discussable_id].presence
|
|
113
|
+
return if type.blank? || id.blank?
|
|
114
|
+
|
|
115
|
+
discussable = validate_discussable(type)
|
|
116
|
+
|
|
117
|
+
# 3. Execution: Now it is safe to query
|
|
118
|
+
@discussable = discussable.where(account: current_user.account).find_by(id: id)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def discussion_params
|
|
122
|
+
params.require(scope_key.to_sym).permit(:message)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,126 @@
|
|
|
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 Item
|
|
35
|
+
class TasksController < ApplicationLesliController
|
|
36
|
+
before_action :set_task, only: %i[show update]
|
|
37
|
+
before_action :set_taskable, only: %i[index create]
|
|
38
|
+
|
|
39
|
+
def index
|
|
40
|
+
@tasks = task_class
|
|
41
|
+
.where(account: current_user.account)
|
|
42
|
+
.order(created_at: :desc)
|
|
43
|
+
respond_with_lesli(json: @tasks)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def show
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def create
|
|
50
|
+
task = task_class.new(task_params)
|
|
51
|
+
|
|
52
|
+
task.user = current_user
|
|
53
|
+
task.account = current_user.account
|
|
54
|
+
task.taskable = @taskable if @taskable
|
|
55
|
+
|
|
56
|
+
if task.save
|
|
57
|
+
respond_with_lesli(:turbo => [
|
|
58
|
+
stream_notification_success("Task created"),
|
|
59
|
+
turbo_stream.prepend("#{scope_key}-lesli-items-tasks-list") do
|
|
60
|
+
LesliView::Item::Task.new(task, scope_key).render_in(view_context)
|
|
61
|
+
end
|
|
62
|
+
])
|
|
63
|
+
else
|
|
64
|
+
respond_with_lesli(
|
|
65
|
+
:turbo => stream_notification_danger(task.errors.full_messages)
|
|
66
|
+
)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def update
|
|
71
|
+
@task.done = true
|
|
72
|
+
@task.save
|
|
73
|
+
respond_with_lesli(:turbo => [
|
|
74
|
+
stream_notification_success("Task updated #{@taskable}"),
|
|
75
|
+
turbo_stream.replace(helpers.dom_id(@task, scope_key)) do
|
|
76
|
+
LesliView::Item::Task.new(@task, scope_key).render_in(view_context)
|
|
77
|
+
end
|
|
78
|
+
])
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
private
|
|
82
|
+
|
|
83
|
+
# return a key to identify the engine where the tasks are running
|
|
84
|
+
def scope_key = ActiveSupport::Inflector.underscore(task_class.name).tr("/", "_")
|
|
85
|
+
|
|
86
|
+
# return the task class including the engine where the tasks are running
|
|
87
|
+
def task_class = self.class.module_parent.const_get("Task")
|
|
88
|
+
|
|
89
|
+
# validate we invoke only models that implements Lesli::Item::Tasks concern
|
|
90
|
+
def validate_taskable taskable
|
|
91
|
+
|
|
92
|
+
# 1. Attempt to resolve the class safely
|
|
93
|
+
klass = taskable.safe_constantize
|
|
94
|
+
|
|
95
|
+
# 2. VALIDATION: Check if the class is allowed to be taskable
|
|
96
|
+
# We check if the class exists AND if it includes your specific taskable trait
|
|
97
|
+
unless klass && klass.respond_to?(:is_lesli_taskable?) && klass.is_lesli_taskable?
|
|
98
|
+
render json: { error: "Unauthorized taskable type" }, status: :forbidden and return
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
klass
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def set_task
|
|
105
|
+
@task = task_class.where(account: current_user.account).find(params[:id])
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Permite filtrar/crear para un actionable específico:
|
|
109
|
+
# params: actionable_type=LesliSupport::Ticket&actionable_id=123
|
|
110
|
+
def set_taskable
|
|
111
|
+
type = params[:taskable_type].presence
|
|
112
|
+
id = params[:taskable_id].presence
|
|
113
|
+
return if type.blank? || id.blank?
|
|
114
|
+
|
|
115
|
+
taskable = validate_taskable(type)
|
|
116
|
+
|
|
117
|
+
# 3. Execution: Now it is safe to query
|
|
118
|
+
@taskable = taskable.where(account: current_user.account).find_by(id: id)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def task_params
|
|
122
|
+
params.require(scope_key.to_sym).permit(:title)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
@@ -0,0 +1,106 @@
|
|
|
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 Item
|
|
35
|
+
module Activities
|
|
36
|
+
extend ActiveSupport::Concern
|
|
37
|
+
|
|
38
|
+
included do
|
|
39
|
+
class_attribute :lesli_activities_class, instance_accessor: false
|
|
40
|
+
lesli_activities_setup
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class_methods do
|
|
44
|
+
|
|
45
|
+
# Automatically sets the associations to the
|
|
46
|
+
# engine model that is implementing the task items
|
|
47
|
+
def lesli_activities_setup(use: nil, as: :subject, association_name: :activities)
|
|
48
|
+
klass = if use
|
|
49
|
+
use.to_s.constantize
|
|
50
|
+
else
|
|
51
|
+
"#{name.deconstantize}::Item::Activity".constantize
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
self.lesli_activities_class = klass
|
|
55
|
+
|
|
56
|
+
# ✅ Auto-fix table name (works even when engine defines table_name_prefix)
|
|
57
|
+
expected_table = lesli_expected_activity_table_name_for(klass)
|
|
58
|
+
|
|
59
|
+
if klass.table_name != expected_table
|
|
60
|
+
klass.table_name = expected_table
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Set associations
|
|
64
|
+
# Example:
|
|
65
|
+
# class LesliSupport::Ticket
|
|
66
|
+
# has_many :activities, class_name: "LesliSupport::Items::Activity"
|
|
67
|
+
# end
|
|
68
|
+
has_many(association_name,
|
|
69
|
+
-> { where(deleted_at: nil).order(created_at: :desc) },
|
|
70
|
+
as: as,
|
|
71
|
+
class_name: klass.name,
|
|
72
|
+
dependent: :destroy
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
# rescue NameError
|
|
76
|
+
# raise NameError,
|
|
77
|
+
# "Task class not found for #{name}. Expected #{name.deconstantize}::Activity or pass `use:`"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
# Build: "lesli_support_item_activities" from "LesliSupport::Item::Activity"
|
|
83
|
+
#
|
|
84
|
+
# We DO NOT rely on ActiveRecord's table_name_prefix, because that’s what breaks your case.
|
|
85
|
+
def lesli_expected_activity_table_name_for(klass)
|
|
86
|
+
parts = klass.name.split("::").map(&:underscore) # ["lesli_support", "item", "activity"]
|
|
87
|
+
"#{parts.join('_').pluralize}" # "lesli_support_item_activities"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def after_save_activities
|
|
92
|
+
L2.warn "You need to define your activity methods in your model"
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def activities_create **resource
|
|
96
|
+
self.activities.create(
|
|
97
|
+
subject_type: self.class.name,
|
|
98
|
+
subject_id: self.id,
|
|
99
|
+
user_id:self.user_id,
|
|
100
|
+
account_id:self.account_id,
|
|
101
|
+
**resource
|
|
102
|
+
)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,92 @@
|
|
|
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 Item
|
|
35
|
+
module Discussions
|
|
36
|
+
extend ActiveSupport::Concern
|
|
37
|
+
|
|
38
|
+
included do
|
|
39
|
+
class_attribute :lesli_discussions_class, instance_accessor: false
|
|
40
|
+
lesli_discussions_setup
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class_methods do
|
|
44
|
+
|
|
45
|
+
# This acts as our allowlist flag
|
|
46
|
+
def is_lesli_commentable?
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Automatically sets the associations to the
|
|
51
|
+
# engine model that is implementing the task items
|
|
52
|
+
def lesli_discussions_setup(use: nil, as: :discussable, association_name: :discussions)
|
|
53
|
+
klass = if use
|
|
54
|
+
use.to_s.constantize
|
|
55
|
+
else
|
|
56
|
+
"#{name.deconstantize}::Item::Discussion".constantize
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
self.lesli_discussions_class = klass
|
|
60
|
+
|
|
61
|
+
# ✅ Auto-fix table name (works even when engine defines table_name_prefix)
|
|
62
|
+
expected_table = lesli_expected_discussions_table_name_for(klass)
|
|
63
|
+
|
|
64
|
+
if klass.table_name != expected_table
|
|
65
|
+
klass.table_name = expected_table
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Set associations
|
|
69
|
+
# Example:
|
|
70
|
+
# class LesliSupport::Ticket
|
|
71
|
+
# has_many :lesli_support_tasks
|
|
72
|
+
# end
|
|
73
|
+
has_many(association_name,
|
|
74
|
+
-> { where(deleted_at: nil).order(created_at: :desc) },
|
|
75
|
+
as: as,
|
|
76
|
+
class_name: klass.name,
|
|
77
|
+
dependent: :destroy)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
private
|
|
81
|
+
|
|
82
|
+
# Build: "lesli_support_item_activities" from "LesliSupport::Item::Activity"
|
|
83
|
+
#
|
|
84
|
+
# We DO NOT rely on ActiveRecord's table_name_prefix, because that’s what breaks your case.
|
|
85
|
+
def lesli_expected_discussions_table_name_for(klass)
|
|
86
|
+
parts = klass.name.split("::").map(&:underscore) # ["lesli_support", "item", "discussion"]
|
|
87
|
+
"#{parts.join('_').pluralize}" # "lesli_support_item_discussions"
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
@@ -0,0 +1,95 @@
|
|
|
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 Item
|
|
35
|
+
module Tasks
|
|
36
|
+
extend ActiveSupport::Concern
|
|
37
|
+
|
|
38
|
+
included do
|
|
39
|
+
class_attribute :lesli_tasks_class, instance_accessor: false
|
|
40
|
+
lesli_tasks_setup
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
class_methods do
|
|
44
|
+
|
|
45
|
+
# This acts as our allowlist flag
|
|
46
|
+
def is_lesli_taskable?
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Automatically sets the associations to the
|
|
51
|
+
# engine model that is implementing the task items
|
|
52
|
+
def lesli_tasks_setup(use: nil, as: :taskable, association_name: :tasks)
|
|
53
|
+
klass = if use
|
|
54
|
+
use.to_s.constantize
|
|
55
|
+
else
|
|
56
|
+
"#{name.deconstantize}::Item::Task".constantize
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
self.lesli_tasks_class = klass
|
|
60
|
+
|
|
61
|
+
# ✅ Auto-fix table name (works even when engine defines table_name_prefix)
|
|
62
|
+
expected_table = lesli_expected_task_table_name_for(klass)
|
|
63
|
+
|
|
64
|
+
if klass.table_name != expected_table
|
|
65
|
+
klass.table_name = expected_table
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Set associations
|
|
69
|
+
# Example:
|
|
70
|
+
# class LesliSupport::Ticket
|
|
71
|
+
# has_many :lesli_support_tasks
|
|
72
|
+
# end
|
|
73
|
+
has_many(association_name,
|
|
74
|
+
-> { where(deleted_at: nil).order(created_at: :desc) },
|
|
75
|
+
as: as,
|
|
76
|
+
class_name: klass.name,
|
|
77
|
+
dependent: :destroy)
|
|
78
|
+
rescue NameError
|
|
79
|
+
raise NameError,
|
|
80
|
+
"Task class not found for #{name}. Expected #{name.deconstantize}::Task or pass `use:`"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
private
|
|
84
|
+
|
|
85
|
+
# Build: "lesli_support_item_activities" from "LesliSupport::Item::Activity"
|
|
86
|
+
#
|
|
87
|
+
# We DO NOT rely on ActiveRecord's table_name_prefix, because that’s what breaks your case.
|
|
88
|
+
def lesli_expected_task_table_name_for(klass)
|
|
89
|
+
parts = klass.name.split("::").map(&:underscore) # ["lesli_support", "item", "task"]
|
|
90
|
+
"#{parts.join('_').pluralize}" # "lesli_support_item_tasks"
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
end
|
data/app/models/lesli/account.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lesli
|
|
4
4
|
|
|
5
|
-
Copyright (c)
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
6
|
|
|
7
7
|
This program is free software: you can redistribute it and/or modify
|
|
8
8
|
it under the terms of the GNU General Public License as published by
|
|
@@ -31,20 +31,12 @@ Building a better future, one line of code at a time.
|
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
33
|
module Lesli
|
|
34
|
-
module
|
|
34
|
+
module Item
|
|
35
35
|
class Activity < ApplicationRecord
|
|
36
36
|
self.abstract_class = true
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
enum :activity_type, {
|
|
41
|
-
activity: "activity",
|
|
42
|
-
system: "system"
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
# if needed should be defined
|
|
46
|
-
# by the user at resource level
|
|
47
|
-
# enum activity_code: { }
|
|
37
|
+
belongs_to :user, class_name: "Lesli::User"
|
|
38
|
+
belongs_to :account, class_name: "Lesli::Account"
|
|
39
|
+
belongs_to :subject, polymorphic: true
|
|
48
40
|
end
|
|
49
41
|
end
|
|
50
42
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Lesli
|
|
4
4
|
|
|
5
|
-
Copyright (c)
|
|
5
|
+
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
6
6
|
|
|
7
7
|
This program is free software: you can redistribute it and/or modify
|
|
8
8
|
it under the terms of the GNU General Public License as published by
|
|
@@ -19,7 +19,7 @@ along with this program. If not, see http://www.gnu.org/licenses/.
|
|
|
19
19
|
|
|
20
20
|
Lesli · Ruby on Rails SaaS Development Framework.
|
|
21
21
|
|
|
22
|
-
Made with ♥ by
|
|
22
|
+
Made with ♥ by LesliTech
|
|
23
23
|
Building a better future, one line of code at a time.
|
|
24
24
|
|
|
25
25
|
@contact hello@lesli.tech
|
|
@@ -30,18 +30,13 @@ Building a better future, one line of code at a time.
|
|
|
30
30
|
// ·
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
module Lesli
|
|
34
|
+
module Item
|
|
35
|
+
class Task < ApplicationRecord
|
|
36
|
+
self.abstract_class = true
|
|
37
|
+
belongs_to :user, class_name: "Lesli::User"
|
|
38
|
+
belongs_to :account, class_name: "Lesli::Account"
|
|
39
|
+
belongs_to :taskable, polymorphic: true
|
|
40
40
|
end
|
|
41
41
|
end
|
|
42
|
-
|
|
43
|
-
# Drop the Lesli database (development only)
|
|
44
|
-
def build
|
|
45
|
-
|
|
46
|
-
end
|
|
47
42
|
end
|