postproxy-sdk 1.8.0 → 1.9.0

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: 1d2f9ae8cbbc2ca3cd324b5dc522226c9d7a77cd93430abb309b31efc210a293
4
- data.tar.gz: 26c58e5f9b7ea1af4eccb3935ef8c71bf202bf5bff93898d0b30a5450114bb1a
3
+ metadata.gz: 7b20d20d7dc1f6a386e74894a57e470c70a1edc3e95bcd61c3b25f02b3e457cd
4
+ data.tar.gz: 6fd6807bcbbd09fae222ccd07eee0d66cbb420bc04e83fd49ab98c4340a4ed82
5
5
  SHA512:
6
- metadata.gz: 906800719560c2e37351c958fa72449d1411b351c1cad4deb0d312e9b6fcaa3af3be3dcb504eeef045a3d24737815afb4e7f772edae4687e102e2f9d4bd605cc
7
- data.tar.gz: b6ee51b608b91a9d31ed2891b7bba87df996006be1795504f540e275dd54c8ff3b7ef7e5f1994a7aa495a02f67ec8f3921e9017baadb3e1e8d3c5550d6959b06
6
+ metadata.gz: c5e18b59805d1aff449eb7e3b8227bd2290b85994ba8e14f38b1c945381facd37a1b77e218d9eaf3c3e8c3183eade0da5268eb86b79762ad1aa9606b015a8e6a
7
+ data.tar.gz: ec5a37899a8c3622212e5d7d2b43a540df1e7aff64f9ea99a17a3fd1b0ed1e332a44a7c568eef24882f70fba267fe18302581d9af999ed997651df368dca59cc
data/README.md CHANGED
@@ -317,6 +317,32 @@ client.comments.like("post-id", "comment-id", profile_id: "profile-id")
317
317
  client.comments.unlike("post-id", "comment-id", profile_id: "profile-id")
318
318
  ```
319
319
 
320
+ ## Profile comments (Google Business reviews)
321
+
322
+ Profile-level comments expose Google Business reviews and replies. Reviews are user-generated — the SDK lets you list/get them and reply to or delete your own replies. Reviews sync twice daily.
323
+
324
+ ```ruby
325
+ # List reviews for a profile (paginated)
326
+ reviews = client.profile_comments.list("profile-id")
327
+ reviews.data.each do |review|
328
+ rating = (review.platform_data || {})[:star_rating]
329
+ puts "#{review.author_username} #{rating}: #{review.body}"
330
+ review.replies.each { |r| puts " reply: #{r.body}" }
331
+ end
332
+
333
+ # Filter by placement (location)
334
+ reviews = client.profile_comments.list("profile-id", placement_id: "accounts/123/locations/456")
335
+
336
+ # Get a single review
337
+ review = client.profile_comments.get("profile-id", "review-id")
338
+
339
+ # Reply to a review (parent_id is the review id)
340
+ reply = client.profile_comments.create("profile-id", parent_id: "review-id", text: "Thanks for visiting!")
341
+
342
+ # Delete your reply
343
+ client.profile_comments.delete("profile-id", "reply-id")
344
+ ```
345
+
320
346
  ## Profiles
321
347
 
322
348
  ```ruby
@@ -435,7 +461,27 @@ post = client.posts.create(
435
461
  )
