LinkedIn: Page names from organizationsLookup, cached for a day
The organizations resource hit LinkedIn's app-wide daily cap; organizationsLookup has its own. Falls back to organizations, then ids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
41da5b3968
commit
db56b69ce6
@ -46,6 +46,34 @@ async function uploadVideo(token, owner, src) {
|
|||||||
return video;
|
return video;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Company Page names. LinkedIn caps lookups per app and member per day, so names are cached for a day and
|
||||||
|
// fetched in batches of 50, from organizationsLookup first and the organizations resource if that is capped.
|
||||||
|
const NAME_TTL = 24 * 3600 * 1000;
|
||||||
|
const nameCache = new Map();
|
||||||
|
async function pageNames(token, ids) {
|
||||||
|
const names = {};
|
||||||
|
const missing = [];
|
||||||
|
for (const id of ids) {
|
||||||
|
const hit = nameCache.get(id);
|
||||||
|
if (hit && Date.now() - hit.at < NAME_TTL) names[id] = hit.name; else missing.push(id);
|
||||||
|
}
|
||||||
|
for (let i = 0; i < missing.length; i += 50) {
|
||||||
|
const list = `List(${missing.slice(i, i + 50).join(",")})`;
|
||||||
|
for (const resource of ["organizationsLookup", "organizations"]) {
|
||||||
|
try {
|
||||||
|
const r = await request("LinkedIn", `${API}/rest/${resource}?ids=${list}`, rest(token));
|
||||||
|
for (const [id, o] of Object.entries(r.data.results || {})) {
|
||||||
|
if (!o.localizedName) continue;
|
||||||
|
names[id] = o.localizedName;
|
||||||
|
nameCache.set(id, { name: o.localizedName, at: Date.now() });
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
} catch { /* capped or not allowed: try the next resource, else keep ids */ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
id: "linkedin",
|
id: "linkedin",
|
||||||
name: "LinkedIn",
|
name: "LinkedIn",
|
||||||
@ -84,14 +112,7 @@ export default {
|
|||||||
try {
|
try {
|
||||||
const { data } = await request("LinkedIn", `${API}/rest/organizationAcls`, { ...rest(tokens.accessToken), query: { q: "roleAssignee", role: "ADMINISTRATOR", state: "APPROVED" } });
|
const { data } = await request("LinkedIn", `${API}/rest/organizationAcls`, { ...rest(tokens.accessToken), query: { q: "roleAssignee", role: "ADMINISTRATOR", state: "APPROVED" } });
|
||||||
const ids = (data.elements || []).map((e) => String(e.organization).split(":").pop());
|
const ids = (data.elements || []).map((e) => String(e.organization).split(":").pop());
|
||||||
// One batch call per 50 Pages: single-Page lookups have a small daily limit per member.
|
const names = await pageNames(tokens.accessToken, ids);
|
||||||
const names = {};
|
|
||||||
for (let i = 0; i < ids.length; i += 50) {
|
|
||||||
try {
|
|
||||||
const r = await request("LinkedIn", `${API}/rest/organizations?ids=List(${ids.slice(i, i + 50).join(",")})`, rest(tokens.accessToken));
|
|
||||||
for (const [id, o] of Object.entries(r.data.results || {})) names[id] = o.localizedName;
|
|
||||||
} catch { /* keep ids */ }
|
|
||||||
}
|
|
||||||
for (const id of ids) out.push({ id: `urn:li:organization:${id}`, name: `${names[id] || `Company ${id}`} (company Page)` });
|
for (const id of ids) out.push({ id: `urn:li:organization:${id}`, name: `${names[id] || `Company ${id}`} (company Page)` });
|
||||||
} catch { /* no organization scopes: personal profile only */ }
|
} catch { /* no organization scopes: personal profile only */ }
|
||||||
return out;
|
return out;
|
||||||
|
|||||||
@ -141,7 +141,7 @@ test("LinkedIn: connect, list company Pages, post image to a company Page", asyn
|
|||||||
const { conn } = await connect("linkedin", "acme", { identify: [
|
const { conn } = await connect("linkedin", "acme", { identify: [
|
||||||
["GET", "https://api.linkedin.com/v2/me", json({ id: "abc", localizedFirstName: "Pat", localizedLastName: "Lee" })],
|
["GET", "https://api.linkedin.com/v2/me", json({ id: "abc", localizedFirstName: "Pat", localizedLastName: "Lee" })],
|
||||||
["GET", "https://api.linkedin.com/rest/organizationAcls", json({ elements: [{ organization: "urn:li:organization:42" }] })],
|
["GET", "https://api.linkedin.com/rest/organizationAcls", json({ elements: [{ organization: "urn:li:organization:42" }] })],
|
||||||
["GET", "https://api.linkedin.com/rest/organizations?ids=List(42)", json({ results: { 42: { localizedName: "Acme Co" } } })],
|
["GET", "https://api.linkedin.com/rest/organizationsLookup?ids=List(42)", json({ results: { 42: { localizedName: "Acme Co" } } })],
|
||||||
] });
|
] });
|
||||||
assert.equal(conn.account.name, "Pat Lee");
|
assert.equal(conn.account.name, "Pat Lee");
|
||||||
const targets = await P.targetsFor(conn.id);
|
const targets = await P.targetsFor(conn.id);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user