close_encounters 0.1.3 → 0.2.1

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: ad2eb14acac02e5a5795ffd9508b0bb7dd19987265e398bcdbb73fe48ff42407
4
- data.tar.gz: 123e788ca23010056255b21bc9a71a4fd27e4bdd1e340586b22147f8fe10e8cb
3
+ metadata.gz: e7c56a469fc69cd3a15c93f84ac6a3789415a41d8499df1ea2fd28f5f1aeb07b
4
+ data.tar.gz: 8e0b47517ce53491205e3a89c65a56347bed80473e7cb7ac0cec908aaddd06d8
5
5
  SHA512:
6
- metadata.gz: fdf6130ae5170dc17f1af37cc16e7405c334b722d0ced759c8012782a1b314a73a518886bbd5f7d9199384097bf8554373379da16cb0a92dea781190095ff028
7
- data.tar.gz: a652c2aaa5215275695811da24003816689a19de14407ba053186ef7c007f9825010d5053b00e2cd9421b6399f74f4b44d7255994ee22bab98f57056f360a897
6
+ metadata.gz: a376bbdf0a61509ec060f2624a97498493decb68f7f5655eae922e2980c802378e6c3550fff069dd7d9582cf3c3923befed034bfaa1e735d83375dcbe0156cdb
7
+ data.tar.gz: 5af33cc8325f9db5f3a8a5db639049e02509111c83c096f046c1248114e85ede0b743e69fa2f5f4eba57de998c8192ad592c5d91e39c82006c0dbe17e51014d4
data/CHANGELOG.md CHANGED
@@ -5,24 +5,24 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
6
6
  and this project adheres to [Semantic Versioning](http://semver.org/).
7
7
 
8
- ## [0.1.3] - 2024-07-11
8
+ ## [0.2.1] - 2025-03-05
9
9
 
10
- ## [] -
11
-
12
- ###
10
+ ### Added
13
11
 
14
- - [] -
12
+ - Add alias for verify method as scan.
13
+ - Add configuration for auto_contact and verify_scan_statuses.
15
14
 
16
- ### Removed
15
+ ### Changed
17
16
 
18
- - Remove serialize connection_info for manual methods
17
+ - Ensure that events are only created if the status has changed or if the status is in the verify_scan_statuses list and verification fails.
19
18
 
20
- ## [0.1.2] - 2024-07-11
19
+ ## [0.2.0] - 2025-02-26
21
20
 
22
- ### Added
21
+ ### Changed
23
22
 
24
- - Check if the table exits before conditionally setting up the serialize column
23
+ - Test with Ruby 3.4
25
24
 
26
- ### Removed
25
+ ### Added
27
26
 
28
- - Appending engine migrations to the main app's migration path
27
+ - Ability to use CloseEncounters::Middleware and CloseEncounters.auto_contact! to automatically track responses from third-party services.
28
+ - Add metadata to events for storing extra information about the event.
data/README.md CHANGED
@@ -27,6 +27,23 @@ CloseEncounters.status("SomeThirdPartyService") # => 200
27
27
  CloseEncounters.status("SomeThirdPartyService") # => 500
28
28
  ```
29
29
 
30
+ ### Rack Middleware
31
+
32
+ Setup your middleware in your `config/application.rb` or `config/environments/production.rb`.
33
+
34
+ ```ruby
35
+ config.middleware.use CloseEncounters::Middleware
36
+ ```
37
+
38
+ This will automatically track responses from third-party services when you store a "domain" key in the
39
+ `connection_info` in the ParticipantService records.
40
+
41
+ Alternatively, you can use the `auto_contact!` method to automatically turn on the rack middleware:
42
+
43
+ ```ruby
44
+ CloseEncounters.auto_contact!
45
+ ```
46
+
30
47
  ### TODO
31
48
 
32
49
  - [ ] Add JS to the gem to track events on the front-end.
@@ -6,5 +6,13 @@ module CloseEncounters
6
6
  foreign_key: "close_encounters_participant_service_id"
7
7
 
8
8
  scope :newest, -> { order(created_at: :desc).limit(1) }
9
+
10
+ unless ActiveRecord::Base.connection.adapter_name.downcase.include?("postgresql")
11
+ serialize :metadata, coder: JSON
12
+ end
13
+
14
+ def verified?
15
+ !!metadata.to_h.dig("verified")
16
+ end
9
17
  end
10
18
  end
@@ -0,0 +1,9 @@
1
+ class AddMetadataToCloseEncountersParticipantEvents < ActiveRecord::Migration[7.1]
2
+ def change
3
+ if ActiveRecord::Base.connection.adapter_name.downcase.include?("postgresql")
4
+ add_column :close_encounters_participant_events, :metadata, :jsonb
5
+ else
6
+ add_column :close_encounters_participant_events, :metadata, :text
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,4 @@
1
+ require_relative "middleware"
1
2
  module CloseEncounters
2
3
  class Engine < ::Rails::Engine
3
4
  isolate_namespace CloseEncounters
@@ -6,6 +7,10 @@ module CloseEncounters
6
7
  g.test_framework :minitest, spec: true
7
8
  end
8
9
 
10
+ initializer "close_encounters.middleware" do |app|
11
+ app.middleware.use CloseEncounters::Middleware if CloseEncounters.auto_contact?
12
+ end
13
+
9
14
  if defined?(Importmap)
10
15
  initializer "close_encounters.importmap", before: "importmap" do |app|
11
16
  app.config.importmap.paths << root.join("config/importmap.rb")
@@ -0,0 +1,31 @@
1
+ module CloseEncounters
2
+ class Middleware
3
+ def initialize(app, tracker: CloseEncounters)
4
+ @app = app
5
+ @tracker = tracker
6
+ end
7
+
8
+ def call(env)
9
+ status, headers, response = @app.call(env)
10
+
11
+ record_contact(env["SERVER_NAME"], status, response)
12
+
13
+ [status, headers, response]
14
+ end
15
+
16
+ private
17
+
18
+ def record_contact(host, status, response)
19
+ if (name = participant_services[host])
20
+ @tracker.contact(name, status:, response:)
21
+ end
22
+ end
23
+
24
+ def participant_services
25
+ @participant_services ||= CloseEncounters::ParticipantService.all
26
+ .map do |service|
27
+ [service.connection_info["domain"], service.name]
28
+ end.to_h
29
+ end
30
+ end
31
+ end
@@ -1,3 +1,3 @@
1
1
  module CloseEncounters
2
- VERSION = "0.1.3"
2
+ VERSION = "0.2.1"
3
3
  end
@@ -7,6 +7,23 @@ module CloseEncounters
7
7
  autoload :ParticipantService, "close_encounters/participant_service"
8
8
  autoload :ParticipantEvent, "close_encounters/participant_event"
9
9
 
10
+ class Configuration
11
+ attr_accessor :auto_contact, :verify_scan_statuses
12
+
13
+ def initialize
14
+ @auto_contact = !!ENV["CLOSE_ENCOUNTERS_AUTO_CONTACT"]
15
+ @verify_scan_statuses = [200, 201]
16
+ end
17
+ end
18
+
19
+ def self.configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def self.configure
24
+ yield(configuration)
25
+ end
26
+
10
27
  # Record a contact with a third party service if the status has changed
11
28
  #
12
29
  # @param name [String] the name of the service
@@ -19,6 +36,54 @@ module CloseEncounters
19
36
  end
20
37
  end
21
38
 
39
+ # Record a verification of a contact with a third party service where the
40
+ # verification is a callable which must also respond to to_s.
41
+ #
42
+ # Creates a new event if:
43
+ # 1. The status has changed from the last recorded status
44
+ # 2. OR the status is in the verify_scan list AND verification fails
45
+ #
46
+ # @param name [String] the name of the service
47
+ # @param status [Integer] the HTTP status of the contact
48
+ # @param response [String] the response object
49
+ # @param verifier [Proc] the verification callable which must also respond to to_s
50
+ def scan(name, status:, response:, verifier:)
51
+ service = ParticipantService.find_by!(name:)
52
+ last_status = service.events.newest.pick(:status)
53
+
54
+ if last_status != status
55
+ verified = verifier.call(response)
56
+ service.events.create!(status:, response:, metadata: {verified:, verification: verifier.to_s})
57
+ elsif verify_scan_statuses.include?(status)
58
+ verified = verifier.call(response)
59
+ service.events.create!(status:, response:, metadata: {verified:, verification: verifier.to_s}) if !verified
60
+ end
61
+ end
62
+ alias_method :verify, :scan
63
+ module_function :verify
64
+
65
+ # Determine if contacts with third party services should be recorded automatically
66
+ # using the Rack Middleware
67
+ #
68
+ # Set the CLOSE_ENCOUNTERS_AUTO_CONTACT environment variable to enable this feature
69
+ # or call CloseEncounters.auto_contact! in an initializer
70
+ #
71
+ # @return [Boolean] whether or not to automatically record contacts
72
+ def auto_contact?
73
+ # If auto_contact is explicitly set, use that value
74
+ return configuration.auto_contact unless configuration.auto_contact.nil?
75
+ # Otherwise check the environment variable
76
+ !!ENV["CLOSE_ENCOUNTERS_AUTO_CONTACT"]
77
+ end
78
+
79
+ # Enable automatic contact recording in the Rack Middleware
80
+ def auto_contact!
81
+ configuration.auto_contact = true
82
+ end
83
+
84
+ # Get the statuses that should be verified
85
+ def verify_scan_statuses = configuration.verify_scan_statuses
86
+
22
87
  # Get the status of the most recent contact with a third party service
23
88
  #
24
89
  # @param name [String] the name of the service
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: close_encounters
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jim Gay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-07-11 00:00:00.000000000 Z
11
+ date: 2025-03-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: railties
@@ -112,13 +112,14 @@ files:
112
112
  - app/models/close_encounters/application_record.rb
113
113
  - app/models/close_encounters/participant_event.rb
114
114
  - app/models/close_encounters/participant_service.rb
115
- - app/views/layouts/close_encounters/application.html.erb
116
115
  - config/importmap.rb
117
116
  - db/migrate/20240430173723_create_close_encounters_participant_services.rb
118
117
  - db/migrate/20240430173725_create_close_encounters_participant_events.rb
119
118
  - db/migrate/20240508190642_add_close_ecounters_indexes.rb
119
+ - db/migrate/20250225232551_add_metadata_to_close_encounters_participant_events.rb
120
120
  - lib/close_encounters.rb
121
121
  - lib/close_encounters/engine.rb
122
+ - lib/close_encounters/middleware.rb
122
123
  - lib/close_encounters/version.rb
123
124
  - lib/tasks/close_encounters.rake
124
125
  homepage: https://github.com/SOFware/close_encounters
@@ -1,15 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Close encounters</title>
5
- <%= csrf_meta_tags %>
6
- <%= csp_meta_tag %>
7
-
8
- <%= stylesheet_link_tag "close_encounters/application", media: "all" %>
9
- </head>
10
- <body>
11
-
12
- <%= yield %>
13
-
14
- </body>
15
- </html>