436
462
  ```
437
463
 
438
- Supported platforms: `facebook`, `instagram`, `tiktok`, `linkedin`, `youtube`, `twitter`, `threads`, `pinterest`, `bluesky`, `telegram`. Telegram requires a `chat_id` per post — list channels with `client.profiles.placements(profile_id)`.
464
+ Supported platforms: `facebook`, `instagram`, `tiktok`, `linkedin`, `youtube`, `twitter`, `threads`, `pinterest`, `bluesky`, `telegram`, `google_business`. Telegram requires a `chat_id` per post — list channels with `client.profiles.placements(profile_id)`.
465
+
466
+ ### Google Business
467
+
468
+ Google Business posts use a `google_business` entry in `PlatformParams` (a plain hash; no typed struct). The `location_id` is the location resource path returned by `client.profiles.placements()`. Supported formats: `standard`, `event`, `offer`. CTA actions: `LEARN_MORE`, `BOOK`, `ORDER`, `SHOP`, `SIGN_UP`, `CALL`. Media is limited to one image (≤5 MB).
469
+
470
+ ```ruby
471
+ client.posts.create(
472
+ "Now open weekends!",
473
+ ["gbp-profile-id"],
474
+ media: ["https://example.com/store.jpg"],
475
+ platforms: {
476
+ google_business: {
477
+ format: "standard",
478
+ location_id: "accounts/123/locations/456",
479
+ cta_action_type: "LEARN_MORE",
480
+ cta_url: "https://example.com"
481
+ }
482
+ }
483
+ )
484
+ ```
439
485
 
440
486
  ## Error Handling
441
487
 
@@ -7,6 +7,7 @@ require_relative "resources/profile_groups"
7
7
  require_relative "resources/webhooks"
8
8
  require_relative "resources/queues"
9
9
  require_relative "resources/comments"
10
+ require_relative "resources/profile_comments"
10
11
 
11
12
  module PostProxy
12
13
  class Client
@@ -23,6 +24,7 @@ module PostProxy
23
24
  @webhooks = nil
24
25
  @queues = nil
25
26
  @comments = nil
27
+ @profile_comments = nil
26
28
  end
27
29
 
28
30
  def posts
@@ -49,6 +51,10 @@ module PostProxy
49
51
  @comments ||= Resources::Comments.new(self)
50
52
  end
51
53
 
54
+ def profile_comments
55
+ @profile_comments ||= Resources::ProfileComments.new(self)
56
+ end
57
+
52
58
  def request(method, path, params: nil, json: nil, data: nil, files: nil, profile_group_id: nil)
53
59
  url = "/api#{path}"
54
60
 
@@ -2,7 +2,7 @@ module PostProxy
2
2
  DEFAULT_BASE_URL = "https://api.postproxy.dev"
3
3
 
4
4
  PLATFORMS = %w[
5
- facebook instagram tiktok linkedin youtube twitter threads pinterest bluesky telegram
5
+ facebook instagram tiktok linkedin youtube twitter threads pinterest bluesky telegram google_business
6
6
  ].freeze
7
7
 
8
8
  PROFILE_STATUSES = %w[active expired inactive].freeze
@@ -0,0 +1,41 @@
1
+ module PostProxy
2
+ module Resources
3
+ class ProfileComments
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ def list(profile_id, placement_id: nil, page: nil, per_page: nil)
9
+ params = {}
10
+ params[:placement_id] = placement_id if placement_id
11
+ params[:page] = page if page
12
+ params[:per_page] = per_page if per_page
13
+
14
+ result = @client.request(:get, "/profiles/#{profile_id}/comments", params: params)
15
+ comments = (result[:data] || []).map { |c| ProfileComment.new(**c) }
16
+ PaginatedResponse.new(
17
+ data: comments,
18
+ total: result[:total],
19
+ page: result[:page],
20
+ per_page: result[:per_page]
21
+ )
22
+ end
23
+
24
+ def get(profile_id, comment_id)
25
+ result = @client.request(:get, "/profiles/#{profile_id}/comments/#{comment_id}")
26
+ ProfileComment.new(**result)
27
+ end
28
+
29
+ def create(profile_id, parent_id:, text:)
30
+ result = @client.request(:post, "/profiles/#{profile_id}/comments",
31
+ json: { parent_id: parent_id, text: text })
32
+ ProfileComment.new(**result)
33
+ end
34
+
35
+ def delete(profile_id, comment_id)
36
+ result = @client.request(:delete, "/profiles/#{profile_id}/comments/#{comment_id}")
37
+ AcceptedResponse.new(**result)
38
+ end
39
+ end
40
+ end
41
+ end
@@ -98,14 +98,31 @@ module PostProxy
98
98
  end
99
99
  end
100
100
 
101
+ class MediaPlatformError < Model
102
+ attr_accessor :platform, :status, :error, :error_details
103
+
104
+ def initialize(**attrs)
105
+ @error = nil
106
+ @error_details = nil
107
+ super
108
+ @error_details = ErrorDetails.new(**@error_details.transform_keys(&:to_sym)) if @error_details.is_a?(Hash)
109
+ end
110
+ end
111
+
101
112
  class Media < Model
102
- attr_accessor :id, :status, :error_message, :content_type, :source_url, :url
113
+ attr_accessor :id, :status, :error_message, :content_type, :source_url, :url, :platforms
103
114
 
104
115
  def initialize(**attrs)
105
116
  @error_message = nil
106
117
  @source_url = nil
107
118
  @url = nil
119
+ @platforms = nil
108
120
  super
121
+ if @platforms.is_a?(Array)
122
+ @platforms = @platforms.map do |p|
123
+ p.is_a?(MediaPlatformError) ? p : MediaPlatformError.new(**p.transform_keys(&:to_sym))
124
+ end
125
+ end
109
126
  end
110
127
  end
111
128
 
@@ -322,6 +339,33 @@ module PostProxy
322
339
  end
323
340
  end
324
341
 
342
+ class ProfileComment < Model
343
+ attr_accessor :id, :external_id, :parent_external_id, :placement_id,
344
+ :body, :status, :author_username, :author_avatar_url,
345
+ :platform_data, :posted_at, :created_at, :replies
346
+
347
+ def initialize(**attrs)
348
+ @parent_external_id = nil
349
+ @author_username = nil
350
+ @author_avatar_url = nil
351
+ @platform_data = nil
352
+ @replies = []
353
+ super
354
+ @posted_at = parse_time(@posted_at)
355
+ @created_at = parse_time(@created_at)
356
+ @replies = (@replies || []).map do |r|
357
+ r.is_a?(ProfileComment) ? r : ProfileComment.new(**r.transform_keys(&:to_sym))
358
+ end
359
+ end
360
+
361
+ private
362
+
363
+ def parse_time(value)
364
+ return nil if value.nil?
365
+ value.is_a?(Time) ? value : Time.parse(value.to_s)
366
+ end
367
+ end
368
+
325
369
  class AcceptedResponse < Model
326
370
  attr_accessor :accepted
327
371
  end
@@ -452,11 +496,11 @@ module PostProxy
452
496
 
453
497
  class PlatformParams < Model
454
498
  attr_accessor :facebook, :instagram, :tiktok, :linkedin, :youtube,
455
- :pinterest, :threads, :twitter, :bluesky, :telegram
499
+ :pinterest, :threads, :twitter, :bluesky, :telegram, :google_business
456
500
 
457
501
  def to_h
458
502
  result = {}
459
- %i[facebook instagram tiktok linkedin youtube pinterest threads twitter bluesky telegram].each do |platform|
503
+ %i[facebook instagram tiktok linkedin youtube pinterest threads twitter bluesky telegram google_business].each do |platform|
460
504
  value = send(platform)
461
505
  next if value.nil?
462
506
 
@@ -1,3 +1,3 @@
1
1
  module PostProxy
2
- VERSION = "1.8.0"
2
+ VERSION = "1.9.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: postproxy-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.0
4
+ version: 1.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - PostProxy
@@ -80,6 +80,7 @@ files:
80
80
  - lib/postproxy/errors.rb
81
81
  - lib/postproxy/resources/comments.rb
82
82
  - lib/postproxy/resources/posts.rb
83
+ - lib/postproxy/resources/profile_comments.rb
83
84
  - lib/postproxy/resources/profile_groups.rb
84
85
  - lib/postproxy/resources/profiles.rb
85
86
  - lib/postproxy/resources/queues.rb