Skip to content

Commit f86512d

Browse files
committed
WIP Draft that attempts to use new endpoints to post fields
1 parent 53cdcfc commit f86512d

File tree

2 files changed

+129
-7
lines changed

2 files changed

+129
-7
lines changed

src/charityNavigator.ts

Lines changed: 61 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ import { HttpLink } from '@apollo/client/link/http';
77
import { isValidEin } from './ein';
88
import { logger } from './logger';
99
import { AccessTokenSet, getToken, oidcOptions } from './oidc';
10-
import { getChangemakers, getSources, postSource } from './pdc-api';
10+
import {
11+
getChangemakers, getSources, postChangemakerFieldValue, postChangemakerFieldValueBatch,
12+
postSource,
13+
} from './pdc-api';
1114
import type { CommandModule } from 'yargs';
12-
import type { Source } from '@pdc/sdk';
15+
import type { Changemaker, ChangemakerBundle, Source } from '@pdc/sdk';
1316

1417
const CN_SHORT_CODE = 'charitynav';
1518

@@ -24,8 +27,18 @@ interface NonprofitPublic {
2427
encompassScore?: number,
2528
encompassStarRating?: number
2629
encompassPublicationDate?: string,
30+
size?: string,
31+
cause?: string,
2732
}
2833

34+
/** Map from Charity Navigator NonprofitPublic attribute name to PDC base field name */
35+
const baseFieldMap = {
36+
name: 'organization_name',
37+
website: 'organization_website',
38+
phone: 'organization_phone',
39+
mission: 'organization_mission_statement',
40+
};
41+
2942
interface PageInfo {
3043
totalPages: number;
3144
totalItems: number;
@@ -72,6 +85,8 @@ NonprofitsPublicVariables
7285
encompassScore
7386
encompassStarRating
7487
encompassPublicationDate
88+
size
89+
cause
7590
}
7691
pageInfo {
7792
totalPages
@@ -205,6 +220,22 @@ const lookupCommand: CommandModule<unknown, LookupCommandArgs> = {
205220
},
206221
};
207222

223+
const getChangemakerByEin = (ein: string, changemakers: ChangemakerBundle): Changemaker | null => {
224+
const matches = changemakers.entries.filter((c) => c.taxId === ein);
225+
if (matches.length > 1) {
226+
logger.warn(`Found multiple changemakers with EIN ${ein}, not returning any.`);
227+
return null;
228+
}
229+
if (matches.length < 1) {
230+
logger.info(`Found no changemaker with EIN ${ein}`);
231+
return null;
232+
}
233+
if (matches.length === 1 && matches[0] !== undefined) {
234+
return matches[0];
235+
}
236+
throw new Error('How could this have happened?');
237+
};
238+
208239
const getOrCreateSource = async (baseUrl: string, token: AccessTokenSet): Promise<Source> => {
209240
const sources = await getSources(baseUrl, token);
210241
const filteredSources = sources.entries.filter((s) => s.dataProviderShortCode === CN_SHORT_CODE);
@@ -262,15 +293,38 @@ const updateAllCommand: CommandModule<unknown, UpdateAllCommandArgs> = {
262293
args.oidcClientId,
263294
args.oidcClientSecret,
264295
);
296+
if (!charityNavResponse.data) {
297+
logger.warn('No data found');
298+
return;
299+
}
265300
// First, find the existing source. As of this writing, it cannot be created by non-admins.
266301
const source = await getOrCreateSource(args.pdcApiBaseUrl, token);
267302
logger.info(source, 'The PDC Source for Charity Navigator was found');
268303
// Second, post the fields to PDC
269-
if (charityNavResponse.data) {
270-
const { edges } = charityNavResponse.data.nonprofitsPublic;
271-
const nonprofits = edges.filter((e): e is NonprofitPublic => isNonprofitPublic(e));
272-
logger.info(nonprofits, 'Found these nonprofits');
273-
}
304+
const { edges } = charityNavResponse.data.nonprofitsPublic;
305+
const nonprofits = edges.filter((e): e is NonprofitPublic => isNonprofitPublic(e));
306+
logger.info(nonprofits, 'Found these nonprofits');
307+
// Third, register a batch of changemaker fields to be posted
308+
const fieldBatch = await postChangemakerFieldValueBatch(args.pdcApiBaseUrl, token, { sourceId: source.id, notes: `data-scripts charityNavigator.ts execution ${Date.now()}` });
309+
// Last, for each nonprofit, for each field, post the field
310+
edges.map(async (e) => {
311+
const changemaker = getChangemakerByEin(e.ein, changemakers);
312+
if (changemaker !== null) {
313+
Object.entries(baseFieldMap).map(async ([cnAttributeName, baseFieldShortCode]) => {
314+
const cnAttribute = e[cnAttributeName as keyof NonprofitPublic];
315+
if (cnAttribute !== undefined) {
316+
const fieldValue = await postChangemakerFieldValue(args.pdcApiBaseUrl, token, {
317+
changemakerId: changemaker.id,
318+
batchId: fieldBatch.id,
319+
baseFieldShortCode,
320+
value: cnAttribute.toString(),
321+
goodAsOf: e.updatedAt,
322+
});
323+
logger.info(`Added changemaker field value: ${JSON.stringify(fieldValue)}`);
324+
}
325+
});
326+
}
327+
});
274328
},
275329
};
276330

