motor-admin 0.1.39 → 0.1.40

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2e0ab742c32ae1b59bfa12c6eb1f838e5d379cb5a964521fe7f345de5fabf953
4
- data.tar.gz: 9f018c3475ae06b4104e35f30774c80b2098a8a23b7fa3a8e4ac35df089ee98e
3
+ metadata.gz: c650dcb3b3585c6776bb7ece77590fe9e69e5c64323dfa7827870f11203afe09
4
+ data.tar.gz: 4e9e8e62612c93686c1c5ed2532b14a260e44078830302f7155e49a45a0b6a66
5
5
  SHA512:
6
- metadata.gz: '0651978240824b17dc1f379047faf9f5c5a393b9bebe6e37ae692a606630a300454a2c56c88173383defef451787555006d355fe26c2dd38173f0ece03e116a0'
7
- data.tar.gz: b15c006847a5c9dcea315741ccc3a46e3a2bba49ab05d2aceab44c75a530ba0f5fad79067aae0b8e31abad9cda105a827cbdb892d93fd1c2c1fe72a2f62a8637
6
+ metadata.gz: a8325df21f414fc4dfb5e61173ca94312662012d3a3ba12cb128a6c7c91d88b0cc97bfb344d8466500f43fd28bc6c3195eaa662e11ddb4c3333fbe1257611ad2
7
+ data.tar.gz: 787be19b2a2407237060341ff623e20f40a86fc5a76ce075e75c1dd62fbede8bbd94dd7a0312072cd60af12571c9dcf7edf2afe7e088e6c75267893156cd8482
@@ -7,8 +7,8 @@ module Motor
7
7
  belongs_to :query
8
8
  belongs_to :author, polymorphic: true, optional: true
9
9
 
10
- has_many :alert_locks
11
- has_many :taggable_tags, as: :taggable
10
+ has_many :alert_locks, dependent: :destroy
11
+ has_many :taggable_tags, as: :taggable, dependent: :destroy
12
12
  has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
13
13
 
14
14
  serialize :preferences, HashSerializer
@@ -6,7 +6,7 @@ module Motor
6
6
 
7
7
  belongs_to :author, polymorphic: true, optional: true
8
8
 
9
- has_many :taggable_tags, as: :taggable
9
+ has_many :taggable_tags, as: :taggable, dependent: :destroy
10
10
  has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
11
11
 
12
12
  serialize :preferences, HashSerializer
@@ -6,7 +6,7 @@ module Motor
6
6
 
7
7
  belongs_to :author, polymorphic: true, optional: true
8
8
 
9
- has_many :taggable_tags, as: :taggable
9
+ has_many :taggable_tags, as: :taggable, dependent: :destroy
10
10
  has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
11
11
 
12
12
  serialize :preferences, HashSerializer
@@ -6,8 +6,9 @@ module Motor
6
6
 
7
7
  belongs_to :author, polymorphic: true, optional: true
8
8
 
9
- has_many :taggable_tags, as: :taggable
9
+ has_many :taggable_tags, as: :taggable, dependent: :destroy
10
10
  has_many :tags, through: :taggable_tags, class_name: 'Motor::Tag'
11
+ has_many :alerts, dependent: :destroy
11
12
 
12
13
  serialize :preferences, HashSerializer
13
14
 
data/lib/motor/admin.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'motor/configs/sync_middleware'
4
-
5
3
  module Motor
6
4
  class Admin < ::Rails::Engine
7
5
  initializer 'motor.startup_message' do
@@ -31,9 +29,11 @@ module Motor
31
29
  end
32
30
 
33
31
  initializer 'motor.configs.sync_middleware' do
34
- if Motor::Configs::SyncMiddleware::ACCESS_KEY.present?
35
- Rails.application.config.middleware.insert_before(0, Motor::Configs::SyncMiddleware)
36
- end
32
+ next if Motor::Configs::SYNC_ACCESS_KEY.blank?
33
+
34
+ require 'motor/configs/sync_middleware'
35
+
36
+ Rails.application.config.middleware.insert_after(Rails::Rack::Logger, Motor::Configs::SyncMiddleware)
37
37
  end
38
38
 
39
39
  initializer 'motor.filter_params' do
@@ -43,25 +43,31 @@ module Motor
43
43
  retry
44
44
  end
45
45
 
46
- def update_from_params!(alert, params)
46
+ def update_from_params!(alert, params, force_replace: false)
47
47
  tag_ids = alert.tags.ids
48
48
 
49
49
  alert = assign_attributes(alert, params)
50
50
 
51
- raise NameAlreadyExists if name_already_exists?(alert)
51
+ raise NameAlreadyExists if !force_replace && name_already_exists?(alert)
52
52
  raise InvalidInterval unless alert.cron
53
53
 
54
54
  ApplicationRecord.transaction do
55
+ archive_with_existing_name(alert) if force_replace
56
+
55
57
  alert.save!
56
58
  end
57
59
 
58
- alert.touch if tag_ids.sort != alert.tags.reload.ids.sort && params[:updated_at].blank?
60
+ alert.touch if tags_changed?(tag_ids, alert) && params[:updated_at].blank?
59
61
 
60
62
  alert
61
63
  rescue ActiveRecord::RecordNotUnique
62
64
  retry
63
65
  end
64
66
 
67
+ def tags_changed?(previous_ids, alert)
68
+ previous_ids.sort != alert.tags.reload.ids.sort
69
+ end
70
+
65
71
  def assign_attributes(alert, params)
66
72
  alert.assign_attributes(params.slice(*ALERT_ATTRIBUTES))
67
73
  alert.preferences[:interval] = normalize_interval(alert.preferences[:interval])
@@ -70,6 +76,11 @@ module Motor
70
76
  Motor::Tags.assign_tags(alert, params[:tags])
71
77
  end
72
78
 
79
+ def archive_with_existing_name(alert)
80
+ Motor::Alert.where(['lower(name) = ? AND id != ?', alert.name.to_s.downcase, alert.id])
81
+ .update_all(deleted_at: Time.current)
82
+ end
83
+
73
84
  def normalize_interval(interval)
74
85
  interval.to_s.gsub(NORMALIZE_INTERVAL_REGEXP, 'every ')
75
86
  end
data/lib/motor/configs.rb CHANGED
@@ -4,6 +4,7 @@ module Motor
4
4
  module Configs
5
5
  FILE_PATH = 'config/motor.yml'
6
6
  SYNC_API_PATH = '/motor_configs_sync'
7
+ SYNC_ACCESS_KEY = ENV.fetch('MOTOR_SYNC_API_KEY', '')
7
8
  end
8
9
  end
9
10
 
@@ -9,7 +9,7 @@ module Motor
9
9
 
10
10
  module_function
11
11
 
12
- def call
12
+ def call(with_exception: false)
13
13
  MUTEXT.synchronize do
14
14
  file = Rails.root.join(FILE_PATH)
15
15
 
@@ -17,6 +17,8 @@ module Motor
17
17
  begin
18
18
  file.ctime
19
19
  rescue Errno::ENOENT
20
+ raise if with_exception
21
+
20
22
  nil
21
23
  end
22
24
 
@@ -100,7 +100,7 @@ module Motor
100
100
 
101
101
  next if record.updated_at >= attrs[:updated_at]
102
102
 
103
- update_proc.call(record, attrs)
103
+ update_proc.call(record, attrs, force_replace: true)
104
104
  end
105
105
  end
106
106
 
@@ -108,7 +108,7 @@ module Motor
108
108
  create_items.each do |attrs|
109
109
  record = records_class.find_or_initialize_by(id: attrs[:id]).tap { |e| e.deleted_at = nil }
110
110
 
111
- update_proc.call(record, attrs)
111
+ update_proc.call(record, attrs, force_replace: true)
112
112
  end
113
113
  end
114
114
 
@@ -3,8 +3,6 @@
3
3
  module Motor
