postproxy-sdk 1.0.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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 822ce030b347645daad188e55da76ab9a3494b0f7f01d0b6a78a02b4c9e933d6
4
+ data.tar.gz: 33dc5d8cf8e97817b9f6f69d8f57dd4dfd207ff1b8add0ba58661cddfd88f64f
5
+ SHA512:
6
+ metadata.gz: 8460f568b415ec00973fa57d9065a85a141fe16aafb430765054ae51ca0ee16c514a55c02f59c54b7983def183c9131c07c65a5db448976f05d9db2139243915
7
+ data.tar.gz: 64c079b04bbd82dde18a2c612000ad42f8525351326714243c923dfde21bba6e51125006169a36675301b2fde2857f94c54e74cab08ae406345bf1dd8a26e711
data/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # PostProxy Ruby SDK
2
+
3
+ Ruby client for the [PostProxy API](https://postproxy.dev) — manage social media posts, profiles, and profile groups.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ gem install postproxy-sdk
9
+ ```
10
+
11
+ Or add to your Gemfile:
12
+
13
+ ```ruby
14
+ gem "postproxy-sdk"
15
+ ```
16
+
17
+ ## Quick Start
18
+
19
+ ```ruby
20
+ require "postproxy"
21
+
22
+ client = PostProxy::Client.new("your-api-key", profile_group_id: "pg-abc")
23
+
24
+ profiles = client.profiles.list.data
25
+ post = client.posts.create(
26
+ "Hello from PostProxy!",
27
+ profiles: [profiles.first.id]
28
+ )
29
+ puts post.id, post.status
30
+ ```
31
+
32
+ ## Client
33
+
34
+ ```ruby
35
+ # Basic
36
+ client = PostProxy::Client.new("your-api-key")
37
+
38
+ # With default profile group
39
+ client = PostProxy::Client.new("your-api-key", profile_group_id: "pg-abc")
40
+
41
+ # With custom base URL
42
+ client = PostProxy::Client.new("your-api-key", base_url: "https://custom.api.dev")
43
+
44
+ # With custom Faraday client
45
+ faraday = Faraday.new(url: "https://api.postproxy.dev") do |f|
46
+ f.request :retry
47
+ f.headers["Authorization"] = "Bearer your-api-key"
48
+ f.adapter :net_http
49
+ end
50
+ client = PostProxy::Client.new("your-api-key", faraday_client: faraday)
51
+ ```
52
+
53
+ ## Posts
54
+
55
+ ```ruby
56
+ # List posts (paginated)
57
+ result = client.posts.list(page: 1, per_page: 10, status: "processed")
58
+ result.data # => [Post, ...]
59
+ result.total # => 42
60
+ result.page # => 1
61
+
62
+ # Get a single post
63
+ post = client.posts.get("post-id")
64
+
65
+ # Create a post
66
+ post = client.posts.create("Hello!", profiles: ["prof-1", "prof-2"])
67
+
68
+ # Create with media URLs
69
+ post = client.posts.create(
70
+ "Check this out!",
71
+ profiles: ["prof-1"],
72
+ media: ["https://example.com/image.jpg"]
73
+ )
74
+
75
+ # Create with local file uploads
76
+ post = client.posts.create(
77
+ "Uploaded!",
78
+ profiles: ["prof-1"],
79
+ media_files: ["/path/to/photo.jpg"]
80
+ )
81
+
82
+ # Create a draft
83
+ draft = client.posts.create("Draft", profiles: ["prof-1"], draft: true)
84
+
85
+ # Publish a draft
86
+ post = client.posts.publish_draft("post-id")
87
+
88
+ # Schedule a post
89
+ post = client.posts.create(
90
+ "Later!",
91
+ profiles: ["prof-1"],
92
+ scheduled_at: (Time.now + 3600).iso8601
93
+ )
94
+
95
+ # Delete a post
96
+ client.posts.delete("post-id")
97
+ ```
98
+
99
+ ## Profiles
100
+
101
+ ```ruby
102
+ # List profiles
103
+ profiles = client.profiles.list.data
104
+
105
+ # Get a profile
106
+ profile = client.profiles.get("prof-id")
107
+
108
+ # Get placements for a profile
109
+ placements = client.profiles.placements("prof-id").data
110
+
111
+ # Delete a profile
112
+ client.profiles.delete("prof-id")
113
+ ```
114
+
115
+ ## Profile Groups
116
+
117
+ ```ruby
118
+ # List groups
119
+ groups = client.profile_groups.list.data
120
+
121
+ # Get a group
122
+ group = client.profile_groups.get("pg-id")
123
+
124
+ # Create a group
125
+ group = client.profile_groups.create("My Group")
126
+
127
+ # Delete a group
128
+ client.profile_groups.delete("pg-id")
129
+
130
+ # Initialize OAuth connection
131
+ connection = client.profile_groups.initialize_connection(
132
+ "pg-id",
133
+ platform: "instagram",
134
+ redirect_url: "https://myapp.com/callback"
135
+ )
136
+ # Redirect user to connection.url
137
+ ```
138
+
139
+ ## Platform Parameters
140
+
141
+ ```ruby
142
+ platforms = PostProxy::PlatformParams.new(
143
+ facebook: PostProxy::FacebookParams.new(
144
+ format: "post",
145
+ first_comment: "First!"
146
+ ),
147
+ instagram: PostProxy::InstagramParams.new(
148
+ format: "reel",
149
+ collaborators: ["@friend"],
150
+ cover_url: "https://example.com/cover.jpg"
151
+ ),
152
+ tiktok: PostProxy::TikTokParams.new(
153
+ privacy_status: "PUBLIC_TO_EVERYONE",
154
+ auto_add_music: true
155
+ ),
156
+ linkedin: PostProxy::LinkedInParams.new(format: "post"),
157
+ youtube: PostProxy::YouTubeParams.new(
158
+ title: "My Video",
159
+ privacy_status: "public"
160
+ ),
161
+ pinterest: PostProxy::PinterestParams.new(
162
+ title: "My Pin",
163
+ board_id: "board-123"
164
+ ),
165
+ threads: PostProxy::ThreadsParams.new(format: "post"),
166
+ twitter: PostProxy::TwitterParams.new(format: "post")
167
+ )
168
+
169
+ post = client.posts.create(
170
+ "Cross-platform!",
171
+ profiles: ["prof-1", "prof-2"],
172
+ platforms: platforms
173
+ )
174
+ ```
175
+
176
+ ## Error Handling
177
+
178
+ ```ruby
179
+ begin
180
+ client.posts.get("bad-id")
181
+ rescue PostProxy::AuthenticationError => e
182
+ puts "Auth failed: #{e.message}" # 401
183
+ rescue PostProxy::NotFoundError => e
184
+ puts "Not found: #{e.message}" # 404
185
+ rescue PostProxy::ValidationError => e
186
+ puts "Invalid: #{e.message}" # 422
187
+ rescue PostProxy::BadRequestError => e
188
+ puts "Bad request: #{e.message}" # 400
189
+ rescue PostProxy::Error => e
190
+ puts "Error #{e.status_code}: #{e.message}"
191
+ puts e.response # parsed response body
192
+ end
193
+ ```
194
+
195
+ ## License
196
+
197
+ MIT
@@ -0,0 +1,155 @@
1
+ require "faraday"
2
+ require "faraday/multipart"
3
+ require "json"
4
+ require_relative "resources/posts"
5
+ require_relative "resources/profiles"
6
+ require_relative "resources/profile_groups"
7
+
8
+ module PostProxy
9
+ class Client
10
+ attr_reader :api_key, :base_url, :profile_group_id
11
+
12
+ def initialize(api_key, base_url: DEFAULT_BASE_URL, profile_group_id: nil, faraday_client: nil)
13
+ @api_key = api_key
14
+ @base_url = base_url
15
+ @profile_group_id = profile_group_id
16
+ @faraday_client = faraday_client
17
+ @posts = nil
18
+ @profiles = nil
19
+ @profile_groups = nil
20
+ end
21
+
22
+ def posts
23
+ @posts ||= Resources::Posts.new(self)
24
+ end
25
+
26
+ def profiles
27
+ @profiles ||= Resources::Profiles.new(self)
28
+ end
29
+
30
+ def profile_groups
31
+ @profile_groups ||= Resources::ProfileGroups.new(self)
32
+ end
33
+
34
+ def request(method, path, params: nil, json: nil, data: nil, files: nil, profile_group_id: nil)
35
+ url = "/api#{path}"
36
+
37
+ query = {}
38
+ pgid = profile_group_id || @profile_group_id
39
+ query[:profile_group_id] = pgid if pgid
40
+ query.merge!(params) if params
41
+
42
+ response = if files
43
+ conn = multipart_connection
44
+ parts = []
45
+ data&.each { |k, v| parts << [k.to_s, v.to_s] }
46
+ files.each do |field, filename, io, content_type|
47
+ if io.nil?
48
+ # Plain text part (filename holds the string value)
49
+ parts << [field, filename]
50
+ elsif io.is_a?(String)
51
+ # Plain text part
52
+ parts << [field, io]
53
+ else
54
+ # File upload
55
+ parts << [field, Faraday::Multipart::FilePart.new(io, content_type, filename)]
56
+ end
57
+ end
58
+ # Build payload preserving duplicate keys
59
+ payload = parts.each_with_object({}) do |(key, val), h|
60
+ if h.key?(key)
61
+ h[key] = [h[key]] unless h[key].is_a?(Array)
62
+ h[key] << val
63
+ else
64
+ h[key] = val
65
+ end
66
+ end
67
+ conn.send(method, url) do |req|
68
+ req.params = query unless query.empty?
69
+ req.body = payload
70
+ end
71
+ else
72
+ conn = json_connection
73
+ conn.send(method, url) do |req|
74
+ req.params = query unless query.empty?
75
+ req.body = json.to_json if json
76
+ end
77
+ end
78
+
79
+ handle_response(response)
80
+ end
81
+
82
+ private
83
+
84
+ def json_connection
85
+ @faraday_client || Faraday.new(url: @base_url) do |f|
86
+ f.request :url_encoded
87
+ f.headers["Authorization"] = "Bearer #{@api_key}"
88
+ f.headers["Content-Type"] = "application/json"
89
+ f.adapter Faraday.default_adapter
90
+ end
91
+ end
92
+
93
+ def multipart_connection
94
+ @faraday_client || Faraday.new(url: @base_url) do |f|
95
+ f.request :multipart
96
+ f.headers["Authorization"] = "Bearer #{@api_key}"
97
+ f.adapter Faraday.default_adapter
98
+ end
99
+ end
100
+
101
+ def handle_response(response)
102
+ case response.status
103
+ when 200..299
104
+ return nil if response.status == 204
105
+ return nil if response.body.nil? || response.body.empty?
106
+ JSON.parse(response.body, symbolize_names: true)
107
+ when 401
108
+ body = parse_error_body(response)
109
+ raise AuthenticationError.new(
110
+ error_message(body),
111
+ status_code: response.status,
112
+ response: body
113
+ )
114
+ when 404
115
+ body = parse_error_body(response)
116
+ raise NotFoundError.new(
117
+ error_message(body),
118
+ status_code: response.status,
119
+ response: body
120
+ )
121
+ when 422
122
+ body = parse_error_body(response)
123
+ raise ValidationError.new(
124
+ error_message(body),
125
+ status_code: response.status,
126
+ response: body
127
+ )
128
+ when 400
129
+ body = parse_error_body(response)
130
+ raise BadRequestError.new(
131
+ error_message(body),
132
+ status_code: response.status,
133
+ response: body
134
+ )
135
+ else
136
+ body = parse_error_body(response)
137
+ raise Error.new(
138
+ error_message(body),
139
+ status_code: response.status,
140
+ response: body
141
+ )
142
+ end
143
+ end
144
+
145
+ def parse_error_body(response)
146
+ JSON.parse(response.body, symbolize_names: true)
147
+ rescue JSON::ParserError, TypeError
148
+ { error: response.body }
149
+ end
150
+
151
+ def error_message(body)
152
+ body[:message] || body[:error]
153
+ end
154
+ end
155
+ end
@@ -0,0 +1,28 @@
1
+ module PostProxy
2
+ DEFAULT_BASE_URL = "https://api.postproxy.dev"
3
+
4
+ PLATFORMS = %w[
5
+ facebook instagram tiktok linkedin youtube twitter threads pinterest
6
+ ].freeze
7
+
8
+ PROFILE_STATUSES = %w[active expired inactive].freeze
9
+
10
+ POST_STATUSES = %w[pending draft processing processed scheduled].freeze
11
+
12
+ PLATFORM_POST_STATUSES = %w[pending processing published failed deleted].freeze
13
+
14
+ INSTAGRAM_FORMATS = %w[post reel story].freeze
15
+ FACEBOOK_FORMATS = %w[post story].freeze
16
+ TIKTOK_FORMATS = %w[video image].freeze
17
+ LINKEDIN_FORMATS = %w[post].freeze
18
+ YOUTUBE_FORMATS = %w[post].freeze
19
+ PINTEREST_FORMATS = %w[pin].freeze
20
+ THREADS_FORMATS = %w[post].freeze
21
+ TWITTER_FORMATS = %w[post].freeze
22
+
23
+ TIKTOK_PRIVACIES = %w[
24
+ PUBLIC_TO_EVERYONE MUTUAL_FOLLOW_FRIENDS FOLLOWER_OF_CREATOR SELF_ONLY
25
+ ].freeze
26
+
27
+ YOUTUBE_PRIVACIES = %w[public unlisted private].freeze
28
+ end
@@ -0,0 +1,16 @@
1
+ module PostProxy
2
+ class Error < StandardError
3
+ attr_reader :status_code, :response
4
+
5
+ def initialize(message, status_code: nil, response: nil)
6
+ super(message)
7
+ @status_code = status_code
8
+ @response = response
9
+ end
10
+ end
11
+
12
+ class AuthenticationError < Error; end
13
+ class NotFoundError < Error; end
14
+ class ValidationError < Error; end
15
+ class BadRequestError < Error; end
16
+ end
@@ -0,0 +1,117 @@
1
+ module PostProxy
2
+ module Resources
3
+ class Posts
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ def list(page: nil, per_page: nil, status: nil, platforms: nil, scheduled_after: nil, profile_group_id: nil)
9
+ params = {}
10
+ params[:page] = page if page
11
+ params[:per_page] = per_page if per_page
12
+ params[:status] = status if status
13
+ params[:platforms] = platforms.join(",") if platforms
14
+ params[:scheduled_after] = format_time(scheduled_after) if scheduled_after
15
+
16
+ result = @client.request(:get, "/posts", params: params, profile_group_id: profile_group_id)
17
+ posts = (result[:data] || []).map { |p| Post.new(**p) }
18
+ PaginatedResponse.new(
19
+ data: posts,
20
+ total: result[:total],
21
+ page: result[:page],
22
+ per_page: result[:per_page]
23
+ )
24
+ end
25
+
26
+ def get(id, profile_group_id: nil)
27
+ result = @client.request(:get, "/posts/#{id}", profile_group_id: profile_group_id)
28
+ Post.new(**result)
29
+ end
30
+
31
+ def create(body, profiles:, media: nil, media_files: nil, platforms: nil,
32
+ scheduled_at: nil, draft: nil, profile_group_id: nil)
33
+ if media_files && !media_files.empty?
34
+ form_data = { "post[body]" => body }
35
+ form_data["post[scheduled_at]"] = format_time(scheduled_at) if scheduled_at
36
+ form_data["post[draft]"] = draft.to_s if !draft.nil?
37
+
38
+ files = []
39
+
40
+ profiles.each do |p|
41
+ files << ["profiles[]", nil, p, "text/plain"]
42
+ end
43
+
44
+ media&.each do |m|
45
+ files << ["media[]", nil, m, "text/plain"]
46
+ end
47
+
48
+ if platforms
49
+ params_hash = platforms.is_a?(PlatformParams) ? platforms.to_h : platforms
50
+ params_hash.each do |platform, platform_params|
51
+ platform_params.each do |key, value|
52
+ files << ["platforms[#{platform}][#{key}]", nil, value.to_s, "text/plain"]
53
+ end
54
+ end
55
+ end
56
+
57
+ media_files.each do |path|
58
+ path = path.to_s
59
+ filename = File.basename(path)
60
+ content_type = mime_type_for(filename)
61
+ io = File.open(path, "rb")
62
+ files << ["media[]", filename, io, content_type]
63
+ end
64
+
65
+ result = @client.request(:post, "/posts",
66
+ data: form_data,
67
+ files: files,
68
+ profile_group_id: profile_group_id
69
+ )
70
+ else
71
+ post_payload = { body: body }
72
+ post_payload[:scheduled_at] = format_time(scheduled_at) if scheduled_at
73
+ post_payload[:draft] = draft unless draft.nil?
74
+
75
+ json_body = { post: post_payload, profiles: profiles }
76
+ json_body[:platforms] = platforms.is_a?(PlatformParams) ? platforms.to_h : platforms if platforms
77
+ json_body[:media] = media if media
78
+
79
+ result = @client.request(:post, "/posts", json: json_body, profile_group_id: profile_group_id)
80
+ end
81
+
82
+ Post.new(**result)
83
+ end
84
+
85
+ def publish_draft(id, profile_group_id: nil)
86
+ result = @client.request(:post, "/posts/#{id}/publish", profile_group_id: profile_group_id)
87
+ Post.new(**result)
88
+ end
89
+
90
+ def delete(id, profile_group_id: nil)
91
+ result = @client.request(:delete, "/posts/#{id}", profile_group_id: profile_group_id)
92
+ DeleteResponse.new(**result)
93
+ end
94
+
95
+ private
96
+
97
+ def format_time(value)
98
+ return value if value.is_a?(String)
99
+ value.iso8601
100
+ end
101
+
102
+ def mime_type_for(filename)
103
+ case File.extname(filename).downcase
104
+ when ".jpg", ".jpeg" then "image/jpeg"
105
+ when ".png" then "image/png"
106
+ when ".gif" then "image/gif"
107
+ when ".webp" then "image/webp"
108
+ when ".mp4" then "video/mp4"
109
+ when ".mov" then "video/quicktime"
110
+ when ".avi" then "video/x-msvideo"
111
+ when ".webm" then "video/webm"
112
+ else "application/octet-stream"
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
@@ -0,0 +1,37 @@
1
+ module PostProxy
2
+ module Resources
3
+ class ProfileGroups
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ def list
9
+ result = @client.request(:get, "/profile_groups")
10
+ groups = (result[:data] || []).map { |g| ProfileGroup.new(**g) }
11
+ ListResponse.new(data: groups)
12
+ end
13
+
14
+ def get(id)
15
+ result = @client.request(:get, "/profile_groups/#{id}")
16
+ ProfileGroup.new(**result)
17
+ end
18
+
19
+ def create(name)
20
+ result = @client.request(:post, "/profile_groups", json: { name: name })
21
+ ProfileGroup.new(**result)
22
+ end
23
+
24
+ def delete(id)
25
+ result = @client.request(:delete, "/profile_groups/#{id}")
26
+ DeleteResponse.new(**result)
27
+ end
28
+
29
+ def initialize_connection(id, platform:, redirect_url:)
30
+ result = @client.request(:post, "/profile_groups/#{id}/initialize_connection",
31
+ json: { platform: platform, redirect_url: redirect_url }
32
+ )
33
+ ConnectionResponse.new(**result)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,31 @@
1
+ module PostProxy
2
+ module Resources
3
+ class Profiles
4
+ def initialize(client)
5
+ @client = client
6
+ end
7
+
8
+ def list(profile_group_id: nil)
9
+ result = @client.request(:get, "/profiles", profile_group_id: profile_group_id)
10
+ profiles = (result[:data] || []).map { |p| Profile.new(**p) }
11
+ ListResponse.new(data: profiles)
12
+ end
13
+
14
+ def get(id, profile_group_id: nil)
15
+ result = @client.request(:get, "/profiles/#{id}", profile_group_id: profile_group_id)
16
+ Profile.new(**result)
17
+ end
18
+
19
+ def placements(id, profile_group_id: nil)
20
+ result = @client.request(:get, "/profiles/#{id}/placements", profile_group_id: profile_group_id)
21
+ items = (result[:data] || []).map { |p| Placement.new(**p) }
22
+ ListResponse.new(data: items)
23
+ end
24
+
25
+ def delete(id, profile_group_id: nil)
26
+ result = @client.request(:delete, "/profiles/#{id}", profile_group_id: profile_group_id)
27
+ SuccessResponse.new(**result)
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,197 @@
1
+ require "time"
2
+
3
+ module PostProxy
4
+ class Model
5
+ def initialize(**attrs)
6
+ attrs.each do |key, value|
7
+ if respond_to?(:"#{key}=")
8
+ send(:"#{key}=", value)
9
+ end
10
+ end
11
+ end
12
+
13
+ def to_h
14
+ instance_variables.each_with_object({}) do |var, hash|
15
+ key = var.to_s.delete_prefix("@")
16
+ hash[key.to_sym] = instance_variable_get(var)
17
+ end
18
+ end
19
+ end
20
+
21
+ class Profile < Model
22
+ attr_accessor :id, :name, :status, :platform, :profile_group_id, :expires_at, :post_count
23
+
24
+ def initialize(**attrs)
25
+ @expires_at = nil
26
+ @post_count = 0
27
+ super
28
+ @expires_at = parse_time(@expires_at)
29
+ end
30
+
31
+ private
32
+
33
+ def parse_time(value)
34
+ return nil if value.nil?
35
+ value.is_a?(Time) ? value : Time.parse(value.to_s)
36
+ end
37
+ end
38
+
39
+ class ProfileGroup < Model
40
+ attr_accessor :id, :name, :profiles_count
41
+
42
+ def initialize(**attrs)
43
+ @profiles_count = 0
44
+ super
45
+ end
46
+ end
47
+
48
+ class Insights < Model
49
+ attr_accessor :impressions, :on
50
+
51
+ def initialize(**attrs)
52
+ @impressions = nil
53
+ @on = nil
54
+ super
55
+ @on = parse_time(@on)
56
+ end
57
+
58
+ private
59
+
60
+ def parse_time(value)
61
+ return nil if value.nil?
62
+ value.is_a?(Time) ? value : Time.parse(value.to_s)
63
+ end
64
+ end
65
+
66
+ class PlatformResult < Model
67
+ attr_accessor :platform, :status, :params, :error, :attempted_at, :insights
68
+
69
+ def initialize(**attrs)
70
+ @params = nil
71
+ @error = nil
72
+ @attempted_at = nil
73
+ @insights = nil
74
+ super
75
+ @attempted_at = parse_time(@attempted_at)
76
+ @insights = Insights.new(**@insights) if @insights.is_a?(Hash)
77
+ end
78
+
79
+ private
80
+
81
+ def parse_time(value)
82
+ return nil if value.nil?
83
+ value.is_a?(Time) ? value : Time.parse(value.to_s)
84
+ end
85
+ end
86
+
87
+ class Post < Model
88
+ attr_accessor :id, :body, :status, :scheduled_at, :created_at, :platforms
89
+
90
+ def initialize(**attrs)
91
+ @scheduled_at = nil
92
+ @platforms = []
93
+ super
94
+ @scheduled_at = parse_time(@scheduled_at)
95
+ @created_at = parse_time(@created_at)
96
+ @platforms = (@platforms || []).map do |p|
97
+ p.is_a?(PlatformResult) ? p : PlatformResult.new(**p.transform_keys(&:to_sym))
98
+ end
99
+ end
100
+
101
+ private
102
+
103
+ def parse_time(value)
104
+ return nil if value.nil?
105
+ value.is_a?(Time) ? value : Time.parse(value.to_s)
106
+ end
107
+ end
108
+
109
+ class Placement < Model
110
+ attr_accessor :id, :name
111
+ end
112
+
113
+ class ListResponse
114
+ attr_reader :data
115
+
116
+ def initialize(data:)
117
+ @data = data
118
+ end
119
+ end
120
+
121
+ class PaginatedResponse < ListResponse
122
+ attr_reader :total, :page, :per_page
123
+
124
+ def initialize(data:, total:, page:, per_page:)
125
+ super(data: data)
126
+ @total = total
127
+ @page = page
128
+ @per_page = per_page
129
+ end
130
+ end
131
+
132
+ class DeleteResponse < Model
133
+ attr_accessor :deleted
134
+ end
135
+
136
+ class SuccessResponse < Model
137
+ attr_accessor :success
138
+ end
139
+
140
+ class ConnectionResponse < Model
141
+ attr_accessor :url, :success
142
+ end
143
+
144
+ # Platform-specific parameter structs
145
+
146
+ class FacebookParams < Model
147
+ attr_accessor :format, :first_comment, :page_id
148
+ end
149
+
150
+ class InstagramParams < Model
151
+ attr_accessor :format, :first_comment, :collaborators, :cover_url,
152
+ :audio_name, :trial_strategy, :thumb_offset
153
+ end
154
+
155
+ class TikTokParams < Model
156
+ attr_accessor :format, :privacy_status, :photo_cover_index, :auto_add_music,
157
+ :made_with_ai, :disable_comment, :disable_duet, :disable_stitch,
158
+ :brand_content_toggle, :brand_organic_toggle
159
+ end
160
+
161
+ class LinkedInParams < Model
162
+ attr_accessor :format, :organization_id
163
+ end
164
+
165
+ class YouTubeParams < Model
166
+ attr_accessor :format, :title, :privacy_status, :cover_url
167
+ end
168
+
169
+ class PinterestParams < Model
170
+ attr_accessor :format, :title, :board_id, :destination_link, :cover_url, :thumb_offset
171
+ end
172
+
173
+ class ThreadsParams < Model
174
+ attr_accessor :format
175
+ end
176
+
177
+ class TwitterParams < Model
178
+ attr_accessor :format
179
+ end
180
+
181
+ class PlatformParams < Model
182
+ attr_accessor :facebook, :instagram, :tiktok, :linkedin, :youtube,
183
+ :pinterest, :threads, :twitter
184
+
185
+ def to_h
186
+ result = {}
187
+ %i[facebook instagram tiktok linkedin youtube pinterest threads twitter].each do |platform|
188
+ value = send(platform)
189
+ next if value.nil?
190
+
191
+ params = value.is_a?(Model) ? value.to_h : value
192
+ result[platform] = params.reject { |_, v| v.nil? }
193
+ end
194
+ result
195
+ end
196
+ end
197
+ end
@@ -0,0 +1,3 @@
1
+ module PostProxy
2
+ VERSION = "1.0.0"
3
+ end
data/lib/postproxy.rb ADDED
@@ -0,0 +1,8 @@
1
+ require_relative "postproxy/version"
2
+ require_relative "postproxy/constants"
3
+ require_relative "postproxy/errors"
4
+ require_relative "postproxy/types"
5
+ require_relative "postproxy/client"
6
+
7
+ module PostProxy
8
+ end
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: postproxy-sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - PostProxy
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: faraday
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '2.0'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '2.0'
26
+ - !ruby/object:Gem::Dependency
27
+ name: faraday-multipart
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: '1.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: !ruby/object:Gem::Requirement
36
+ requirements:
37
+ - - ">="
38
+ - !ruby/object:Gem::Version
39
+ version: '1.0'
40
+ - !ruby/object:Gem::Dependency
41
+ name: rspec
42
+ requirement: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - "~>"
45
+ - !ruby/object:Gem::Version
46
+ version: '3.0'
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '3.0'
54
+ - !ruby/object:Gem::Dependency
55
+ name: webmock
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '3.0'
61
+ type: :development
62
+ prerelease: false
63
+ version_requirements: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: '3.0'
68
+ description: Ruby client for the PostProxy API — manage social media posts, profiles,
69
+ and profile groups.
70
+ email:
71
+ - support@postproxy.dev
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - lib/postproxy.rb
78
+ - lib/postproxy/client.rb
79
+ - lib/postproxy/constants.rb
80
+ - lib/postproxy/errors.rb
81
+ - lib/postproxy/resources/posts.rb
82
+ - lib/postproxy/resources/profile_groups.rb
83
+ - lib/postproxy/resources/profiles.rb
84
+ - lib/postproxy/types.rb
85
+ - lib/postproxy/version.rb
86
+ homepage: https://postproxy.dev
87
+ licenses:
88
+ - MIT
89
+ metadata:
90
+ homepage_uri: https://postproxy.dev
91
+ source_code_uri: https://github.com/postproxy/postproxy-ruby
92
+ documentation_uri: https://postproxy.dev/getting-started/overview/
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ required_ruby_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '3.1'
101
+ required_rubygems_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: '0'
106
+ requirements: []
107
+ rubygems_version: 4.0.3
108
+ specification_version: 4
109
+ summary: Ruby client for the PostProxy API
110
+ test_files: []