@mindful-web/export-framework 1.57.0 → 1.68.7

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.
@@ -0,0 +1,69 @@
1
+ const replaceCharacter = (t, from, to) => {
2
+ let text = t.replace(from, to);
3
+ if (text.includes(from)) text = replaceCharacter(text, from, to);
4
+ return text;
5
+ };
6
+ const formatText = (t) => {
7
+ if (t === null) {
8
+ return null;
9
+ }
10
+ // https://www.compart.com/en/unicode/U+00E3
11
+ let text = t;
12
+ const trans = [];
13
+ trans.push({ from: ' ', to: ' ' });
14
+ trans.push({ from: ' ', to: ' ' });
15
+ trans.push({ from: ' , ', to: ', ' });
16
+ trans.push({ from: ' , ', to: ', ' });
17
+ trans.push({ from: 'ä', to: '<0x00E4>' });
18
+ trans.push({ from: 'â', to: '<0x00E2>' });
19
+ trans.push({ from: 'ã', to: '<0x00E3>' });
20
+ trans.push({ from: 'ß', to: '<0x00DF>' });
21
+ trans.push({ from: 'ç', to: '<0x00E7>' });
22
+ trans.push({ from: 'è', to: '<0x00E8>' });
23
+ trans.push({ from: 'é', to: '<0x00E9>' });
24
+ trans.push({ from: 'ï', to: '<0x00EF>' });
25
+ trans.push({ from: 'í', to: '<0x00ED>' });
26
+ trans.push({ from: 'É', to: '<0x00C9>' });
27
+ trans.push({ from: 'ñ', to: '<0x00F1>' });
28
+ trans.push({ from: 'ó', to: '<0x00F3>' });
29
+ trans.push({ from: 'ö', to: '<0x00F6>' });
30
+ trans.push({ from: 'ú', to: '<0x00FA>' });
31
+ trans.push({ from: 'ü', to: '<0x00FC>' });
32
+ trans.push({ from: 'Ü', to: '<0x00DC>' });
33
+ trans.push({ from: '&#39;', to: "'" });
34
+ trans.push({ from: '&quot', to: '"' });
35
+ trans.push({ from: '&hellip;', to: '<0x2026>' });
36
+ trans.push({ from: '&frac14;', to: '<0x00BC>' });
37
+ trans.push({ from: '&frac12;', to: '<0x00BD>' });
38
+ trans.push({ from: '&frac34;', to: '<0x00BE>' });
39
+ trans.push({ from: '&lsquo;', to: '<0x2018>' });
40
+ trans.push({ from: '’', to: '<0x2019>' });
41
+ trans.push({ from: '&rsquo;', to: '<0x2019>' });
42
+ trans.push({ from: '“', to: '<0x201C>' });
43
+ trans.push({ from: '&ldquo;', to: '<0x201C>' });
44
+ trans.push({ from: '”', to: '<0x201D>' });
45
+ trans.push({ from: '&rdquo;', to: '<0x201D>' });
46
+ trans.push({ from: '&bull;', to: '<0x2022>' });
47
+ trans.push({ from: '|0x2022|', to: '<0x2022>' });
48
+ trans.push({ from: '&ndash;', to: '<0x2013>' });
49
+ trans.push({ from: '—', to: '<0x2014>' });
50
+ trans.push({ from: '&mdash;', to: '<0x2014>' });
51
+ trans.push({ from: '&trade;', to: '<0x2122>' });
52
+ trans.push({ from: '&copy;', to: '<0x00A9>' });
53
+ trans.push({ from: '®', to: '<0x00AE>' });
54
+ trans.push({ from: '&reg;', to: '<0x00AE>' });
55
+ trans.push({ from: 'º', to: '<0x00B0>' });
56
+ trans.push({ from: '&deg;', to: '<0x00B0>' });
57
+ trans.push({ from: '\\', to: '\\\\' });
58
+ // eslint-disable-next-line no-useless-escape
59
+ trans.push({ from: '&lt;', to: '\<' });
60
+ // eslint-disable-next-line no-useless-escape
61
+ trans.push({ from: '&gt;', to: '\>' });
62
+ trans.forEach((tran) => {
63
+ if (text.includes(tran.from)) text = replaceCharacter(text, tran.from, tran.to);
64
+ });
65
+
66
+ return text.trim();
67
+ };
68
+
69
+ module.exports = { formatText };
@@ -0,0 +1,11 @@
1
+ const { getAsArray } = require('@mindful-web/object-path');
2
+
3
+ const getChildSections = (section, sections = {}, includeSelf = true) => {
4
+ const { id } = section;
5
+ const children = getAsArray(section, 'children.edges').map(({ node }) => node);
6
+ return {
7
+ ...children.reduce((obj, child) => getChildSections(child, obj), sections),
8
+ ...(includeSelf && !section[id] && { [id]: section }),
9
+ };
10
+ };
11
+ module.exports = { getChildSections };
@@ -0,0 +1,54 @@
1
+ const path = require('path');
2
+ const fetch = require('node-fetch');
3
+ const fs = require('fs');
4
+ const zipFolder = require('zip-folder');
5
+ const AWS = require('aws-sdk');
6
+
7
+ // AWS credentials are validated at startup by tenants/all/env.js (envalid).
8
+ // We read process.env directly here to avoid coupling this shared util to
9
+ // any particular tenant's env.js location.
10
+ const s3 = new AWS.S3({
11
+ accessKeyId: process.env.AWS_ACCESS_KEY,
12
+ secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
13
+ });
14
+
15
+ const downloadImages = async (tmpDir, filePaths) => Promise.all(filePaths.map((url) => {
16
+ // create the directory if it doesn't exists
17
+ if (!fs.existsSync(tmpDir)) {
18
+ fs.mkdirSync(tmpDir, { recursive: true });
19
+ }
20
+ const fileName = path.basename(url);
21
+ return fetch(url).then((res) => {
22
+ const dest = fs.createWriteStream(`${tmpDir}/${fileName}`);
23
+ res.body.pipe(dest);
24
+ });
25
+ }));
26
+
27
+ const zipItUp = (tmpDirToZip, tmpDirToPlace, exportName) => new Promise((resolve, reject) => {
28
+ zipFolder(tmpDirToZip, `${tmpDirToPlace}/${exportName}`, (err) => {
29
+ if (err) {
30
+ reject();
31
+ } else {
32
+ resolve();
33
+ }
34
+ });
35
+ });
36
+
37
+ const uploadToS3 = (bucket, keyPrefix, filePath) => {
38
+ const fileName = path.basename(filePath);
39
+ const fileStream = fs.createReadStream(filePath);
40
+ const keyName = path.join(keyPrefix, fileName);
41
+ return new Promise((resolve, reject) => {
42
+ fileStream.once('error', reject);
43
+ s3.upload(
44
+ {
45
+ Bucket: bucket,
46
+ Key: keyName,
47
+ Body: fileStream,
48
+ ContentType: 'application/zip',
49
+ },
50
+ ).promise().then(resolve, reject);
51
+ });
52
+ };
53
+
54
+ module.exports = { downloadImages, zipItUp, uploadToS3 };
@@ -0,0 +1,74 @@
1
+ const { getAsArray, getAsObject } = require('@mindful-web/object-path');
2
+
3
+ // @todo clean this up
4
+ const buildVars = (variables, cursorPath, endCursor) => {
5
+ const keys = cursorPath.split('.');
6
+ if (keys.length === 0) {
7
+ return { ...variables, endCursor };
8
+ }
9
+ if (keys.length === 1) {
10
+ return { ...variables, [keys[0]]: endCursor };
11
+ }
12
+ if (keys.length === 2) {
13
+ const k1 = keys[0];
14
+ const k2 = keys[1];
15
+ return {
16
+ ...variables,
17
+ [k1]: {
18
+ ...variables[k1],
19
+ [k2]: endCursor,
20
+ },
21
+ };
22
+ }
23
+ if (keys.length === 3) {
24
+ const k1 = keys[0];
25
+ const k2 = keys[1];
26
+ const k3 = keys[2];
27
+ return {
28
+ ...variables,
29
+ [k1]: {
30
+ ...variables[k1],
31
+ [k2]: {
32
+ ...variables[k1][k2],
33
+ [k3]: endCursor,
34
+ },
35
+ },
36
+ };
37
+ }
38
+ throw new Error(`Unable to parse cursorPath ${cursorPath}`);
39
+ };
40
+
41
+ /**
42
+ * Returns all results from the specified query
43
+ * @param results - The results to accumulate
44
+ * @param client - The GraphQL client
45
+ * @param query - The GraphQL query
46
+ * @param variables - The GraphQL query variables
47
+ * @param cursorPath - The dot-notated path within `variables` that the cursor should be placed
48
+ * @param rootValue - The root query key, e.g; `data.queryName`
49
+ */
50
+ const executor = async (args) => {
51
+ const {
52
+ results = [],
53
+ client,
54
+ query,
55
+ variables,
56
+ cursorPath,
57
+ rootValue,
58
+ } = args;
59
+ const r = await client.query({ query, variables }, rootValue);
60
+ const items = getAsArray(r, `data.${rootValue}.edges`).map(({ node }) => node);
61
+ const pageInfo = getAsObject(r, `data.${rootValue}.pageInfo`);
62
+ if (pageInfo.hasNextPage) {
63
+ const { endCursor } = pageInfo;
64
+ const vars = buildVars(variables, cursorPath, endCursor);
65
+ return executor({
66
+ ...args,
67
+ variables: vars,
68
+ results: [...results, ...items],
69
+ });
70
+ }
71
+ return [...results, ...items];
72
+ };
73
+
74
+ module.exports = executor;
@@ -0,0 +1,6 @@
1
+ const replaceCharacters = (t, from, to) => {
2
+ let text = t.replace(from, to);
3
+ if (text.includes(from)) text = replaceCharacters(text, from, to);
4
+ return text;
5
+ };
6
+ module.exports = { replaceCharacters };
@@ -0,0 +1,109 @@
1
+ const { get, getAsArray } = require('@mindful-web/object-path');
2
+ const paginateQuery = require('./paginate-query');
3
+
4
+ /**
5
+ * Retrieve all published companies for a site, applying optional magazine and section filters.
6
+ *
7
+ * Each returned company is augmented with a `sectionIds` array (the section IDs from its
8
+ * currently-active websiteSchedules) and — when `attachTaxonomyIds` is enabled — a
9
+ * `taxonomyIds` array (the node IDs from its taxonomy edges).
10
+ *
11
+ * Usage examples:
12
+ *
13
+ * // Plain — no magazine filter:
14
+ * retrieveCompanies(apollo, query, siteId);
15
+ * retrieveCompanies(apollo, query, siteId, { additionalParams: { taxonomyId: 12 } });
16
+ *
17
+ * // With a magazine-schedule filter (company must appear in this issue):
18
+ * retrieveCompanies(apollo, query, siteId, {
19
+ * magazineSchedule: { sectionId: PRINT_SECTION_ID, issueId: PRINT_ISSUE_ID },
20
+ * });
21
+ *
22
+ * // Every option enabled (e.g. for an "industry leaders" style listing).
23
+ * // descendantSectionIds is any list of section IDs whose companies should
24
+ * // also count as matches, even without an active website schedule.
25
+ * retrieveCompanies(apollo, query, siteId, {
26
+ * injectSiteIdInQuery: true,
27
+ * magazineSchedule: { sectionId: PRINT_SECTION_ID, issueId: PRINT_ISSUE_ID },
28
+ * descendantSectionIds: DESCENDANT_SECTION_IDS,
29
+ * attachTaxonomyIds: true,
30
+ * });
31
+ *
32
+ * @param {ApolloClient} apollo GraphQL client used for paginated queries.
33
+ * @param {DocumentNode} query GraphQL query selecting `allPublishedContent` of Companies.
34
+ * @param {string} [siteId]
35
+ * When set, scopes websiteSchedules and primarySite checks to this site.
36
+ * @param {object} [options]
37
+ * @param {object} [options.additionalParams={}]
38
+ * Extra fields spread into the GraphQL `input` variables.
39
+ * @param {boolean} [options.injectSiteIdInQuery=false]
40
+ * When true, also injects `siteId` into the GraphQL `input` for server-side filtering.
41
+ * @param {{sectionId:number, issueId:number}|null} [options.magazineSchedule=null]
42
+ * When provided, a company must have a `magazineSchedules` entry matching this
43
+ * `{sectionId, issueId}` pair to be included.
44
+ * @param {number[]} [options.descendantSectionIds=[]]
45
+ * Additional inclusion path: companies whose `primarySection.id` is in this list are
46
+ * kept even without a website-schedule match (e.g. an "industry leaders" tree where
47
+ * every descendant section should also count as a match).
48
+ * @param {boolean} [options.attachTaxonomyIds=false]
49
+ * When true, attach a `taxonomyIds` array derived from `taxonomy.edges` to each result.
50
+ *
51
+ * @returns {Promise<object[]>} Array of companies, each with `sectionIds`
52
+ * (and optionally `taxonomyIds`).
53
+ */
54
+ const retrieveCompanies = async (apollo, query, siteId, options = {}) => {
55
+ const {
56
+ additionalParams = {},
57
+ injectSiteIdInQuery = false,
58
+ magazineSchedule = null,
59
+ descendantSectionIds = [],
60
+ attachTaxonomyIds = false,
61
+ } = options;
62
+
63
+ const promise = await paginateQuery({
64
+ client: apollo,
65
+ query,
66
+ variables: {
67
+ input: {
68
+ includeContentTypes: 'Company',
69
+ ...(injectSiteIdInQuery ? { siteId } : null),
70
+ pagination: { limit: 250 },
71
+ sort: { field: 'name', order: 'asc' },
72
+ ...additionalParams,
73
+ },
74
+ },
75
+ cursorPath: 'input.pagination.after',
76
+ rootValue: 'allPublishedContent',
77
+ });
78
+
79
+ const now = Date.now().valueOf();
80
+ return promise.reduce((arr, company) => {
81
+ const sectionIds = (siteId)
82
+ ? getAsArray(company, 'websiteSchedules')
83
+ // eslint-disable-next-line max-len
84
+ .filter(({ section, start, end }) => get(section, 'site.id') === siteId && start < now && (!end || end > now))
85
+ .map(({ section }) => section.id)
86
+ : getAsArray(company, 'websiteSchedules')
87
+ .filter(({ start, end }) => start < now && (!end || end > now))
88
+ .map(({ section }) => section.id);
89
+
90
+ const magazineOk = !magazineSchedule || getAsArray(company, 'magazineSchedules')
91
+ .some(({ section, issue }) => section.id === magazineSchedule.sectionId
92
+ && issue.id === magazineSchedule.issueId);
93
+
94
+ const sectionOk = sectionIds.length
95
+ || (siteId && get(company, 'primarySite.id') === siteId)
96
+ || descendantSectionIds.includes(get(company, 'primarySection.id'));
97
+
98
+ if (magazineOk && sectionOk) {
99
+ const next = { ...company, sectionIds };
100
+ if (attachTaxonomyIds) {
101
+ next.taxonomyIds = getAsArray(company, 'taxonomy.edges').map(({ node }) => node.id);
102
+ }
103
+ arr.push(next);
104
+ }
105
+ return arr;
106
+ }, []);
107
+ };
108
+
109
+ module.exports = { retrieveCompanies };
@@ -0,0 +1,8 @@
1
+ const retrieveSections = async (client, query, alias, siteId) => {
2
+ const { data: { websiteSectionAlias } } = await client.query({
3
+ query,
4
+ variables: { input: { alias, siteId } },
5
+ });
6
+ return websiteSectionAlias;
7
+ };
8
+ module.exports = { retrieveSections };
@@ -0,0 +1,258 @@
1
+ module.exports = [
2
+ {
3
+ key: 'AL',
4
+ name: 'Alabama',
5
+ },
6
+ {
7
+ key: 'AK',
8
+ name: 'Alaska',
9
+ },
10
+ {
11
+ key: 'AB',
12
+ name: 'Alberta',
13
+ },
14
+ {
15
+ key: 'AZ',
16
+ name: 'Arizona',
17
+ },
18
+ {
19
+ key: 'AR',
20
+ name: 'Arkansas',
21
+ },
22
+ {
23
+ key: 'BC',
24
+ name: 'British Columbia',
25
+ },
26
+ {
27
+ key: 'CA',
28
+ name: 'California',
29
+ },
30
+ {
31
+ key: 'CO',
32
+ name: 'Colorado',
33
+ },
34
+ {
35
+ key: 'CT',
36
+ name: 'Connecticut',
37
+ },
38
+ {
39
+ key: 'DE',
40
+ name: 'Delaware',
41
+ },
42
+ {
43
+ key: 'DC',
44
+ name: 'District of Columbia',
45
+ },
46
+ {
47
+ key: 'FL',
48
+ name: 'Florida',
49
+ },
50
+ {
51
+ key: 'GA',
52
+ name: 'Georgia',
53
+ },
54
+ {
55
+ key: 'HI',
56
+ name: 'Hawaii',
57
+ },
58
+ {
59
+ key: 'ID',
60
+ name: 'Idaho',
61
+ },
62
+ {
63
+ key: 'IL',
64
+ name: 'Illinois',
65
+ },
66
+ {
67
+ key: 'IN',
68
+ name: 'Indiana',
69
+ },
70
+ {
71
+ key: 'IA',
72
+ name: 'Iowa',
73
+ },
74
+ {
75
+ key: 'KS',
76
+ name: 'Kansas',
77
+ },
78
+ {
79
+ key: 'KY',
80
+ name: 'Kentucky',
81
+ },
82
+ {
83
+ key: 'LA',
84
+ name: 'Louisiana',
85
+ },
86
+ {
87
+ key: 'ME',
88
+ name: 'Maine',
89
+ },
90
+ {
91
+ key: 'MB',
92
+ name: 'Manitoba',
93
+ },
94
+ {
95
+ key: 'MD',
96
+ name: 'Maryland',
97
+ },
98
+ {
99
+ key: 'MA',
100
+ name: 'Massachusetts',
101
+ },
102
+ {
103
+ key: 'MI',
104
+ name: 'Michigan',
105
+ },
106
+ {
107
+ key: 'MN',
108
+ name: 'Minnesota',
109
+ },
110
+ {
111
+ key: 'MS',
112
+ name: 'Mississippi',
113
+ },
114
+ {
115
+ key: 'MO',
116
+ name: 'Missouri',
117
+ },
118
+ {
119
+ key: 'MT',
120
+ name: 'Montana',
121
+ },
122
+ {
123
+ key: 'NE',
124
+ name: 'Nebraska',
125
+ },
126
+ {
127
+ key: 'NV',
128
+ name: 'Nevada',
129
+ },
130
+ {
131
+ key: 'NB',
132
+ name: 'New Brunswick',
133
+ },
134
+ {
135
+ key: 'NH',
136
+ name: 'New Hampshire',
137
+ },
138
+ {
139
+ key: 'NJ',
140
+ name: 'New Jersey',
141
+ },
142
+ {
143
+ key: 'NM',
144
+ name: 'New Mexico',
145
+ },
146
+ {
147
+ key: 'NY',
148
+ name: 'New York',
149
+ },
150
+ {
151
+ key: 'NF',
152
+ name: 'Newfoundland & Labrador',
153
+ },
154
+ {
155
+ key: 'NC',
156
+ name: 'North Carolina',
157
+ },
158
+ {
159
+ key: 'ND',
160
+ name: 'North Dakota',
161
+ },
162
+ {
163
+ key: 'NT',
164
+ name: 'Northwest Territories',
165
+ },
166
+ {
167
+ key: 'NS',
168
+ name: 'Nova Scotia',
169
+ },
170
+ {
171
+ key: 'NU',
172
+ name: 'Nunavut',
173
+ },
174
+ {
175
+ key: 'OH',
176
+ name: 'Ohio',
177
+ },
178
+ {
179
+ key: 'OK',
180
+ name: 'Oklahoma',
181
+ },
182
+ {
183
+ key: 'ON',
184
+ name: 'Ontario',
185
+ },
186
+ {
187
+ key: 'OR',
188
+ name: 'Oregon',
189
+ },
190
+ {
191
+ key: 'PA',
192
+ name: 'Pennsylvania',
193
+ },
194
+ {
195
+ key: 'PE',
196
+ name: 'Prince Edward Island',
197
+ },
198
+ {
199
+ key: 'QC',
200
+ name: 'Quebec',
201
+ },
202
+ {
203
+ key: 'RI',
204
+ name: 'Rhode Island',
205
+ },
206
+ {
207
+ key: 'SK',
208
+ name: 'Saskatchewan',
209
+ },
210
+ {
211
+ key: 'SC',
212
+ name: 'South Carolina',
213
+ },
214
+ {
215
+ key: 'SD',
216
+ name: 'South Dakota',
217
+ },
218
+ {
219
+ key: 'TN',
220
+ name: 'Tennessee',
221
+ },
222
+ {
223
+ key: 'TX',
224
+ name: 'Texas',
225
+ },
226
+ {
227
+ key: 'UT',
228
+ name: 'Utah',
229
+ },
230
+ {
231
+ key: 'VT',
232
+ name: 'Vermont',
233
+ },
234
+ {
235
+ key: 'VA',
236
+ name: 'Virginia',
237
+ },
238
+ {
239
+ key: 'WA',
240
+ name: 'Washington',
241
+ },
242
+ {
243
+ key: 'WV',
244
+ name: 'West Virginia',
245
+ },
246
+ {
247
+ key: 'WI',
248
+ name: 'Wisconsin',
249
+ },
250
+ {
251
+ key: 'WY',
252
+ name: 'Wyoming',
253
+ },
254
+ {
255
+ key: 'YT',
256
+ name: 'Yukon',
257
+ },
258
+ ];
@@ -0,0 +1,70 @@
1
+ module.exports = {
2
+ alabama: 'AL',
3
+ alaska: 'AK',
4
+ arizona: 'AZ',
5
+ arkansas: 'AR',
6
+ california: 'CA',
7
+ colorado: 'CO',
8
+ connecticut: 'CT',
9
+ delaware: 'DE',
10
+ 'district of columbia': 'DC',
11
+ florida: 'FL',
12
+ georgia: 'GA',
13
+ hawaii: 'HI',
14
+ idaho: 'ID',
15
+ illinois: 'IL',
16
+ indiana: 'IN',
17
+ iowa: 'IA',
18
+ kansas: 'KS',
19
+ kentucky: 'KY',
20
+ louisiana: 'LA',
21
+ maine: 'ME',
22
+ maryland: 'MD',
23
+ massachusetts: 'MA',
24
+ michigan: 'MI',
25
+ minnesota: 'MN',
26
+ mississippi: 'MS',
27
+ missouri: 'MO',
28
+ montana: 'MT',
29
+ nebraska: 'NE',
30
+ nevada: 'NV',
31
+ 'new hampshire': 'NH',
32
+ 'new jersey': 'NJ',
33
+ 'new mexico': 'NM',
34
+ 'new york': 'NY',
35
+ 'north carolina': 'NC',
36
+ 'north dakota': 'ND',
37
+ ohio: 'OH',
38
+ oklahoma: 'OK',
39
+ oregon: 'OR',
40
+ pennsylvania: 'PA',
41
+ 'rhode island': 'RI',
42
+ 'south carolina': 'SC',
43
+ 'south dakota': 'SD',
44
+ tennessee: 'TN',
45
+ texas: 'TX',
46
+ utah: 'UT',
47
+ vermont: 'VT',
48
+ virginia: 'VA',
49
+ washington: 'WA',
50
+ 'west virginia': 'WV',
51
+ wisconsin: 'WI',
52
+ wyoming: 'WY',
53
+ // Canadian
54
+ alberta: 'AB',
55
+ 'british columbia': 'BC',
56
+ manitoba: 'MB',
57
+ 'new brunswick': 'NB',
58
+ newfoundland: 'NL',
59
+ 'newfoundland & labrador': 'NL',
60
+ labrador: 'NL',
61
+ 'northwest territories': 'NT',
62
+ 'nova scotia': 'NS',
63
+ nunavut: 'NU',
64
+ ontario: 'ON',
65
+ 'prince edward island': 'PE',
66
+ quebec: 'QC',
67
+ saskatchewan: 'SK',
68
+ yukon: 'YT',
69
+ 'yukon territory': 'YT',
70
+ };