4
4
  module Configs
5
5
  class SyncMiddleware
6
- ACCESS_KEY = ENV.fetch('MOTOR_SYNC_API_KEY', '')
7
-
8
6
  KeyNotSpecified = Class.new(StandardError)
9
7
  NotAuthenticated = Class.new(StandardError)
10
8
 
@@ -14,13 +12,15 @@ module Motor
14
12
 
15
13
  def call(env)
16
14
  if env['PATH_INFO'] == Motor::Configs::SYNC_API_PATH
17
- authenticate!(env['QUERY_STRING'])
15
+ authenticate!(env['HTTP_X_AUTHORIZATION'])
18
16
 
19
17
  case env['REQUEST_METHOD']
20
18
  when 'GET'
21
19
  respond_with_configs
22
20
  when 'POST'
23
- sync_configs(env['rack.input'].read)
21
+ input = env['rack.input']
22
+ input.rewind
23
+ sync_configs(input.read)
24
24
  else
25
25
  @app.call(env)
26
26
  end
@@ -35,14 +35,14 @@ module Motor
35
35
 
36
36
  private
37
37
 
38
- def authenticate!(query_string)
39
- raise KeyNotSpecified if ACCESS_KEY.blank?
40
- raise NotAuthenticated if query_string.blank?
38
+ def authenticate!(token)
39
+ raise KeyNotSpecified if Motor::Configs::SYNC_ACCESS_KEY.blank?
40
+ raise NotAuthenticated if token.blank?
41
41
 
42
42
  is_token_valid =
43
43
  ActiveSupport::SecurityUtils.secure_compare(
44
- Digest::SHA256.hexdigest(query_string),
45
- Digest::SHA256.hexdigest("token=#{ACCESS_KEY}")
44
+ Digest::SHA256.hexdigest(token),
45
+ Digest::SHA256.hexdigest(Motor::Configs::SYNC_ACCESS_KEY)
46
46
  )
47
47
 
48
48
  raise NotAuthenticated unless is_token_valid
@@ -16,7 +16,7 @@ module Motor
16
16
  end
17
17
 
18
18
  def sync_from_remote!(remote_url, api_key)
19
- response = Motor::NetHttpUtils.get(remote_url, { token: api_key })
19
+ response = Motor::NetHttpUtils.get(remote_url, {}, { 'X-Authorization' => api_key })
20
20
 
21
21
  raise ApiNotFound if response.is_a?(Net::HTTPNotFound)
22
22
  raise UnableToSync, [response.message, response.body].join(': ') unless response.is_a?(Net::HTTPSuccess)
@@ -29,7 +29,15 @@ module Motor
29
29
  def sync_to_remote!(remote_url, api_key)
30
30
  configs_hash = Motor::Configs::BuildConfigsHash.call
31
31
 
32
- response = Motor::NetHttpUtils.post(remote_url, { token: api_key }, configs_hash.to_json)
32
+ response = Motor::NetHttpUtils.post(
33
+ remote_url,
34
+ {},
35
+ {
36
+ 'X-Authorization' => api_key,
37
+ 'Content-Type' => 'application/json'
38
+ },
39
+ configs_hash.to_json
40
+ )
33
41
 
34
42
  raise ApiNotFound if response.is_a?(Net::HTTPNotFound)
35
43
  raise UnableToSync, [response.message, response.body].join(': ') unless response.is_a?(Net::HTTPSuccess)
@@ -29,14 +29,16 @@ module Motor
29
29
  retry
30
30
  end
31
31
 
32
- def update_from_params!(dashboard, params)
32
+ def update_from_params!(dashboard, params, force_replace: false)
33
33
  tag_ids = dashboard.tags.ids
34
34
 
35
35
  dashboard = assign_attributes(dashboard, params)
36
36
 
37
- raise TitleAlreadyExists if title_already_exists?(dashboard)
37
+ raise TitleAlreadyExists if !force_replace && title_already_exists?(dashboard)
38
38
 
39
39
  ApplicationRecord.transaction do
