marty 8.0.0 → 8.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitlab-ci.yml +7 -0
- data/app/assets/javascripts/marty/cable.js +12 -0
- data/app/assets/stylesheets/marty/codemirror/notifications.css +4 -0
- data/app/channels/application_cable/channel.rb +4 -0
- data/app/channels/application_cable/connection.rb +17 -0
- data/app/channels/marty/notification_channel.rb +8 -0
- data/app/components/marty/auth_app.rb +54 -6
- data/app/components/marty/auth_app/client/auth_app.js +53 -0
- data/app/components/marty/main_auth_app.rb +47 -1
- data/app/components/marty/notifications/config_view.rb +56 -0
- data/app/components/marty/notifications/deliveries_view.rb +50 -0
- data/app/components/marty/notifications/grid_view.rb +56 -0
- data/app/components/marty/notifications/window.rb +23 -0
- data/app/components/marty/promise_view.rb +13 -1
- data/app/components/marty/promise_view/client/promise_view.js +18 -0
- data/app/components/marty/{schedule_jobs_dashboard/client/schedule_jobs_dashboard.js → schedule_jobs_grid/client/schedule_jobs_grid.js} +0 -0
- data/app/components/marty/simple_app/client/simple_app.js +5 -1
- data/app/components/marty/users/user_view.rb +177 -0
- data/app/controllers/marty/application_controller.rb +13 -0
- data/app/models/marty/data_grid.rb +1 -1
- data/app/models/marty/notifications.rb +4 -0
- data/app/models/marty/notifications/config.rb +25 -0
- data/app/models/marty/notifications/delivery.rb +56 -0
- data/app/models/marty/notifications/event_type.rb +11 -0
- data/app/models/marty/notifications/notification.rb +25 -0
- data/app/models/marty/promise.rb +1 -0
- data/app/models/marty/user.rb +14 -0
- data/app/services/marty/notifications/create.rb +39 -0
- data/app/services/marty/notifications/create_deliveries.rb +25 -0
- data/app/services/marty/notifications/process_delivery.rb +11 -0
- data/app/services/marty/notifications/processors/email.rb +13 -0
- data/app/services/marty/notifications/processors/sms.rb +13 -0
- data/app/services/marty/notifications/processors/web.rb +27 -0
- data/app/services/marty/promises/cancel.rb +37 -0
- data/app/services/marty/promises/delorean/create.rb +4 -0
- data/app/services/marty/promises/ruby/create.rb +4 -1
- data/app/views/marty/diagnostic/op.html.erb +4 -0
- data/db/migrate/514_remove_marty_events.rb +1 -1
- data/db/migrate/519_create_marty_notifications_event_types.rb +16 -0
- data/db/migrate/520_create_marty_notifications.rb +11 -0
- data/db/migrate/521_create_marty_notifications_deliveries.rb +22 -0
- data/db/migrate/522_create_marty_notifications_config.rb +21 -0
- data/db/sql/lookup_grid_distinct_v1.sql +6 -6
- data/lib/marty.rb +2 -0
- data/lib/marty/diagnostic/version.rb +36 -26
- data/lib/marty/engine.rb +7 -1
- data/lib/marty/mcfly_model.rb +27 -6
- data/lib/marty/railtie.rb +1 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +3 -0
- data/spec/controllers/diagnostic/controller_spec.rb +1 -1
- data/spec/dummy/app/models/gemini/fannie_bup.rb +27 -13
- data/spec/dummy/app/models/gemini/helper.rb +62 -0
- data/spec/features/notifications_spec.rb +224 -0
- data/spec/job_helper.rb +14 -1
- data/spec/lib/mcfly_model_spec.rb +14 -7
- data/spec/models/promise_spec.rb +121 -0
- data/spec/services/notifications/create_spec.rb +82 -0
- metadata +73 -3
data/app/models/marty/promise.rb
CHANGED
data/app/models/marty/user.rb
CHANGED
@@ -9,6 +9,13 @@ class Marty::User < Marty::Base
|
|
9
9
|
|
10
10
|
has_many :user_roles, dependent: :destroy
|
11
11
|
|
12
|
+
has_many(
|
13
|
+
:notification_deliveries,
|
14
|
+
class_name: '::Marty::Notifications::Delivery',
|
15
|
+
dependent: :destroy,
|
16
|
+
foreign_key: :recipient_id
|
17
|
+
)
|
18
|
+
|
12
19
|
scope :active, -> { where(active: true) }
|
13
20
|
|
14
21
|
validate :verify_changes
|
@@ -114,6 +121,13 @@ class Marty::User < Marty::Base
|
|
114
121
|
end
|
115
122
|
end
|
116
123
|
|
124
|
+
def unread_web_notifications_count
|
125
|
+
notification_deliveries.where(
|
126
|
+
delivery_type: :web,
|
127
|
+
state: [:sent]
|
128
|
+
).count
|
129
|
+
end
|
130
|
+
|
117
131
|
private
|
118
132
|
|
119
133
|
def verify_changes
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Marty
|
2
|
+
module Notifications
|
3
|
+
module Create
|
4
|
+
extend Delorean::Functions
|
5
|
+
|
6
|
+
delorean_fn :call do |event_type:, text:|
|
7
|
+
notification, deliveries = ActiveRecord::Base.transaction do
|
8
|
+
notification = ::Marty::Notifications::Notification.create!(
|
9
|
+
event_type: event_type,
|
10
|
+
text: text,
|
11
|
+
state: :pending
|
12
|
+
)
|
13
|
+
|
14
|
+
# FIXME: We should consider processing deliveries in the background
|
15
|
+
deliveries = ::Marty::Notifications::CreateDeliveries.call(
|
16
|
+
notification: notification
|
17
|
+
)
|
18
|
+
|
19
|
+
[notification, deliveries]
|
20
|
+
end
|
21
|
+
|
22
|
+
deliveries.each do |delivery|
|
23
|
+
::Marty::Notifications::ProcessDelivery.call(
|
24
|
+
delivery: delivery
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
notification.set_processed!
|
29
|
+
|
30
|
+
{
|
31
|
+
id: notification.id,
|
32
|
+
event_type: event_type,
|
33
|
+
text: text,
|
34
|
+
state: notification.state,
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Marty
|
2
|
+
module Notifications
|
3
|
+
module CreateDeliveries
|
4
|
+
class << self
|
5
|
+
def call(notification:)
|
6
|
+
configs(notification).map do |config|
|
7
|
+
notification.deliveries.create!(
|
8
|
+
state: :pending,
|
9
|
+
delivery_type: config.delivery_type,
|
10
|
+
recipient: config.recipient,
|
11
|
+
text: config.text
|
12
|
+
)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def configs(notification)
|
17
|
+
Marty::Notifications::Config.where(
|
18
|
+
state: :on,
|
19
|
+
event_type: notification.event_type
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Marty
|
2
|
+
module Notifications
|
3
|
+
module Processors
|
4
|
+
module Web
|
5
|
+
class << self
|
6
|
+
def call(delivery:)
|
7
|
+
delivery.set_sent!
|
8
|
+
notify_websocket(delivery: delivery)
|
9
|
+
end
|
10
|
+
|
11
|
+
private
|
12
|
+
|
13
|
+
def notify_websocket(delivery:)
|
14
|
+
return unless Rails.application.config.marty.enable_action_cable
|
15
|
+
|
16
|
+
unread_notifications_count = delivery.recipient&.unread_web_notifications_count
|
17
|
+
|
18
|
+
ActionCable.server.broadcast(
|
19
|
+
"marty_notifications_#{delivery.recipient_id}",
|
20
|
+
unread_notifications_count: unread_notifications_count
|
21
|
+
)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Marty::Promises
|
2
|
+
module Cancel
|
3
|
+
class << self
|
4
|
+
def call(id)
|
5
|
+
ids = get_all_ids(id)
|
6
|
+
promises = Marty::Promise.where(id: ids)
|
7
|
+
jobids = promises.map(&:job_id).compact.sort
|
8
|
+
Delayed::Job.where(id: jobids).destroy_all
|
9
|
+
promises.each do |p|
|
10
|
+
p.update!(status: false,
|
11
|
+
end_dt: p.end_dt || Time.zone.now,
|
12
|
+
result: p.result + { error: 'Cancelled' })
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
# Promises are nodes/leaves on a tree. Given a promise id
|
19
|
+
# from anywhere on the tree, find the ids of all promises
|
20
|
+
# on that tree.
|
21
|
+
def get_all_ids(id)
|
22
|
+
get_base = lambda do |pid|
|
23
|
+
p = Marty::Promise.find_by(id: pid)
|
24
|
+
p.parent_id ? get_base.call(p.parent_id) : pid
|
25
|
+
end
|
26
|
+
base_id = get_base.call(id)
|
27
|
+
get_children = lambda do |pid|
|
28
|
+
children = Marty::Promise.where(parent_id: pid).pluck(:id)
|
29
|
+
children.present? ?
|
30
|
+
(children + children.map { |cid| get_children.call(cid) }).flatten :
|
31
|
+
children
|
32
|
+
end
|
33
|
+
[base_id] + get_children.call(base_id)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -15,9 +15,13 @@ module Marty
|
|
15
15
|
pid = promise_params[:_parent_id]
|
16
16
|
if pid
|
17
17
|
ppr = Marty::Promise.find_by(id: pid)
|
18
|
+
# make sure parent isn't cancelled
|
19
|
+
return if ppr&.result&.[]('error') == 'Cancelled'
|
20
|
+
|
18
21
|
default_priority = ppr.priority if ppr
|
19
22
|
end
|
20
23
|
priority = promise_params['p_priority'] || default_priority
|
24
|
+
|
21
25
|
promise = Marty::Promise.create(
|
22
26
|
title: title,
|
23
27
|
user_id: promise_params[:_user_id],
|
@@ -15,10 +15,13 @@ module Marty
|
|
15
15
|
pid = promise_params[:_parent_id]
|
16
16
|
if pid
|
17
17
|
ppr = Marty::Promise.find_by(id: pid)
|
18
|
+
# make sure parent isn't cancelled
|
19
|
+
return if ppr&.result&.[]('error') == 'Cancelled'
|
20
|
+
|
18
21
|
default_priority = ppr.priority if ppr
|
19
22
|
end
|
20
|
-
|
21
23
|
priority = promise_params['p_priority'] || default_priority
|
24
|
+
|
22
25
|
promise = Marty::Promise.create(
|
23
26
|
title: title,
|
24
27
|
user_id: promise_params[:_user_id],
|
@@ -1,5 +1,9 @@
|
|
1
1
|
<!DOCTYPE html>
|
2
2
|
<html>
|
3
|
+
<% if cookies[:dark_mode] == 'true' %>
|
4
|
+
<%= stylesheet_link_tag 'marty/dark_mode', media: 'all', 'data-turbolinks-track': 'reload' %>
|
5
|
+
<% end %>
|
6
|
+
|
3
7
|
<head>
|
4
8
|
<title><%=Rails.application.class.parent_name%> Diagnostic</title>
|
5
9
|
<style type="text/css">
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class CreateMartyNotificationsEventTypes < ActiveRecord::Migration[4.2]
|
2
|
+
def up
|
3
|
+
values = ::Marty::Notifications::EventType::VALUES
|
4
|
+
str_values = values.map {|v| ActiveRecord::Base.connection.quote v}.join ','
|
5
|
+
|
6
|
+
execute <<-SQL
|
7
|
+
CREATE TYPE marty_notifications_event_types AS ENUM (#{str_values});
|
8
|
+
SQL
|
9
|
+
end
|
10
|
+
|
11
|
+
def down
|
12
|
+
execute <<-SQL
|
13
|
+
DROP TYPE marty_notifications_event_types;
|
14
|
+
SQL
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class CreateMartyNotifications < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :marty_notifications do |t|
|
4
|
+
t.pg_enum :event_type, enum: :marty_notifications_event_types, null: false
|
5
|
+
t.string :state, null: false
|
6
|
+
t.text :text, null: false
|
7
|
+
|
8
|
+
t.timestamps null: false
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class CreateMartyNotificationsDeliveries < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :marty_notifications_deliveries do |t|
|
4
|
+
t.integer :notification_id, null: false
|
5
|
+
t.integer :recipient_id
|
6
|
+
t.string :delivery_type, null: false
|
7
|
+
t.string :state, null: false
|
8
|
+
t.text :text, null: false, default: ''
|
9
|
+
t.string :error_text, null: false, default: ''
|
10
|
+
|
11
|
+
t.timestamps null: false
|
12
|
+
end
|
13
|
+
|
14
|
+
add_foreign_key :marty_notifications_deliveries, :marty_notifications,
|
15
|
+
column: :notification_id, on_delete: :cascade
|
16
|
+
add_foreign_key :marty_notifications_deliveries, :marty_users,
|
17
|
+
column: :recipient_id, on_delete: :nullify
|
18
|
+
|
19
|
+
add_index :marty_notifications_deliveries, [:notification_id, :recipient_id, :delivery_type],
|
20
|
+
unique: true, name: :index_marty_notifications_deliveries_on_n_id_r_id_and_type
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateMartyNotificationsConfig < ActiveRecord::Migration[4.2]
|
2
|
+
def change
|
3
|
+
create_table :marty_notifications_configs do |t|
|
4
|
+
t.pg_enum :event_type, enum: :marty_notifications_event_types, null: false
|
5
|
+
t.integer :recipient_id
|
6
|
+
t.string :delivery_type, null: false
|
7
|
+
t.string :state, null: false
|
8
|
+
t.text :text, null: false, default: ''
|
9
|
+
|
10
|
+
t.timestamps null: false
|
11
|
+
end
|
12
|
+
|
13
|
+
add_foreign_key :marty_notifications_configs, :marty_users,
|
14
|
+
column: :recipient_id, on_delete: :nullify
|
15
|
+
|
16
|
+
add_index :marty_notifications_configs,
|
17
|
+
[:event_type, :recipient_id, :delivery_type],
|
18
|
+
unique: true,
|
19
|
+
name: :index_marty_notifications_configs_on_event_recipient_delivery
|
20
|
+
end
|
21
|
+
end
|
@@ -37,7 +37,7 @@ DECLARE
|
|
37
37
|
|
38
38
|
result JSONB;
|
39
39
|
return_json JSONB;
|
40
|
-
|
40
|
+
|
41
41
|
error_extra JSONB;
|
42
42
|
|
43
43
|
target RECORD;
|
@@ -58,7 +58,7 @@ BEGIN
|
|
58
58
|
END IF;
|
59
59
|
END LOOP;
|
60
60
|
|
61
|
-
FOREACH direction IN ARRAY directions LOOP
|
61
|
+
FOREACH direction IN ARRAY directions LOOP
|
62
62
|
|
63
63
|
IF direction = 'h' THEN
|
64
64
|
data_grid_metadata_current := data_grid_metadata_h;
|
@@ -89,7 +89,7 @@ BEGIN
|
|
89
89
|
|
90
90
|
query_index_result := empty_jsonb_array;
|
91
91
|
|
92
|
-
-- execute the SQL query that has been received before and
|
92
|
+
-- execute the SQL query that has been received before and
|
93
93
|
-- add it's (possibly multiplt) results to query_index_result variable
|
94
94
|
FOR target IN EXECUTE query_dir_result ->> 0 USING query_dir_result -> 1 LOOP
|
95
95
|
query_index_result := query_index_result || to_jsonb(target.index);
|
@@ -105,7 +105,7 @@ BEGIN
|
|
105
105
|
END IF;
|
106
106
|
|
107
107
|
|
108
|
-
IF dis AND jsonb_array_length(query_index_result) > 1 THEN
|
108
|
+
IF dis AND jsonb_array_length(query_index_result) > 1 THEN
|
109
109
|
RAISE EXCEPTION 'matches > 1';
|
110
110
|
END IF;
|
111
111
|
|
@@ -114,7 +114,7 @@ BEGIN
|
|
114
114
|
vertical_indexes := COALESCE(vertical_indexes, empty_jsonb_array);
|
115
115
|
horizontal_indexes := COALESCE(horizontal_indexes, empty_jsonb_array);
|
116
116
|
|
117
|
-
IF ((jsonb_array_length(vertical_indexes)) = 0
|
117
|
+
IF ((jsonb_array_length(vertical_indexes)) = 0
|
118
118
|
OR (jsonb_array_length(horizontal_indexes)) = 0)
|
119
119
|
AND NOT data_grid_lenient
|
120
120
|
AND NOT return_grid_data THEN
|
@@ -140,7 +140,7 @@ BEGIN
|
|
140
140
|
result := data_grid_data -> vertical_index -> horizontal_index;
|
141
141
|
END IF;
|
142
142
|
|
143
|
-
IF NOT return_grid_data THEN
|
143
|
+
IF NOT return_grid_data THEN
|
144
144
|
data_grid_data := NULL;
|
145
145
|
data_grid_metadata := NULL;
|
146
146
|
END IF;
|
data/lib/marty.rb
CHANGED
@@ -7,6 +7,7 @@
|
|
7
7
|
|
8
8
|
# Also note that anything required here will need to require in any
|
9
9
|
# classes that they might be overriding methods in
|
10
|
+
require 'action_cable/engine'
|
10
11
|
|
11
12
|
require 'marty/engine'
|
12
13
|
require 'marty/railtie'
|
@@ -22,6 +23,7 @@ require 'marty/rails_app'
|
|
22
23
|
# to the Gemfile
|
23
24
|
require 'net-ldap'
|
24
25
|
require 'delayed_cron_job'
|
26
|
+
require 'state_machines-activerecord'
|
25
27
|
|
26
28
|
require 'pathname'
|
27
29
|
|
@@ -1,30 +1,40 @@
|
|
1
|
-
module Marty::Diagnostic
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
1
|
+
module Marty::Diagnostic
|
2
|
+
class Version < Base
|
3
|
+
diagnostic_fn do
|
4
|
+
begin
|
5
|
+
submodules = `cd #{Rails.root}; git submodule`.split("\n").map do |s|
|
6
|
+
sha, path, tag = s.split
|
7
|
+
name = File.basename(path)
|
8
|
+
{
|
9
|
+
"#{name}_sha".titleize => sha[0..7],
|
10
|
+
"#{name}_tag".titleize => tag,
|
11
|
+
}
|
12
|
+
end.reduce(&:merge) || {}
|
13
|
+
|
14
|
+
git_tag = `cd #{Rails.root}; git describe --tags --always;`.strip
|
15
|
+
git = { 'Root Git' => git_tag }.merge(submodules)
|
16
|
+
rescue StandardError
|
17
|
+
git = { 'Root Git' => error('Failed accessing git') }
|
18
|
+
end
|
19
|
+
rbv = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"
|
20
|
+
{
|
21
|
+
'Marty' => Marty::VERSION,
|
22
|
+
'Delorean' => Delorean::VERSION,
|
23
|
+
'Mcfly' => Mcfly::VERSION,
|
24
|
+
'Rails' => Rails.version,
|
25
|
+
'Netzke Core' => Netzke::Core::VERSION,
|
26
|
+
'Netzke Basepack' => Netzke::Basepack::VERSION,
|
27
|
+
'Ruby' => rbv,
|
28
|
+
'RubyGems' => Gem::VERSION,
|
29
|
+
'Database Schema Version' => db_schema,
|
30
|
+
'Environment' => Rails.env,
|
31
|
+
}.merge(git)
|
7
32
|
end
|
8
|
-
rbv = "#{RUBY_VERSION}-p#{RUBY_PATCHLEVEL} (#{RUBY_PLATFORM})"
|
9
|
-
{
|
10
|
-
'Marty' => Marty::VERSION,
|
11
|
-
'Delorean' => Delorean::VERSION,
|
12
|
-
'Mcfly' => Mcfly::VERSION,
|
13
|
-
'Git' => message,
|
14
|
-
'Rails' => Rails.version,
|
15
|
-
'Netzke Core' => Netzke::Core::VERSION,
|
16
|
-
'Netzke Basepack' => Netzke::Basepack::VERSION,
|
17
|
-
'Ruby' => rbv,
|
18
|
-
'RubyGems' => Gem::VERSION,
|
19
|
-
'Database Schema Version' => db_schema,
|
20
|
-
'Environment' => Rails.env,
|
21
|
-
}
|
22
|
-
end
|
23
33
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
34
|
+
def self.db_schema
|
35
|
+
Database.db_schema
|
36
|
+
rescue StandardError => e
|
37
|
+
error(e.message)
|
38
|
+
end
|
28
39
|
end
|
29
40
|
end
|
30
|
-
end
|