motor-admin-cstham8 0.4.35
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 +7 -0
- data/LICENSE +661 -0
- data/README.md +230 -0
- data/Rakefile +11 -0
- data/app/channels/motor/application_cable/channel.rb +14 -0
- data/app/channels/motor/application_cable/connection.rb +27 -0
- data/app/channels/motor/notes_channel.rb +9 -0
- data/app/channels/motor/notifications_channel.rb +9 -0
- data/app/controllers/concerns/motor/current_ability.rb +21 -0
- data/app/controllers/concerns/motor/current_user_method.rb +18 -0
- data/app/controllers/concerns/motor/load_and_authorize_dynamic_resource.rb +73 -0
- data/app/controllers/concerns/motor/wrap_io_params.rb +25 -0
- data/app/controllers/motor/active_storage_attachments_controller.rb +64 -0
- data/app/controllers/motor/alerts_controller.rb +82 -0
- data/app/controllers/motor/api_base_controller.rb +33 -0
- data/app/controllers/motor/api_configs_controller.rb +54 -0
- data/app/controllers/motor/application_controller.rb +8 -0
- data/app/controllers/motor/assets_controller.rb +43 -0
- data/app/controllers/motor/audits_controller.rb +16 -0
- data/app/controllers/motor/auth_tokens_controller.rb +36 -0
- data/app/controllers/motor/configs_controller.rb +33 -0
- data/app/controllers/motor/dashboards_controller.rb +64 -0
- data/app/controllers/motor/data_controller.rb +88 -0
- data/app/controllers/motor/forms_controller.rb +61 -0
- data/app/controllers/motor/icons_controller.rb +22 -0
- data/app/controllers/motor/note_tags_controller.rb +13 -0
- data/app/controllers/motor/notes_controller.rb +58 -0
- data/app/controllers/motor/notifications_controller.rb +33 -0
- data/app/controllers/motor/queries_controller.rb +64 -0
- data/app/controllers/motor/reminders_controller.rb +38 -0
- data/app/controllers/motor/resource_default_queries_controller.rb +23 -0
- data/app/controllers/motor/resource_methods_controller.rb +23 -0
- data/app/controllers/motor/resources_controller.rb +26 -0
- data/app/controllers/motor/run_api_requests_controller.rb +56 -0
- data/app/controllers/motor/run_graphql_requests_controller.rb +48 -0
- data/app/controllers/motor/run_queries_controller.rb +77 -0
- data/app/controllers/motor/schema_controller.rb +31 -0
- data/app/controllers/motor/send_alerts_controller.rb +26 -0
- data/app/controllers/motor/sessions_controller.rb +23 -0
- data/app/controllers/motor/slack_conversations_controller.rb +11 -0
- data/app/controllers/motor/tags_controller.rb +11 -0
- data/app/controllers/motor/ui_controller.rb +51 -0
- data/app/controllers/motor/users_for_autocomplete_controller.rb +23 -0
- data/app/jobs/motor/alert_sending_job.rb +13 -0
- data/app/jobs/motor/application_job.rb +6 -0
- data/app/jobs/motor/notify_note_mentions_job.rb +9 -0
- data/app/jobs/motor/notify_reminder_job.rb +9 -0
- data/app/mailers/motor/alerts_mailer.rb +39 -0
- data/app/mailers/motor/application_mailer.rb +33 -0
- data/app/mailers/motor/notifications_mailer.rb +33 -0
- data/app/models/motor/alert.rb +30 -0
- data/app/models/motor/alert_lock.rb +7 -0
- data/app/models/motor/api_config.rb +28 -0
- data/app/models/motor/application_record.rb +18 -0
- data/app/models/motor/audit.rb +13 -0
- data/app/models/motor/config.rb +13 -0
- data/app/models/motor/dashboard.rb +26 -0
- data/app/models/motor/form.rb +23 -0
- data/app/models/motor/note.rb +18 -0
- data/app/models/motor/note_tag.rb +7 -0
- data/app/models/motor/note_tag_tag.rb +8 -0
- data/app/models/motor/notification.rb +14 -0
- data/app/models/motor/query.rb +33 -0
- data/app/models/motor/reminder.rb +13 -0
- data/app/models/motor/resource.rb +15 -0
- data/app/models/motor/tag.rb +7 -0
- data/app/models/motor/taggable_tag.rb +8 -0
- data/app/views/layouts/motor/application.html.erb +17 -0
- data/app/views/layouts/motor/mailer.html.erb +72 -0
- data/app/views/motor/alerts_mailer/alert_email.html.erb +54 -0
- data/app/views/motor/notifications_mailer/notify_mention_email.html.erb +28 -0
- data/app/views/motor/notifications_mailer/notify_reminder_email.html.erb +28 -0
- data/app/views/motor/ui/show.html.erb +1 -0
- data/config/locales/el.yml +420 -0
- data/config/locales/en.yml +340 -0
- data/config/locales/es.yml +420 -0
- data/config/locales/ja.yml +340 -0
- data/config/locales/pt.yml +416 -0
- data/config/routes.rb +65 -0
- data/lib/generators/motor/install_generator.rb +24 -0
- data/lib/generators/motor/install_notes_generator.rb +22 -0
- data/lib/generators/motor/migration.rb +17 -0
- data/lib/generators/motor/templates/install.rb +271 -0
- data/lib/generators/motor/templates/install_api_configs.rb +86 -0
- data/lib/generators/motor/templates/install_notes.rb +83 -0
- data/lib/generators/motor/templates/upgrade_motor_api_actions.rb +71 -0
- data/lib/generators/motor/upgrade_generator.rb +43 -0
- data/lib/motor/active_record_utils/action_text_attribute_patch.rb +19 -0
- data/lib/motor/active_record_utils/active_record_connection_column_patch.rb +14 -0
- data/lib/motor/active_record_utils/active_record_filter.rb +405 -0
- data/lib/motor/active_record_utils/active_storage_blob_patch.rb +30 -0
- data/lib/motor/active_record_utils/active_storage_links_extension.rb +11 -0
- data/lib/motor/active_record_utils/defined_scopes_extension.rb +25 -0
- data/lib/motor/active_record_utils/fetch_methods.rb +24 -0
- data/lib/motor/active_record_utils/types.rb +64 -0
- data/lib/motor/active_record_utils.rb +45 -0
- data/lib/motor/admin.rb +141 -0
- data/lib/motor/alerts/persistance.rb +97 -0
- data/lib/motor/alerts/scheduled_alerts_cache.rb +29 -0
- data/lib/motor/alerts/scheduler.rb +30 -0
- data/lib/motor/alerts/slack_sender.rb +74 -0
- data/lib/motor/alerts.rb +52 -0
- data/lib/motor/api_configs.rb +41 -0
- data/lib/motor/api_query/apply_scope.rb +44 -0
- data/lib/motor/api_query/build_json.rb +171 -0
- data/lib/motor/api_query/build_meta.rb +20 -0
- data/lib/motor/api_query/filter.rb +125 -0
- data/lib/motor/api_query/paginate.rb +19 -0
- data/lib/motor/api_query/search.rb +60 -0
- data/lib/motor/api_query/sort.rb +64 -0
- data/lib/motor/api_query.rb +24 -0
- data/lib/motor/assets.rb +62 -0
- data/lib/motor/build_schema/active_storage_attachment_schema.rb +125 -0
- data/lib/motor/build_schema/adjust_devise_model_schema.rb +60 -0
- data/lib/motor/build_schema/apply_permissions.rb +64 -0
- data/lib/motor/build_schema/defaults.rb +66 -0
- data/lib/motor/build_schema/find_display_column.rb +65 -0
- data/lib/motor/build_schema/find_icon.rb +135 -0
- data/lib/motor/build_schema/find_searchable_columns.rb +33 -0
- data/lib/motor/build_schema/load_from_rails.rb +361 -0
- data/lib/motor/build_schema/merge_schema_configs.rb +157 -0
- data/lib/motor/build_schema/reorder_schema.rb +88 -0
- data/lib/motor/build_schema/utils.rb +31 -0
- data/lib/motor/build_schema.rb +125 -0
- data/lib/motor/cancan_utils/ability_patch.rb +31 -0
- data/lib/motor/cancan_utils/can_manage_all.rb +14 -0
- data/lib/motor/cancan_utils.rb +9 -0
- data/lib/motor/configs/build_configs_hash.rb +90 -0
- data/lib/motor/configs/build_ui_app_tag.rb +177 -0
- data/lib/motor/configs/load_from_cache.rb +110 -0
- data/lib/motor/configs/sync_from_file.rb +35 -0
- data/lib/motor/configs/sync_from_hash.rb +159 -0
- data/lib/motor/configs/sync_middleware.rb +72 -0
- data/lib/motor/configs/sync_with_remote.rb +47 -0
- data/lib/motor/configs/write_to_file.rb +36 -0
- data/lib/motor/configs.rb +39 -0
- data/lib/motor/dashboards/persistance.rb +73 -0
- data/lib/motor/dashboards.rb +8 -0
- data/lib/motor/forms/persistance.rb +93 -0
- data/lib/motor/forms.rb +8 -0
- data/lib/motor/hash_serializer.rb +21 -0
- data/lib/motor/net_http_utils.rb +50 -0
- data/lib/motor/notes/notify_mentions.rb +71 -0
- data/lib/motor/notes/notify_reminder.rb +48 -0
- data/lib/motor/notes/persist.rb +36 -0
- data/lib/motor/notes/reminders_scheduler.rb +39 -0
- data/lib/motor/notes/tags.rb +34 -0
- data/lib/motor/notes.rb +12 -0
- data/lib/motor/queries/persistance.rb +90 -0
- data/lib/motor/queries/postgresql_exec_query.rb +28 -0
- data/lib/motor/queries/render_sql_template.rb +61 -0
- data/lib/motor/queries/run_query.rb +289 -0
- data/lib/motor/queries.rb +11 -0
- data/lib/motor/railtie.rb +11 -0
- data/lib/motor/resources/custom_sql_columns_cache.rb +17 -0
- data/lib/motor/resources/fetch_configured_model.rb +269 -0
- data/lib/motor/resources/persist_configs.rb +232 -0
- data/lib/motor/resources.rb +19 -0
- data/lib/motor/slack/client.rb +62 -0
- data/lib/motor/slack.rb +16 -0
- data/lib/motor/tags.rb +32 -0
- data/lib/motor/tasks/motor.rake +54 -0
- data/lib/motor/version.rb +5 -0
- data/lib/motor-admin-cstham8.rb +3 -0
- data/lib/motor.rb +87 -0
- data/ui/dist/manifest.json +1990 -0
- metadata +303 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Motor
|
|
4
|
+
module Resources
|
|
5
|
+
module PersistConfigs
|
|
6
|
+
COLUMN_DEFAULTS = BuildSchema::COLUMN_DEFAULTS
|
|
7
|
+
ACTION_DEFAULTS = BuildSchema::ACTION_DEFAULTS
|
|
8
|
+
TAB_DEFAULTS = BuildSchema::TAB_DEFAULTS
|
|
9
|
+
SCOPE_DEFAULTS = BuildSchema::SCOPE_DEFAULTS
|
|
10
|
+
ASSOCIATION_DEFAULTS = BuildSchema::ASSOCIATION_DEFAULTS
|
|
11
|
+
|
|
12
|
+
module_function
|
|
13
|
+
|
|
14
|
+
# @param resource [Motor::Resource]
|
|
15
|
+
# @return [Motor::Resource]
|
|
16
|
+
def call(resource)
|
|
17
|
+
preferences = resource.preferences
|
|
18
|
+
|
|
19
|
+
resource = Motor::Resource.find_or_initialize_by(name: resource.name)
|
|
20
|
+
|
|
21
|
+
assign_preferences!(resource, preferences)
|
|
22
|
+
|
|
23
|
+
resource.save!
|
|
24
|
+
|
|
25
|
+
resource
|
|
26
|
+
rescue ActiveRecord::RecordNotUnique
|
|
27
|
+
retry
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# @param resource [Motor::Resource]
|
|
31
|
+
# @param preferences [HashWithIndifferentAccess]
|
|
32
|
+
# @return [Motor::Resource]
|
|
33
|
+
def assign_preferences!(resource, preferences)
|
|
34
|
+
default_schema = fetch_default_schema(resource.name)
|
|
35
|
+
|
|
36
|
+
resource.preferences = normalize_preferences(
|
|
37
|
+
default_schema,
|
|
38
|
+
resource.preferences,
|
|
39
|
+
preferences
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
resource
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# @param default_prefs [HashWithIndifferentAccess]
|
|
46
|
+
# @param existing_prefs [HashWithIndifferentAccess]
|
|
47
|
+
# @param new_prefs [HashWithIndifferentAccess]
|
|
48
|
+
# @return [HashWithIndifferentAccess]
|
|
49
|
+
def normalize_preferences(default_prefs, existing_prefs, new_prefs)
|
|
50
|
+
normalized_preferences = new_prefs.slice(*RESOURCE_ATTRS).with_indifferent_access
|
|
51
|
+
normalized_preferences = existing_prefs.merge(normalized_preferences)
|
|
52
|
+
normalized_preferences = reject_default(default_prefs, normalized_preferences)
|
|
53
|
+
|
|
54
|
+
normalize_configs!(normalized_preferences, :columns, default_prefs, existing_prefs, new_prefs)
|
|
55
|
+
normalize_configs!(normalized_preferences, :associations, default_prefs, existing_prefs, new_prefs)
|
|
56
|
+
normalize_configs!(normalized_preferences, :actions, default_prefs, existing_prefs, new_prefs)
|
|
57
|
+
normalize_configs!(normalized_preferences, :tabs, default_prefs, existing_prefs, new_prefs)
|
|
58
|
+
normalize_configs!(normalized_preferences, :scopes, default_prefs, existing_prefs, new_prefs)
|
|
59
|
+
|
|
60
|
+
normalized_preferences.compact
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def normalize_configs!(preferences, configs_name, default_prefs, existing_prefs, new_prefs)
|
|
64
|
+
return preferences if new_prefs[configs_name].blank?
|
|
65
|
+
|
|
66
|
+
normalized_configs = public_send(:"normalize_#{configs_name}",
|
|
67
|
+
default_prefs[configs_name],
|
|
68
|
+
existing_prefs.fetch(configs_name, []),
|
|
69
|
+
new_prefs.fetch(configs_name, []))
|
|
70
|
+
|
|
71
|
+
preferences[configs_name] = normalized_configs
|
|
72
|
+
|
|
73
|
+
preferences
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @param default_columns [Array<HashWithIndifferentAccess>]
|
|
77
|
+
# @param existing_columns [Array<HashWithIndifferentAccess>]
|
|
78
|
+
# @param new_columns [Array<HashWithIndifferentAccess>]
|
|
79
|
+
# @return [Array<HashWithIndifferentAccess>]
|
|
80
|
+
def normalize_columns(default_columns, existing_columns, new_columns)
|
|
81
|
+
fetch_update_names(existing_columns, new_columns).uniq.map do |name|
|
|
82
|
+
new_column = safe_fetch_by_name(new_columns, name)
|
|
83
|
+
|
|
84
|
+
next if new_column[:_remove]
|
|
85
|
+
|
|
86
|
+
existing_column = safe_fetch_by_name(existing_columns, name)
|
|
87
|
+
default_column = safe_fetch_by_name(default_columns, name)
|
|
88
|
+
column_attrs = new_column.slice(*COLUMN_ATTRS)
|
|
89
|
+
|
|
90
|
+
normalized_column = existing_column.merge(column_attrs)
|
|
91
|
+
normalized_column = reject_default(default_column, normalized_column)
|
|
92
|
+
|
|
93
|
+
next if normalized_column.blank?
|
|
94
|
+
|
|
95
|
+
normalized_column[:name] ||= name
|
|
96
|
+
|
|
97
|
+
normalized_column
|
|
98
|
+
end.compact.presence
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# @param default_actions [Array<HashWithIndifferentAccess>]
|
|
102
|
+
# @param existing_actions [Array<HashWithIndifferentAccess>]
|
|
103
|
+
# @param new_actions [Array<HashWithIndifferentAccess>]
|
|
104
|
+
# @return [Array<HashWithIndifferentAccess>]
|
|
105
|
+
def normalize_actions(default_actions, existing_actions, new_actions)
|
|
106
|
+
fetch_update_names(existing_actions, new_actions).map do |name|
|
|
107
|
+
new_action = safe_fetch_by_name(new_actions, name)
|
|
108
|
+
|
|
109
|
+
next if new_action[:_remove]
|
|
110
|
+
|
|
111
|
+
existing_action = safe_fetch_by_name(existing_actions, name)
|
|
112
|
+
default_action = safe_fetch_by_name(default_actions, name)
|
|
113
|
+
action_attrs = new_action.slice(*ACTION_ATTRS)
|
|
114
|
+
|
|
115
|
+
normalized_action = existing_action.merge(action_attrs)
|
|
116
|
+
normalized_action = reject_default(default_action.presence || ACTION_DEFAULTS, normalized_action)
|
|
117
|
+
|
|
118
|
+
next if normalized_action.blank?
|
|
119
|
+
|
|
120
|
+
normalized_action[:name] ||= name
|
|
121
|
+
|
|
122
|
+
normalized_action
|
|
123
|
+
end.compact.presence
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# @param default_tabs [Array<HashWithIndifferentAccess>]
|
|
127
|
+
# @param existing_tabs [Array<HashWithIndifferentAccess>]
|
|
128
|
+
# @param new_tabs [Array<HashWithIndifferentAccess>]
|
|
129
|
+
# @return [Array<HashWithIndifferentAccess>]
|
|
130
|
+
def normalize_tabs(default_tabs, existing_tabs, new_tabs)
|
|
131
|
+
fetch_update_names(existing_tabs, new_tabs).uniq.map do |name|
|
|
132
|
+
new_tab = safe_fetch_by_name(new_tabs, name)
|
|
133
|
+
|
|
134
|
+
next if new_tab[:_remove]
|
|
135
|
+
|
|
136
|
+
existing_tab = safe_fetch_by_name(existing_tabs, name)
|
|
137
|
+
default_tab = safe_fetch_by_name(default_tabs, name)
|
|
138
|
+
tab_attrs = new_tab.slice(*TAB_ATTRS)
|
|
139
|
+
|
|
140
|
+
normalized_tab = existing_tab.merge(tab_attrs)
|
|
141
|
+
normalized_tab = reject_default(default_tab.presence || TAB_DEFAULTS, normalized_tab)
|
|
142
|
+
|
|
143
|
+
next if normalized_tab.blank?
|
|
144
|
+
|
|
145
|
+
normalized_tab[:name] ||= name
|
|
146
|
+
|
|
147
|
+
normalized_tab
|
|
148
|
+
end.compact.presence
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @param default_scopes [Array<HashWithIndifferentAccess>]
|
|
152
|
+
# @param existing_scopes [Array<HashWithIndifferentAccess>]
|
|
153
|
+
# @param new_scopes [Array<HashWithIndifferentAccess>]
|
|
154
|
+
# @return [Array<HashWithIndifferentAccess>]
|
|
155
|
+
def normalize_scopes(default_scopes, existing_scopes, new_scopes)
|
|
156
|
+
fetch_update_names(existing_scopes, new_scopes).uniq.map do |name|
|
|
157
|
+
new_scope = safe_fetch_by_name(new_scopes, name)
|
|
158
|
+
|
|
159
|
+
next if new_scope[:_remove]
|
|
160
|
+
|
|
161
|
+
existing_scope = safe_fetch_by_name(existing_scopes, name)
|
|
162
|
+
default_scope = safe_fetch_by_name(default_scopes, name)
|
|
163
|
+
scope_attrs = new_scope.slice(*SCOPE_ATTRS)
|
|
164
|
+
|
|
165
|
+
normalized_scope = existing_scope.merge(scope_attrs)
|
|
166
|
+
normalized_scope = reject_default(default_scope.presence || SCOPE_DEFAULTS, normalized_scope)
|
|
167
|
+
|
|
168
|
+
next if normalized_scope.blank?
|
|
169
|
+
|
|
170
|
+
normalized_scope[:name] ||= name
|
|
171
|
+
|
|
172
|
+
normalized_scope
|
|
173
|
+
end.compact.presence
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
# @param default_assocs [Array<HashWithIndifferentAccess>]
|
|
177
|
+
# @param existing_assocs [Array<HashWithIndifferentAccess>]
|
|
178
|
+
# @param new_assocs [Array<HashWithIndifferentAccess>]
|
|
179
|
+
# @return [Array<HashWithIndifferentAccess>]
|
|
180
|
+
def normalize_associations(default_assocs, existing_assocs, new_assocs)
|
|
181
|
+
(existing_assocs.pluck(:name) + new_assocs.pluck(:name)).uniq.map do |name|
|
|
182
|
+
new_assoc = safe_fetch_by_name(new_assocs, name)
|
|
183
|
+
|
|
184
|
+
next if new_assoc[:_remove]
|
|
185
|
+
|
|
186
|
+
existing_assoc = safe_fetch_by_name(existing_assocs, name)
|
|
187
|
+
default_assoc = safe_fetch_by_name(default_assocs, name)
|
|
188
|
+
assoc_attrs = new_assoc.slice(*ASSOCIATION_ATTRS)
|
|
189
|
+
|
|
190
|
+
normalized_assoc = existing_assoc.merge(assoc_attrs)
|
|
191
|
+
normalized_assoc = reject_default(default_assoc.presence || ASSOCIATION_DEFAULTS, normalized_assoc)
|
|
192
|
+
|
|
193
|
+
normalized_assoc.merge(name: name) if normalized_assoc.present?
|
|
194
|
+
end.compact.presence
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def fetch_update_names(existing_items, new_items)
|
|
198
|
+
new_names = new_items.map { |e| e[:_update] || e[:name] }
|
|
199
|
+
|
|
200
|
+
(existing_items.pluck(:name) + new_names).uniq
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def safe_fetch_by_name(list, name)
|
|
204
|
+
list.find { |e| e[:_update] == name || e[:name] == name } || {}
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
# @param resource_name [String]
|
|
208
|
+
# @return [HashWithIndifferentAccess]
|
|
209
|
+
def fetch_default_schema(resource_name)
|
|
210
|
+
model = resource_name.classify.constantize
|
|
211
|
+
|
|
212
|
+
BuildSchema::LoadFromRails.build_model_schema(model).merge(custom_sql: model.all.to_sql)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# @param default [HashWithIndifferentAccess]
|
|
216
|
+
# @param new [HashWithIndifferentAccess]
|
|
217
|
+
# @return [HashWithIndifferentAccess]
|
|
218
|
+
def reject_default(default, new)
|
|
219
|
+
return new unless default
|
|
220
|
+
|
|
221
|
+
new.reject do |key, value|
|
|
222
|
+
default[key].to_json ==
|
|
223
|
+
if value.is_a?(Hash) || value.is_a?(ActiveSupport::HashWithIndifferentAccess)
|
|
224
|
+
value.select { |_, v| v.present? }.to_json
|
|
225
|
+
else
|
|
226
|
+
value.to_json
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Motor
|
|
4
|
+
module Resources
|
|
5
|
+
RESOURCE_ATTRS = %w[display_name display_column icon custom_sql visible display_primary_key
|
|
6
|
+
searchable_columns preferences].freeze
|
|
7
|
+
COLUMN_ATTRS = %w[name display_name column_type access_type default_value reference virtual format
|
|
8
|
+
validators description].freeze
|
|
9
|
+
ASSOCIATION_ATTRS = %w[name display_name model_name icon visible foreign_key primary_key options virtual
|
|
10
|
+
polymorphic slug].freeze
|
|
11
|
+
SCOPE_ATTRS = %w[name display_name scope_type preferences visible].freeze
|
|
12
|
+
ACTION_ATTRS = %w[name display_name action_type preferences apply_on visible].freeze
|
|
13
|
+
TAB_ATTRS = %w[name display_name tab_type preferences visible].freeze
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
require_relative 'resources/fetch_configured_model'
|
|
18
|
+
require_relative 'resources/persist_configs'
|
|
19
|
+
require_relative 'resources/custom_sql_columns_cache'
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Motor
|
|
4
|
+
module Slack
|
|
5
|
+
module Client
|
|
6
|
+
BASE_API_URL = 'https://slack.com/api'
|
|
7
|
+
POST_MESSAGE_ENPOINT = "#{BASE_API_URL}/chat.postMessage"
|
|
8
|
+
LOAD_CONVERSATIONS_ENPOINT = "#{BASE_API_URL}/conversations.list"
|
|
9
|
+
LOAD_USERS_ENPOINT = "#{BASE_API_URL}/users.list"
|
|
10
|
+
SEND_FILE_ENPOINT = "#{BASE_API_URL}/files.upload"
|
|
11
|
+
|
|
12
|
+
ApiError = Class.new(StandardError)
|
|
13
|
+
|
|
14
|
+
module_function
|
|
15
|
+
|
|
16
|
+
def send_message(params = {})
|
|
17
|
+
resp = Motor::NetHttpUtils.post(POST_MESSAGE_ENPOINT, params.merge(token: auth_token))
|
|
18
|
+
|
|
19
|
+
parse_json_response_or_throw_error(resp)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def send_file(params = {})
|
|
23
|
+
content = params.delete(:content)
|
|
24
|
+
body = { content: content }.to_query
|
|
25
|
+
|
|
26
|
+
resp = Motor::NetHttpUtils.post(SEND_FILE_ENPOINT, params.merge(token: auth_token), {}, body)
|
|
27
|
+
|
|
28
|
+
parse_json_response_or_throw_error(resp)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def load_conversations(params = {})
|
|
32
|
+
resp = Motor::NetHttpUtils.get(LOAD_CONVERSATIONS_ENPOINT, params.merge(token: auth_token))
|
|
33
|
+
|
|
34
|
+
parse_json_response_or_throw_error(resp)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def load_users(params = {})
|
|
38
|
+
resp = Motor::NetHttpUtils.get(LOAD_USERS_ENPOINT, params.merge(token: auth_token))
|
|
39
|
+
|
|
40
|
+
parse_json_response_or_throw_error(resp)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def parse_json_response_or_throw_error(resp)
|
|
44
|
+
data = JSON.parse(resp.body)
|
|
45
|
+
|
|
46
|
+
raise ApiError, resp.body unless data['ok']
|
|
47
|
+
|
|
48
|
+
data
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def auth_token
|
|
52
|
+
return ENV['SLACK_AUTH_TOKEN'] unless defined?(Motor::EncryptedConfig)
|
|
53
|
+
|
|
54
|
+
config = Motor::EncryptedConfig.find_by(key: EncryptedConfig::SLACK_CREDENTIALS_KEY)
|
|
55
|
+
|
|
56
|
+
return '' unless config
|
|
57
|
+
|
|
58
|
+
config.value[:api_key]
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/motor/slack.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Motor
|
|
4
|
+
module Slack
|
|
5
|
+
ITEMS_LIMIT = 1000
|
|
6
|
+
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
def conversations
|
|
10
|
+
Slack::Client.load_conversations(limit: ITEMS_LIMIT)['channels'] +
|
|
11
|
+
Slack::Client.load_users(limit: ITEMS_LIMIT)['members']
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
require_relative 'slack/client'
|
data/lib/motor/tags.rb
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Motor
|
|
4
|
+
module Tags
|
|
5
|
+
module_function
|
|
6
|
+
|
|
7
|
+
def assign_tags(taggable, tags)
|
|
8
|
+
return taggable unless tags
|
|
9
|
+
|
|
10
|
+
tags.each do |tag_name|
|
|
11
|
+
next if taggable.taggable_tags.find { |tt| tt.tag.name.casecmp(tag_name).zero? }
|
|
12
|
+
|
|
13
|
+
tag = Tag.find_or_initialize_by(name: tag_name)
|
|
14
|
+
|
|
15
|
+
taggable.taggable_tags.new(tag: tag)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
remove_missing_tags(taggable, tags) if taggable.persisted?
|
|
19
|
+
|
|
20
|
+
taggable
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def remove_missing_tags(taggable, tags)
|
|
24
|
+
downcase_tags = tags.map(&:downcase)
|
|
25
|
+
tags_to_remove = taggable.tags.reject { |tt| tt.name.downcase.in?(downcase_tags) }
|
|
26
|
+
|
|
27
|
+
taggable.tags -= tags_to_remove
|
|
28
|
+
|
|
29
|
+
taggable
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
namespace :motor do
|
|
4
|
+
desc 'Create migratione and add route'
|
|
5
|
+
|
|
6
|
+
task install: :environment do
|
|
7
|
+
Rails::Generators.invoke('motor:install')
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
desc 'Update configs/motor.yml file'
|
|
11
|
+
|
|
12
|
+
task dump: :environment do
|
|
13
|
+
Motor::Configs::WriteToFile.write_with_lock
|
|
14
|
+
|
|
15
|
+
puts '✅ configs/motor.yml has been updated'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
desc 'Load configs from configs/motor.yml file'
|
|
19
|
+
|
|
20
|
+
task load: :environment do
|
|
21
|
+
Motor::Configs::SyncFromFile.call(with_exception: true)
|
|
22
|
+
|
|
23
|
+
puts '✅ configs have been loaded from configs/motor.yml'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc 'Reload configs from configs/motor.yml file'
|
|
27
|
+
|
|
28
|
+
task reload: :environment do
|
|
29
|
+
ActiveRecord::Base.transaction do
|
|
30
|
+
Motor::Configs.clear
|
|
31
|
+
Motor::Configs::SyncFromFile.call(with_exception: true)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
puts '✅ configs have been loaded from configs/motor.yml'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
desc 'Synchronize configs with remote application'
|
|
38
|
+
|
|
39
|
+
task sync: :environment do
|
|
40
|
+
remote_url = ENV['MOTOR_SYNC_REMOTE_URL']
|
|
41
|
+
api_key = ENV['MOTOR_SYNC_API_KEY']
|
|
42
|
+
|
|
43
|
+
raise 'Specify target app url using `MOTOR_SYNC_REMOTE_URL` env variable' if remote_url.blank?
|
|
44
|
+
raise 'Specify sync api key using `MOTOR_SYNC_API_KEY` env variable' if api_key.blank?
|
|
45
|
+
|
|
46
|
+
Motor::Configs::SyncWithRemote.call(remote_url, api_key)
|
|
47
|
+
Motor::Configs::WriteToFile.write_with_lock
|
|
48
|
+
|
|
49
|
+
puts "✅ Motor Admin configurations have been synced with #{remote_url}"
|
|
50
|
+
rescue Motor::Configs::SyncWithRemote::ApiNotFound
|
|
51
|
+
puts '⚠️ Synchronization failed: you need to specify `MOTOR_SYNC_API_KEY` ' \
|
|
52
|
+
'env variable in your remote app in order to enable this feature'
|
|
53
|
+
end
|
|
54
|
+
end
|
data/lib/motor.rb
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'concurrent/executor/fixed_thread_pool'
|
|
4
|
+
require 'concurrent/timer_task'
|
|
5
|
+
require 'cancancan'
|
|
6
|
+
require 'ar_lazy_preload'
|
|
7
|
+
require 'fugit'
|
|
8
|
+
require 'csv'
|
|
9
|
+
require 'audited'
|
|
10
|
+
require 'uri'
|
|
11
|
+
require 'net/http'
|
|
12
|
+
require 'net/https'
|
|
13
|
+
|
|
14
|
+
module Motor
|
|
15
|
+
PATH = Pathname.new(__dir__)
|
|
16
|
+
|
|
17
|
+
module DatabaseClasses
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
module_function
|
|
21
|
+
|
|
22
|
+
def reload!
|
|
23
|
+
Kernel.silence_warnings do
|
|
24
|
+
Dir[PATH.join('./motor/**/*.rb')].each do |f|
|
|
25
|
+
next if f.ends_with?('alerts/scheduler.rb')
|
|
26
|
+
next if f.ends_with?('notes/reminders_scheduler.rb')
|
|
27
|
+
next if f.ends_with?('alerts/scheduled_alerts_cache.rb')
|
|
28
|
+
next if f.ends_with?('configs/load_from_cache.rb')
|
|
29
|
+
next if f.ends_with?('configs/sync_from_file.rb')
|
|
30
|
+
next if f.ends_with?('resources/custom_sql_columns_cache.rb')
|
|
31
|
+
|
|
32
|
+
load f
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
true
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def server?
|
|
40
|
+
defined?(::Rails::Server) ||
|
|
41
|
+
defined?(::Thin::Server) ||
|
|
42
|
+
defined?(::PhusionPassenger) ||
|
|
43
|
+
(defined?(::Puma) && File.basename($PROGRAM_NAME) == 'puma') ||
|
|
44
|
+
defined?(::Unicorn::HttpServer) ||
|
|
45
|
+
defined?(::Mongrel::HttpServer) ||
|
|
46
|
+
defined?(JRuby::Rack::VERSION) ||
|
|
47
|
+
defined?(::Trinidad::Server)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def app_host
|
|
51
|
+
Rails.application.config.action_dispatch.default_url_options&.fetch(:host) ||
|
|
52
|
+
ENV.fetch('HOST', 'example.com')
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def company_name
|
|
56
|
+
'Motor Admin'
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def with_public_access?
|
|
60
|
+
ENV['MOTOR_PUBLIC_ACCESS'].to_s == 'true'
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def development?
|
|
64
|
+
ENV['MOTOR_DEVELOPMENT'].present?
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
require 'motor/version'
|
|
69
|
+
require 'motor/admin'
|
|
70
|
+
require 'motor/assets'
|
|
71
|
+
require 'motor/active_record_utils'
|
|
72
|
+
require 'motor/cancan_utils'
|
|
73
|
+
require 'motor/build_schema'
|
|
74
|
+
require 'motor/api_query'
|
|
75
|
+
require 'motor/tags'
|
|
76
|
+
require 'motor/configs'
|
|
77
|
+
require 'motor/queries'
|
|
78
|
+
require 'motor/dashboards'
|
|
79
|
+
require 'motor/forms'
|
|
80
|
+
require 'motor/api_configs'
|
|
81
|
+
require 'motor/alerts'
|
|
82
|
+
require 'motor/slack'
|
|
83
|
+
require 'motor/resources'
|
|
84
|
+
require 'motor/notes'
|
|
85
|
+
require 'motor/hash_serializer'
|
|
86
|
+
require 'motor/net_http_utils'
|
|
87
|
+
require 'motor/railtie'
|