40
+ archive_with_existing_name(dashboard) if force_replace
41
+
40
42
  dashboard.save!
41
43
  end
42
44
 
@@ -54,11 +56,16 @@ module Motor
54
56
  Motor::Tags.assign_tags(dashboard, params[:tags])
55
57
  end
56
58
 
59
+ def archive_with_existing_name(dashboard)
60
+ Motor::Dashboard.where(['lower(title) = ? AND id != ?', dashboard.title.to_s.downcase, dashboard.id])
61
+ .update_all(deleted_at: Time.current)
62
+ end
63
+
57
64
  def title_already_exists?(dashboard)
58
65
  if dashboard.new_record?
59
- Dashboard.exists?(['lower(title) = ?', dashboard.title.to_s.downcase])
66
+ Motor::Dashboard.exists?(['lower(title) = ?', dashboard.title.to_s.downcase])
60
67
  else
61
- Dashboard.exists?(['lower(title) = ? AND id != ?', dashboard.title.to_s.downcase, dashboard.id])
68
+ Motor::Dashboard.exists?(['lower(title) = ? AND id != ?', dashboard.title.to_s.downcase, dashboard.id])
62
69
  end
63
70
  end
64
71
  end
@@ -29,14 +29,16 @@ module Motor
29
29
  retry
30
30
  end
31
31
 
32
- def update_from_params!(form, params)
32
+ def update_from_params!(form, params, force_replace: false)
33
33
  tag_ids = form.tags.ids
34
34
 
35
35
  form = assign_attributes(form, params)
36
36
 
37
- raise NameAlreadyExists if name_already_exists?(form)
37
+ raise NameAlreadyExists if !force_replace && name_already_exists?(form)
38
38
 
39
39
  ApplicationRecord.transaction do
40
+ archive_with_existing_name(form) if force_replace
41
+
40
42
  form.save!
41
43
  end
42
44
 
@@ -54,11 +56,16 @@ module Motor
54
56
  Motor::Tags.assign_tags(form, params[:tags])
55
57
  end
56
58
 
59
+ def archive_with_existing_name(form)
60
+ Motor::Form.where(['lower(name) = ? AND id != ?', form.name.to_s.downcase, form.id])
61
+ .update_all(deleted_at: Time.current)
62
+ end
63
+
57
64
  def name_already_exists?(form)
58
65
  if form.new_record?
59
- Form.exists?(['lower(name) = ?', form.name.to_s.downcase])
66
+ Motor::Form.exists?(['lower(name) = ?', form.name.to_s.downcase])
60
67
  else
61
- Form.exists?(['lower(name) = ? AND id != ?', form.name.to_s.downcase, form.id])
68
+ Motor::Form.exists?(['lower(name) = ? AND id != ?', form.name.to_s.downcase, form.id])
62
69
  end
63
70
  end
64
71
  end
@@ -4,24 +4,25 @@ module Motor
4
4
  module NetHttpUtils
5
5
  module_function
6
6
 
7
- def get(url, params = {})
8
- request = build_request(Net::HTTP::Get, url, params, nil)
7
+ def get(url, params = {}, headers = {})
8
+ request = build_request(Net::HTTP::Get, url, params, headers, nil)
9
9
 
10
10
  execute_request(request)
11
11
  end
12
12
 
13
- def post(url, params = {}, body = '')
14
- request = build_request(Net::HTTP::Post, url, params, body)
13
+ def post(url, params = {}, headers = {}, body = '')
14
+ request = build_request(Net::HTTP::Post, url, params, headers, body)
15
15
 
16
16
  execute_request(request)
17
17
  end
18
18
 
19
- def build_request(method_class, url, params, body)
19
+ def build_request(method_class, url, params, headers, body)
20
20
  uri = URI(url)
21
21
  uri.query = params.to_query
22
22
 
23
23
  request = method_class.new(uri)
24
24
  request.body = body if body.present?
25
+ headers.each { |key, value| request[key] = value }
25
26
 
