motor-admin 0.1.39 → 0.1.40

Sign up to get free protection for your applications and to get access to all the features.
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: