Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"author": "Open Tech Strategies",
"license": "AGPL-3.0-or-later",
"devDependencies": {
"@pdc/sdk": "^0.26.1",
"@pdc/sdk": "^0.35.1",
"@types/node": "^24.12.2",
"@types/yargs": "^17.0.32",
"@typescript-eslint/eslint-plugin": "^5.62.0",
Expand Down
67 changes: 67 additions & 0 deletions src/charityNavigator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,12 @@ interface LookupCommandArgs {
outputFile?: string;
}

interface LookupFromPdcCommandArgs {
'charity-navigator-api-key'?: string;
'pdc-api-base-url': string;
outputFile?: string;
}

interface UpdateAllCommandArgs {
'charity-navigator-api-key'?: string;
'oidc-base-url': string,
Expand Down Expand Up @@ -237,6 +243,66 @@ const getChangemakerByEin = (ein: string, changemakers: ChangemakerBundle): Chan
throw new Error('How could this have happened?');
};

const lookupFromPdcCommand: CommandModule<unknown, LookupFromPdcCommandArgs> = {
command: 'lookupFromPdc',
describe: 'Fetch and display information about organizations present in PDC',
builder: (y) => (y
.option('charity-navigator-api-key', {
describe: 'CharityNavigator API key; get from account management at https://developer.charitynavigator.org/ (can also be set via DS_CHARITY_NAVIGATOR_API_KEY env var)',
demandOption: false,
type: 'string',
})
.check((argv) => {
if (!argv.charityNavigatorApiKey) {
throw new Error('Missing required argument: charity-navigator-api-key (set via CLI or DS_CHARITY_NAVIGATOR_API_KEY env var)');
}
return true;
})
.option('output-file', {
alias: 'write',
describe: 'Write organization information to the specified JSON file',
normalize: true,
type: 'string',
})
.option('pdc-api-base-url', {
describe: 'Location of PDC API',
demandOption: true,
type: 'string',
})
),
handler: async (args) => {
const { charityNavigatorApiKey: apiKey, pdcApiBaseUrl } = args;
if (!apiKey) {
throw new Error('Missing required argument: charity-navigator-api-key');
}
if (!pdcApiBaseUrl) {
throw new Error('Missing required argument: pdc-api-base-url');
}
const changemakers = await getChangemakers(args.pdcApiBaseUrl);
const eins = changemakers.entries.flatMap((c) => c.taxId);
// Charity Navigator expects no hyphens, strip them from EINs after validation.
const validEins = eins.filter(isValidEin).flatMap((e) => e.replace('-', ''));
const invalidEins = eins.filter((e) => !isValidEin(e));
if (invalidEins.length > 0) {
logger.warn(invalidEins, 'These EINs in PDC are invalid and will not be queried');
}
logger.info(validEins, 'Found these valid EINs which will be requested from Charity Navigator');
const charityNavResponse = await getCharityNavigatorProfiles(
apiKey,
validEins,
);
if (args.outputFile) {
await writeFile(
args.outputFile,
JSON.stringify(charityNavResponse, null, 2),
);
logger.info(`Wrote CharityNavigator data for ${JSON.stringify(args.ein)} to ${JSON.stringify(args.outputFile)}`);
} else {
logger.info({ charityNavResponse }, 'CharityNavigator result');
}
},
};

const getOrCreateSource = async (baseUrl: string, token: AccessTokenSet): Promise<Source> => {
const sources = await getSources(baseUrl, token);
const filteredSources = sources.entries.filter((s) => s.dataProviderShortCode === CN_SHORT_CODE);
Expand Down Expand Up @@ -336,6 +402,7 @@ const charityNavigator: CommandModule = {
describe: 'Interact with the CharityNavigator Premier API',
builder: (y) => (y
.command(lookupCommand)
.command(lookupFromPdcCommand)
.command(updateAllCommand)
.demandCommand(1)
),
Expand Down
8 changes: 6 additions & 2 deletions src/pdc-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { client } from './client';
import type { AccessTokenSet } from './oidc';
import type {
BaseField, ProposalBundle, ChangemakerBundle, SourceBundle, Source,
BaseFieldBundle,
} from '@pdc/sdk';

const callPdcApi = async <T>(
Expand All @@ -27,10 +28,13 @@ const callPdcApi = async <T>(
};

const getBaseFields = (baseUrl: string, token: AccessTokenSet) => (
callPdcApi<BaseField[]>(
callPdcApi<BaseFieldBundle>(
baseUrl,
'/baseFields',
{},
{
_page: '1',
_count: '2147483647',
},
'get',
token,
)
Expand Down