26
27
  request
27
28
  end
@@ -29,14 +29,16 @@ module Motor
29
29
  retry
30
30
  end
31
31
 
32
- def update_from_params!(query, params)
32
+ def update_from_params!(query, params, force_replace: false)
33
33
  tag_ids = query.tags.ids
34
34
 
35
35
  query = assign_attributes(query, params)
36
36
 
37
- raise NameAlreadyExists if name_already_exists?(query)
37
+ raise NameAlreadyExists if !force_replace && name_already_exists?(query)
38
38
 
39
39
  ApplicationRecord.transaction do
40
+ archive_with_existing_name(query) if force_replace
41
+
40
42
  query.save!
41
43
  end
42
44
 
@@ -54,6 +56,11 @@ module Motor
54
56
  Motor::Tags.assign_tags(query, params[:tags])
55
57
  end
56
58
 
59
+ def archive_with_existing_name(query)
60
+ Motor::Query.where(['lower(name) = ? AND id != ?', query.name.to_s.downcase, query.id])
61
+ .update_all(deleted_at: Time.current)
62
+ end
63
+
57
64
  def name_already_exists?(query)
58
65
  if query.new_record?
59
66
  Query.exists?(['lower(name) = ?', query.name.to_s.downcase])
@@ -9,6 +9,14 @@ namespace :motor do
9
9
  puts '✅ configs/motor.yml has been updated'
10
10
  end
11
11
 
12
+ desc 'Load configs from configs/motor.yml file'
13
+
14
+ task load: :environment do
15
+ Motor::Configs::SyncFromFile.call(with_exception: true)
16
+
17
+ puts '✅ configs have been loaded from configs/motor.yml'
18
+ end
19
+
12
20
  desc 'Synchronize configs with remote application'
13
21
 
14
22
  task sync: :environment do
data/lib/motor/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Motor
4
- VERSION = '0.1.39'
4
+ VERSION = '0.1.40'
5
5
  end
@@ -5,9 +5,9 @@
5
5
  "fonts/ionicons.ttf?v=3.0.0-alpha.3": "fonts/ionicons.ttf",
6
6
  "fonts/ionicons.woff2?v=3.0.0-alpha.3": "fonts/ionicons.woff2",
7
7
  "fonts/ionicons.woff?v=3.0.0-alpha.3": "fonts/ionicons.woff",
8
- "main-e443f49b386b119ff25a.css.gz": "main-e443f49b386b119ff25a.css.gz",
9
- "main-e443f49b386b119ff25a.js.LICENSE.txt": "main-e443f49b386b119ff25a.js.LICENSE.txt",
10
- "main-e443f49b386b119ff25a.js.gz": "main-e443f49b386b119ff25a.js.gz",
11
- "main.css": "main-e443f49b386b119ff25a.css",
12
- "main.js": "main-e443f49b386b119ff25a.js"
8
+ "main-57d82791202293600221.css.gz": "main-57d82791202293600221.css.gz",
9
+ "main-57d82791202293600221.js.LICENSE.txt": "main-57d82791202293600221.js.LICENSE.txt",
10
+ "main-57d82791202293600221.js.gz": "main-57d82791202293600221.js.gz",
11
+ "main.css": "main-57d82791202293600221.css",
12
+ "main.js": "main-57d82791202293600221.js"
13
13
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: motor-admin
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.39
4
+ version: 0.1.40
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pete Matsyburka
@@ -242,8 +242,8 @@ files:
242
242
  - lib/motor/tasks/motor.rake
243
243
  - lib/motor/version.rb
244
244
  - ui/dist/fonts/ionicons.woff2
245
- - ui/dist/main-e443f49b386b119ff25a.css.gz
246
- - ui/dist/main-e443f49b386b119ff25a.js.gz
245
+ - ui/dist/main-57d82791202293600221.css.gz
246
+ - ui/dist/main-57d82791202293600221.js.gz
247
247
  - ui/dist/manifest.json
248
248
  homepage:
249
249
  licenses: