Skip to content

ENH-296 Giving Tuesday, Metrics and Documentation - #297

Open
grant-minor-sntialtech wants to merge 9 commits into
mainfrom
ENH-296-GivingTuesday-Metrics-Docs
Open

ENH-296 Giving Tuesday, Metrics and Documentation#297
grant-minor-sntialtech wants to merge 9 commits into
mainfrom
ENH-296-GivingTuesday-Metrics-Docs

Conversation

@grant-minor-sntialtech

Copy link
Copy Markdown

No description provided.

@grant-minor-sntialtech

Copy link
Copy Markdown
Author

I believe to correct the prettier stuff I just run:
npm run lint:prettier

Correct?

Comment thread src/getMetrics.ts Outdated
@bickelj

bickelj commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

@grant-minor-sntialtech I don't want to get too pedantic about commit histories but I think we'll want to squash/rebase all the fixes into 1-3 commits before pushing. I asked GLM-5.2 for a review and it usually gives decent feedback.

@bickelj

bickelj commented Aug 20, 2026

Copy link
Copy Markdown
Collaborator

@grant-minor-sntialtech I think the enormous docs files might be too verbose to maintain. It looks like they were generated as summaries of what can be found in the code, and if they are useful I suppose they should stay. But perhaps they can be condensed to repeat less of what can be easily found when examining the code. I like the little tables showing which commands need PDC auth and which don't, though, that part is very handy.

@bickelj-agent

Copy link
Copy Markdown
Collaborator

Reviewed PR #297; npm run lint and the full Jest suite (68 tests) pass locally. Three follow-ups, posted inline: the pdc-bulk-uploaderpdc-metrics default change left the code comment and the docs inconsistent, and src/getMetrics-report.md is referenced but does not exist.

Minor, not commented inline
  • All three new docs use repo-relative links that resolve wrong from docs/ (e.g. [src/index.ts](src/index.ts)docs/src/index.ts); consider ../src/.... docs/getMetrics.md line 3 also drops the src/ prefix ([getMetrics.ts](getMetrics.ts)) while the other two docs keep it.
  • classifyHttpError reports Unexpected HTTP status undefined for transport errors with no response; a distinct note for the no-response case would read more clearly.

— GLM-5.2

Comment thread src/getMetrics.ts Outdated
Comment thread docs/getMetrics.md Outdated
@grant-minor-sntialtech

Copy link
Copy Markdown
Author

For the comment around:
classifyHttpError reports Unexpected HTTP status undefined for transport errors with no response; a distinct note for the no-response case would read more clearly.

I'm not an expert, but I don't believe there is a status for 'no response'. You still get a header and stuff... Is this to start tracking network timeouts?

@bickelj-agent bickelj-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

givingTuesday.ts mirrors large parts of the existing charityNavigator.ts; the three in-band comments cover the clearest copy-pasted helpers, and the handler-level duplication is listed below. — GLM-5.2

Additional duplication not commented in-band
  • The updateAll handler body (getChangemakers → flatMap taxId → filter valid/invalid → warn → fetch profiles → getTokengetOrCreateSourcepostChangemakerFieldValueBatch → sequential postChangemakerFieldValueWarnOnForbidden loop with the missingPermissionChangemakerIds set → final warn) is near-identical to charityNavigator.ts lines 416-489. A shared driver taking { records, getEin, getGoodAsOf, baseFieldMap, shortCode, label, notes } would collapse both.
  • The lookupFromPdc handlers share the same skeleton (getChangemakers → EIN extraction → validEins/invalidEins filter → warn → fetch → write-or-log).
  • JSON_SPACES = 2 and HTTP_STATUS_FORBIDDEN = 403 are redefined in charityNavigator.ts, givingTuesday.ts, and getMetrics.ts.

Comment thread src/givingTuesday.ts
Comment on lines +250 to +267
const postChangemakerFieldValueWarnOnForbidden = async (
baseUrl: string,
token: AccessTokenSet,
data: WritableChangemakerFieldValue,
warnedChangemakers: Set<number>, // Mutated! This is for observation/logs, not control!
): Promise<void> => {
try {
const fieldValue = await postChangemakerFieldValue(baseUrl, token, data);
logger.info(`Added changemaker field value: ${JSON.stringify(fieldValue)}`);
} catch (e: unknown) {
if (e instanceof AxiosError && e.status === HTTP_STATUS_FORBIDDEN) {
logger.warn(`No permission (403) to create ${JSON.stringify(data)}`);
warnedChangemakers.add(data.changemakerId);
} else {
throw e;
}
}
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function is byte-for-byte identical to charityNavigator.ts (lines 296-313). Extract it to a shared module (e.g. pdc-api.ts) so both givingTuesday and charityNavigator import one copy. — GLM-5.2

Comment thread src/givingTuesday.ts
Comment on lines +317 to +331
const getOrCreateSource = async (baseUrl: string, token: AccessTokenSet): Promise<Source> => {
const sources = await getSources(baseUrl, token);
const filteredSources = sources.entries.filter((s) => s.dataProviderShortCode === GT_SHORT_CODE);
if (filteredSources.length === 1 && filteredSources[0] !== undefined) {
// Hurray, an existing GivingTuesday Source was found, return it!
return filteredSources[0];
}
// Create the GivingTuesday Source, we expect/require the Data Provider to exist.
logger.warn('Have a `pdc-admin` create a source because only administrators may be able.');
// The following may not succeed, doesn't succeed as of this writing.
return await postSource(baseUrl, token, {
dataProviderShortCode: GT_SHORT_CODE,
label: 'GivingTuesday',
});
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mirrors charityNavigator.ts's getOrCreateSource (lines 383-397); only the short code (GT_SHORT_CODE vs CN_SHORT_CODE) and label differ. A shared getOrCreateSource(baseUrl, token, shortCode, label) would deduplicate it. — GLM-5.2

Comment thread src/givingTuesday.ts
Comment on lines +230 to +247
const getChangemakerByEin = (ein: string, changemakers: ChangemakerBundle): Changemaker | null => {
// Make the comparison with hyphens stripped and zero-padded to match the
// normalized EIN GivingTuesday echoes back in its records.
const normalized = toGivingTuesdayEin(ein);
const matches = changemakers.entries.filter((c) => toGivingTuesdayEin(c.taxId) === normalized);
if (matches.length > 1) {
logger.warn(`Found multiple changemakers with EIN ${ein}, not returning any.`);
return null;
}
if (matches.length < 1) {
logger.info(`Found no changemaker with EIN ${ein}`);
return null;
}
if (matches.length === 1 && matches[0] !== undefined) {
return matches[0];
}
throw new Error('How could this have happened?');
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Structurally identical to charityNavigator.ts's getChangemakerByEin (lines 278-293); only the EIN normalization differs (toGivingTuesdayEin vs replace('-','')). A shared helper taking a normalize function parameter would deduplicate it. — GLM-5.2

@bickelj bickelj left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@grant-minor-sntialtech If we already have run with the GT script, I'd be OK with merging as-is and doing a refactoring pass in a separate PR, what do you think?

Looks pretty good.

I still guess the generated docs will get stale, but such is life. If they're useful let's keep them. When something gets stale we could revisit.

Thanks for this! (Oh and squash when merging as you suggested)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants