instagram_connect 0.3.0 → 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
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 1d1a0dd271f5e3f830351ddd25d62794b512c7786f125b6aa2f5ea8167db1423
|
|
4
|
+
data.tar.gz: 0e211865a1e788987b1fdb64f739bb2cde4c08ef57821b6b7602e23b22689cf3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8df4d4149716e96900c767391f73c820b6777f0962c0f7e1d3c4e2522984f7af27da083ce75ada8092bd188dd9897053767e6c1fb2e7654291f6bff7a0c0ce66
|
|
7
|
+
data.tar.gz: 97a67eb17002fd5611fb76f53fc6e5a852ed8d8a62875f07a367258fe16758fa16556194b82fa61eea270ca131649df78027821618f3aadfb6c9fa92e5f0d269
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,27 @@ All notable changes to this project are documented here. The format follows
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.3.1] - 2026-07-26
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Connecting an account failed when the Page came from the Login-for-Business asset picker.**
|
|
14
|
+
`/me/accounts` lists only the Pages a token may *enumerate*. A Page granted through the picker is
|
|
15
|
+
absent from that listing while reading perfectly well by id, so the list came back empty and the
|
|
16
|
+
connect was refused — on an account that was correctly linked and fully granted. Identity
|
|
17
|
+
resolution now falls back to the assets the token actually carries (`/debug_token` granular
|
|
18
|
+
scopes, which needs no permission beyond the app's own credentials) and reads those Pages by id.
|
|
19
|
+
- **A failed Graph call was reported as a missing account.** `resolve_identity` never checked
|
|
20
|
+
`Result#success?`, so an expired token or an HTTP 400 produced the same message as an empty list.
|
|
21
|
+
API failures now raise `ApiError` carrying Meta's own message.
|
|
22
|
+
- **The error message asserted a cause it had not verified.** It claimed no Instagram account was
|
|
23
|
+
linked to a Page, which was false in exactly the case that triggered it. It now states what was
|
|
24
|
+
actually checked.
|
|
25
|
+
- **`AccountReadinessJob` had the same flaw**, hunting for a known Page inside `/me/accounts`
|
|
26
|
+
instead of reading it by id — so the Page-token swap and the webhook subscription failed for the
|
|
27
|
+
same accounts, silently.
|
|
28
|
+
|
|
29
|
+
|
|
9
30
|
## [0.3.0] - 2026-07-26
|
|
10
31
|
|
|
11
32
|
Conversations and engagement. The gem parsed 2 of the 15 webhook fields Meta can
|
|
@@ -87,8 +87,10 @@ module InstagramConnect
|
|
|
87
87
|
return
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
|
|
90
|
+
# Read the Page directly rather than hunting for it in /me/accounts: we
|
|
91
|
+
# already know its id, and the listing omits Pages granted through the
|
|
92
|
+
# Login-for-Business asset picker even though they read fine by id.
|
|
93
|
+
page = graph_get(account, "/#{account.page_id}", fields: "id,access_token")
|
|
92
94
|
|
|
93
95
|
if page.nil? || page["access_token"].blank?
|
|
94
96
|
account.update!(needs_reconnect: true,
|
|
@@ -157,6 +157,26 @@ module InstagramConnect
|
|
|
157
157
|
get("/me/accounts", { fields: "id,name,access_token,instagram_business_account" })
|
|
158
158
|
end
|
|
159
159
|
|
|
160
|
+
# One Page by id. /me/accounts answers for the Pages a token may *enumerate*;
|
|
161
|
+
# this answers for a Page it may *read*. Those are not the same set — a Page
|
|
162
|
+
# granted through the Login-for-Business asset picker is readable here while
|
|
163
|
+
# absent from the listing.
|
|
164
|
+
def page(page_id)
|
|
165
|
+
get("/#{page_id}", { fields: "id,name,access_token,instagram_business_account" })
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# The asset ids this token actually carries, from Meta's own record of the
|
|
169
|
+
# consent. Needs no permission beyond the app's own credentials.
|
|
170
|
+
def granted_asset_ids
|
|
171
|
+
result = get("/debug_token", { input_token: access_token,
|
|
172
|
+
access_token: "#{config.app_id}|#{config.app_secret}" })
|
|
173
|
+
return [] unless result.success?
|
|
174
|
+
|
|
175
|
+
Array(result.data.dig("data", "granular_scopes"))
|
|
176
|
+
.flat_map { |scope| Array(scope["target_ids"]) }
|
|
177
|
+
.uniq
|
|
178
|
+
end
|
|
179
|
+
|
|
160
180
|
# Walks a Graph collection to the end, following Meta's own cursors.
|
|
161
181
|
#
|
|
162
182
|
# Offsets are not safe here: a collection can shift between calls, so an
|
|
@@ -35,11 +35,34 @@ module InstagramConnect
|
|
|
35
35
|
def resolve_identity(data)
|
|
36
36
|
return { ig_user_id: data[:ig_user_id], page_id: data[:page_id] } if data[:ig_user_id]
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
page =
|
|
40
|
-
|
|
38
|
+
client = Client.new(access_token: data[:access_token], config: @config)
|
|
39
|
+
page = candidate_pages(client).find { |p| p["instagram_business_account"] }
|
|
40
|
+
unless page
|
|
41
|
+
raise ConfigurationError,
|
|
42
|
+
"connected, but no Page with a linked Instagram business account was found — " \
|
|
43
|
+
"checked the Pages this token can list and the assets it was granted"
|
|
44
|
+
end
|
|
41
45
|
|
|
42
|
-
{ ig_user_id: page.dig("instagram_business_account", "id"), page_id: page["id"] }
|
|
46
|
+
{ ig_user_id: page.dig("instagram_business_account", "id").to_s, page_id: page["id"].to_s }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# /me/accounts lists only the Pages a token may enumerate, and a Page granted
|
|
50
|
+
# through the Login-for-Business asset picker is not one of them — the list
|
|
51
|
+
# comes back empty while the Page itself reads fine. So when the listing has
|
|
52
|
+
# nothing usable, ask the token which assets it carries and read those.
|
|
53
|
+
def candidate_pages(client)
|
|
54
|
+
listed = client.list_pages
|
|
55
|
+
unless listed.success?
|
|
56
|
+
raise ApiError, "could not read Pages from Instagram: #{listed.error_message}"
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
pages = Array(listed.data["data"])
|
|
60
|
+
return pages if pages.any? { |p| p["instagram_business_account"] }
|
|
61
|
+
|
|
62
|
+
client.granted_asset_ids.filter_map do |id|
|
|
63
|
+
result = client.page(id)
|
|
64
|
+
result.data if result.success?
|
|
65
|
+
end
|
|
43
66
|
end
|
|
44
67
|
end
|
|
45
68
|
end
|