patch_retention 0.2.2 → 0.3.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 +4 -4
- data/CHANGELOG.md +21 -0
- data/Gemfile.lock +1 -1
- data/README.md +98 -0
- data/lib/patch_retention/calendar_items.rb +86 -0
- data/lib/patch_retention/contacts/find.rb +4 -1
- data/lib/patch_retention/contacts.rb +2 -2
- data/lib/patch_retention/version.rb +1 -1
- data/patch_retention.gemspec +57 -0
- metadata +18 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9642c7116bc29f3cc1e9368c861ac11d13b2357ab778b4f9395fa2bb14c3edb3
|
4
|
+
data.tar.gz: 7dc040049c15f9b32eb83d06a986daa0da1c4c881d1dfd2553dc764d9fbba494
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cd6b62c587f1ad1ed68b579bfcd70403a916de81593248d4850664b4495dc2ff316d279b338952dfb332f038f1c3b63240907345544298becbf14fe749345806
|
7
|
+
data.tar.gz: 82fe4b41064b55979b281ad05e48459ae3230e04d91f32065ecab1bf030e337bc56b791a6786ba09fb6bee7b7ec75a808485b8f986713cb888543248278e43f0
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
## [Unreleased]
|
2
2
|
|
3
|
+
## [0.3.1] - 2025-09-04
|
4
|
+
|
5
|
+
### Added
|
6
|
+
- Added `tags` parameter support to `CalendarItems.create` method for categorizing calendar items
|
7
|
+
- Added `email` parameter to `Contacts.all` method for filtering contacts by email address
|
8
|
+
|
9
|
+
### Changed
|
10
|
+
- **BREAKING**: Updated `Contacts.all` method to use keyword arguments (limit:, offset:, email:, config:) instead of positional arguments
|
11
|
+
|
12
|
+
## [0.3.0] - 2025-07-27
|
13
|
+
|
14
|
+
### Added
|
15
|
+
- Calendar Items API support with full CRUD operations:
|
16
|
+
- `create` - Create calendar events for contacts
|
17
|
+
- `update` - Update existing calendar items
|
18
|
+
- `find` - Retrieve a specific calendar item
|
19
|
+
- `delete` - Remove calendar items
|
20
|
+
- `all` - List calendar items with filtering and pagination support
|
21
|
+
- Support for calendar item metadata including description, location, external_id, external_data, and tags
|
22
|
+
- Comprehensive test coverage for Calendar Items functionality
|
23
|
+
|
3
24
|
## [0.2.0] - 2025-05-26
|
4
25
|
|
5
26
|
### Added
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -118,7 +118,21 @@ Then, you can use the gem's methods to interact with the API.
|
|
118
118
|
To retrieve all contacts:
|
119
119
|
|
120
120
|
```ruby
|
121
|
+
# Basic usage
|
121
122
|
contacts = PatchRetention::Contacts.all
|
123
|
+
|
124
|
+
# With pagination (using keyword arguments)
|
125
|
+
contacts = PatchRetention::Contacts.all(limit: 10, offset: 0)
|
126
|
+
|
127
|
+
# With email filter
|
128
|
+
contacts = PatchRetention::Contacts.all(email: 'john.doe@example.com')
|
129
|
+
|
130
|
+
# With pagination and email filter
|
131
|
+
contacts = PatchRetention::Contacts.all(
|
132
|
+
limit: 50,
|
133
|
+
offset: 0,
|
134
|
+
email: 'john@example.com'
|
135
|
+
)
|
122
136
|
```
|
123
137
|
|
124
138
|
To retrieve a single contact:
|
@@ -290,6 +304,90 @@ To find a membership:
|
|
290
304
|
membership = PatchRetention::Memberships.find(membership_id: "mem_xxxxxxxxxxxxxx")
|
291
305
|
```
|
292
306
|
|
307
|
+
**Calendar Items**
|
308
|
+
|
309
|
+
To create a calendar item:
|
310
|
+
|
311
|
+
```ruby
|
312
|
+
calendar_item = PatchRetention::CalendarItems.create(
|
313
|
+
contact_id: "ct_xxxxxxxxxxxxxx", # Required, ID of the contact
|
314
|
+
title: "Tennis Court Reservation", # Required, title of the event
|
315
|
+
start_at: "2025-02-01T10:00:00Z", # Required, ISO8601 timestamp - when the event starts
|
316
|
+
end_at: "2025-02-01T11:00:00Z", # Required, ISO8601 timestamp - when the event ends
|
317
|
+
run_start_at: "2025-02-01T09:30:00Z", # Optional, ISO8601 - when to run the event for this item (defaults to start_at if not set)
|
318
|
+
run_end_at: "2025-02-01T11:30:00Z", # Optional, ISO8601 - when to run the event for this item (defaults to end_at if not set)
|
319
|
+
data: { # Optional, additional metadata that will be included in the calendar item
|
320
|
+
external_id: "res_123456", # Your system's ID
|
321
|
+
facility_id: "fac_789",
|
322
|
+
court_name: "Court 1",
|
323
|
+
reservation_type: "match"
|
324
|
+
},
|
325
|
+
tags: ["tennis", "premium", "court1"], # Optional, array of tags to categorize the calendar item
|
326
|
+
time_occurred: "2025-01-28T09:00:00Z", # Optional, ISO8601 - past or current time for the event (will default to now)
|
327
|
+
skip_triggers: false # Optional, if set to false or empty, any automation tied to the calendar item will not run
|
328
|
+
)
|
329
|
+
# => {"id"=>"cal_xxxxxxxxxxxxxx", "contact_id"=>"ct_xxxxxxxxxxxxxx", ...}
|
330
|
+
```
|
331
|
+
|
332
|
+
To update a calendar item:
|
333
|
+
|
334
|
+
```ruby
|
335
|
+
calendar_item = PatchRetention::CalendarItems.update(
|
336
|
+
calendar_item_id: "cal_xxxxxxxxxxxxxx",
|
337
|
+
title: "Updated Tennis Match",
|
338
|
+
end_at: "2025-02-01T12:00:00Z", # Extend by 1 hour
|
339
|
+
data: {
|
340
|
+
description: "Match extended due to tie-break"
|
341
|
+
},
|
342
|
+
tags: ["Tennis", "Extended", "Tie-break"] # Tags as separate parameter
|
343
|
+
)
|
344
|
+
```
|
345
|
+
|
346
|
+
To find a calendar item:
|
347
|
+
|
348
|
+
```ruby
|
349
|
+
calendar_item = PatchRetention::CalendarItems.find(calendar_item_id: "cal_xxxxxxxxxxxxxx")
|
350
|
+
```
|
351
|
+
|
352
|
+
To delete a calendar item:
|
353
|
+
|
354
|
+
```ruby
|
355
|
+
result = PatchRetention::CalendarItems.delete(calendar_item_id: "cal_xxxxxxxxxxxxxx")
|
356
|
+
# => { success: true }
|
357
|
+
```
|
358
|
+
|
359
|
+
To list calendar items:
|
360
|
+
|
361
|
+
```ruby
|
362
|
+
# List all calendar items
|
363
|
+
calendar_items = PatchRetention::CalendarItems.all()
|
364
|
+
|
365
|
+
# List calendar items for a specific contact
|
366
|
+
calendar_items = PatchRetention::CalendarItems.all(contact_id: "ct_xxxxxxxxxxxxxx")
|
367
|
+
|
368
|
+
# List calendar items within ID range (MongoDB IDs)
|
369
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
370
|
+
min_id: "0123456789abcdefghijklmn", # Get all items on or after this ID
|
371
|
+
max_id: "0123456789abcdefghijklmn" # Get all items on or before this ID
|
372
|
+
)
|
373
|
+
|
374
|
+
# List specific calendar items by IDs (comma-separated)
|
375
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
376
|
+
id: "0123456789abcdefghijklmn,123456789abcdefghijklmn"
|
377
|
+
)
|
378
|
+
|
379
|
+
# Filter by date range (predefined options)
|
380
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
381
|
+
date_range: "Today" # Options: "Today", "Yesterday", "Last 7 Days", "This Week", "Last Week", "Last 30 Days"
|
382
|
+
)
|
383
|
+
|
384
|
+
# With pagination
|
385
|
+
calendar_items = PatchRetention::CalendarItems.all(
|
386
|
+
limit: 50, # Default is 50, max is 100
|
387
|
+
offset: 25 # Skip first 25 results
|
388
|
+
)
|
389
|
+
```
|
390
|
+
|
293
391
|
## Development
|
294
392
|
|
295
393
|
After checking out the repo, run `bin/setup` to install dependencies.
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PatchRetention
|
4
|
+
class CalendarItems
|
5
|
+
class << self
|
6
|
+
def create(contact_id:, title:, start_at:, end_at:, run_start_at: nil, run_end_at: nil,
|
7
|
+
data: nil, time_occurred: nil, skip_triggers: false, tags: nil, config: nil)
|
8
|
+
payload = {
|
9
|
+
contact_id: contact_id,
|
10
|
+
title: title,
|
11
|
+
start_at: start_at,
|
12
|
+
end_at: end_at,
|
13
|
+
}
|
14
|
+
payload[:run_start_at] = run_start_at if run_start_at
|
15
|
+
payload[:run_end_at] = run_end_at if run_end_at
|
16
|
+
payload[:data] = data if data
|
17
|
+
payload[:time_occurred] = time_occurred if time_occurred
|
18
|
+
payload[:skip_triggers] = skip_triggers unless skip_triggers.nil?
|
19
|
+
payload[:tags] = tags if tags
|
20
|
+
|
21
|
+
response = PatchRetention.connection(config).post("/v2/calendar_items") do |req|
|
22
|
+
req.body = payload.to_json
|
23
|
+
req.headers["Content-Type"] = "application/json"
|
24
|
+
end
|
25
|
+
|
26
|
+
JSON.parse(response.body)
|
27
|
+
rescue Faraday::Error => e
|
28
|
+
raise Error, "Failed to create calendar item: #{e.message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(calendar_item_id:, title: nil, start_at: nil, end_at: nil, run_start_at: nil,
|
32
|
+
run_end_at: nil, data: nil, tags: nil, config: nil)
|
33
|
+
payload = {}
|
34
|
+
payload[:title] = title if title
|
35
|
+
payload[:start_at] = start_at if start_at
|
36
|
+
payload[:end_at] = end_at if end_at
|
37
|
+
payload[:run_start_at] = run_start_at if run_start_at
|
38
|
+
payload[:run_end_at] = run_end_at if run_end_at
|
39
|
+
payload[:data] = data if data
|
40
|
+
payload[:tags] = tags if tags
|
41
|
+
|
42
|
+
response = PatchRetention.connection(config).patch("/v2/calendar_items/#{calendar_item_id}") do |req|
|
43
|
+
req.body = payload.to_json
|
44
|
+
req.headers["Content-Type"] = "application/json"
|
45
|
+
end
|
46
|
+
|
47
|
+
JSON.parse(response.body)
|
48
|
+
rescue Faraday::Error => e
|
49
|
+
raise Error, "Failed to update calendar item: #{e.message}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def find(calendar_item_id:, config: nil)
|
53
|
+
response = PatchRetention.connection(config).get("/v2/calendar_items/#{calendar_item_id}")
|
54
|
+
|
55
|
+
JSON.parse(response.body)
|
56
|
+
rescue Faraday::Error => e
|
57
|
+
raise Error, "Failed to find calendar item: #{e.message}"
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete(calendar_item_id:, config: nil)
|
61
|
+
response = PatchRetention.connection(config).delete("/v2/calendar_items/#{calendar_item_id}")
|
62
|
+
|
63
|
+
{ success: response.status == 204 }
|
64
|
+
rescue Faraday::Error => e
|
65
|
+
raise Error, "Failed to delete calendar item: #{e.message}"
|
66
|
+
end
|
67
|
+
|
68
|
+
def all(contact_id: nil, min_id: nil, max_id: nil, id: nil, date_range: nil, limit: nil, offset: nil, config: nil)
|
69
|
+
params = {}
|
70
|
+
params[:contact_id] = contact_id if contact_id
|
71
|
+
params[:min_id] = min_id if min_id
|
72
|
+
params[:max_id] = max_id if max_id
|
73
|
+
params[:id] = id if id
|
74
|
+
params[:date_range] = date_range if date_range
|
75
|
+
params[:limit] = limit if limit
|
76
|
+
params[:offset] = offset if offset
|
77
|
+
|
78
|
+
response = PatchRetention.connection(config).get("/v2/calendar_items", params)
|
79
|
+
|
80
|
+
JSON.parse(response.body)
|
81
|
+
rescue Faraday::Error => e
|
82
|
+
raise Error, "Failed to retrieve calendar items: #{e.message}"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -29,13 +29,16 @@ module PatchRetention::Contacts::Find
|
|
29
29
|
#
|
30
30
|
# @param limit [Integer] The number of contacts to retrieve per page.
|
31
31
|
# @param offset [Integer] The number of contacts to skip before starting to collect the result set.
|
32
|
+
# @param email [String] Optional email to filter contacts by.
|
33
|
+
# @param config [Configuration] Optional configuration object.
|
32
34
|
# @return [Object] The response from the PatchRetention API.
|
33
35
|
# @raise [PatchRetention::Error] If the API returns a status other than 200.
|
34
|
-
def all(limit
|
36
|
+
def all(limit:, offset:, email: nil, config: nil)
|
35
37
|
raise_error_if_present do
|
36
38
|
PatchRetention.connection(config).get(PatchRetention::Contacts::API_PATH) do |req|
|
37
39
|
req.params["limit"] = limit
|
38
40
|
req.params["offset"] = offset
|
41
|
+
req.params["email"] = email if email
|
39
42
|
end
|
40
43
|
end
|
41
44
|
end
|
@@ -8,8 +8,8 @@ class PatchRetention::Contacts
|
|
8
8
|
Find.by_id(id, config)
|
9
9
|
end
|
10
10
|
|
11
|
-
def all(limit
|
12
|
-
Find.all(limit, offset, config)
|
11
|
+
def all(limit: 30, offset: 0, email: nil, config: nil)
|
12
|
+
Find.all(limit: limit, offset: offset, email: email, config: config)
|
13
13
|
end
|
14
14
|
|
15
15
|
def find_or_create_by(contact_params:, query_params: {}, config: nil)
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/patch_retention/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "patch_retention"
|
7
|
+
spec.version = PatchRetention::VERSION
|
8
|
+
spec.authors = ["Playbypoint", "Gerardo Ortega"]
|
9
|
+
spec.email = ["webmaster@playbypoint.com", "g3ortega@gmail.com"]
|
10
|
+
|
11
|
+
spec.summary = "Patch Retention API wrapper."
|
12
|
+
spec.description = "Patch Retention API wrapper."
|
13
|
+
spec.homepage = "https://playbypoint.com"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 3.1.0"
|
16
|
+
|
17
|
+
# spec.metadata["allowed_push_host"] = "Set to your gem server 'https://example.com'"
|
18
|
+
|
19
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
20
|
+
spec.metadata["source_code_uri"] = "https://playbypoint.com"
|
21
|
+
spec.metadata["changelog_uri"] = "https://playbypoint.com"
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files = Dir.chdir(__dir__) do
|
26
|
+
%x(git ls-files -z).split("\x0").reject do |f|
|
27
|
+
(f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
|
28
|
+
end
|
29
|
+
end
|
30
|
+
spec.bindir = "exe"
|
31
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
32
|
+
spec.require_paths = ["lib"]
|
33
|
+
|
34
|
+
# Runtime dependencies
|
35
|
+
spec.add_dependency("faraday", "~> 1.10")
|
36
|
+
spec.add_dependency("zeitwerk", "~> 2.6")
|
37
|
+
|
38
|
+
# Development dependencies
|
39
|
+
spec.add_development_dependency("bundler", "~> 2.0")
|
40
|
+
spec.add_development_dependency("bundler-audit", "~> 0.9")
|
41
|
+
spec.add_development_dependency("byebug")
|
42
|
+
spec.add_development_dependency("dotenv", "~> 2.8")
|
43
|
+
spec.add_development_dependency("pry")
|
44
|
+
spec.add_development_dependency("rake", "~> 13.0")
|
45
|
+
spec.add_development_dependency("rspec", "~> 3.0")
|
46
|
+
spec.add_development_dependency("rubocop", "~> 1.21")
|
47
|
+
spec.add_development_dependency("rubocop-shopify", "~> 2.15")
|
48
|
+
spec.add_development_dependency("thor", ">= 1.4.0")
|
49
|
+
spec.add_development_dependency("vcr", "~> 6.0")
|
50
|
+
spec.add_development_dependency("webmock", "~> 3.0")
|
51
|
+
|
52
|
+
# Security update for rexml
|
53
|
+
spec.add_development_dependency("rexml", ">= 3.3.9")
|
54
|
+
|
55
|
+
# For more information and examples about making a new gem, check out our
|
56
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
57
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: patch_retention
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Playbypoint
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2025-
|
12
|
+
date: 2025-09-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: faraday
|
@@ -67,20 +67,6 @@ dependencies:
|
|
67
67
|
- - "~>"
|
68
68
|
- !ruby/object:Gem::Version
|
69
69
|
version: '0.9'
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: thor
|
72
|
-
requirement: !ruby/object:Gem::Requirement
|
73
|
-
requirements:
|
74
|
-
- - ">="
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: 1.4.0
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: !ruby/object:Gem::Requirement
|
80
|
-
requirements:
|
81
|
-
- - ">="
|
82
|
-
- !ruby/object:Gem::Version
|
83
|
-
version: 1.4.0
|
84
70
|
- !ruby/object:Gem::Dependency
|
85
71
|
name: byebug
|
86
72
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,6 +165,20 @@ dependencies:
|
|
179
165
|
- - "~>"
|
180
166
|
- !ruby/object:Gem::Version
|
181
167
|
version: '2.15'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: thor
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - ">="
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: 1.4.0
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - ">="
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: 1.4.0
|
182
182
|
- !ruby/object:Gem::Dependency
|
183
183
|
name: vcr
|
184
184
|
requirement: !ruby/object:Gem::Requirement
|
@@ -251,6 +251,7 @@ files:
|
|
251
251
|
- docs/references/troubleshooting.md
|
252
252
|
- docs/wip/session-2025-05-26.md
|
253
253
|
- lib/patch_retention.rb
|
254
|
+
- lib/patch_retention/calendar_items.rb
|
254
255
|
- lib/patch_retention/configuration.rb
|
255
256
|
- lib/patch_retention/contacts.rb
|
256
257
|
- lib/patch_retention/contacts/delete.rb
|
@@ -264,6 +265,7 @@ files:
|
|
264
265
|
- lib/patch_retention/products.rb
|
265
266
|
- lib/patch_retention/util.rb
|
266
267
|
- lib/patch_retention/version.rb
|
268
|
+
- patch_retention.gemspec
|
267
269
|
- script/setup_test_env
|
268
270
|
- sig/patch_retention.rbs
|
269
271
|
homepage: https://playbypoint.com
|