src/pdc-api.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,70 @@ const postSource = (baseUrl: string, token: AccessTokenSet, data: WritableSource
9898
)
9999
);
100100

101+
// TODO: use the SDK, delete these temp types copied from the service repo
102+
interface ChangemakerFieldValueBatch {
103+
readonly id: number;
104+
sourceId: number;
105+
notes: string | null;
106+
readonly createdAt: string;
107+
readonly source: Source;
108+
}
109+
interface ChangemakerFieldValue {
110+
readonly id: number;
111+
changemakerId: number;
112+
baseFieldShortCode: string;
113+
batchId: number;
114+
value: string;
115+
readonly file: File | null;
116+
goodAsOf: string | null;
117+
readonly createdAt: string;
118+
readonly baseField: BaseField;
119+
readonly batch: ChangemakerFieldValueBatch;
120+
readonly isValid: boolean;
121+
}
122+
123+
interface WritableChangemakerFieldValueBatch {
124+
sourceId: number;
125+
notes: string | null;
126+
}
127+
interface WritableChangemakerFieldValue {
128+
changemakerId: number;
129+
baseFieldShortCode: string;
130+
batchId: number;
131+
value: string;
132+
goodAsOf: string | null;
133+
}
134+
135+
const postChangemakerFieldValueBatch = (
136+
baseUrl: string,
137+
token: AccessTokenSet,
138+
data: WritableChangemakerFieldValueBatch,
139+
) => (
140+
callPdcApi<ChangemakerFieldValueBatch>(
141+
baseUrl,
142+
'/changemakerFieldValueBatches',
143+
{},
144+
'post',
145+
token,
146+
data,
147+
)
148+
);
149+
150+
const postChangemakerFieldValue = (
151+
baseUrl: string,
152+
token: AccessTokenSet,
153+
data: WritableChangemakerFieldValue,
154+
) => (
155+
callPdcApi<ChangemakerFieldValue>(
156+
baseUrl,
157+
'/changemakerFieldValues',
158+
{},
159+
'post',
160+
token,
161+
data,
162+
)
163+
);
164+
101165
const postPlatformProviderData = (
102166
baseUrl: string,
103167
token: AccessTokenSet,
@@ -120,10 +184,14 @@ const postPlatformProviderData = (
120184
);
121185

122186
export {
187+
ChangemakerFieldValue,
188+
ChangemakerFieldValueBatch,
123189
getBaseFields,
124190
getChangemakers,
125191
getProposals,
126192
getSources,
193+
postChangemakerFieldValueBatch,
194+
postChangemakerFieldValue,
127195
postPlatformProviderData,
128196
postSource,
129197
};

0 commit comments

Comments
 (0)