Skip to content

Commit 3b521a4

Browse files
authored
Merge pull request #3506 from SeedCompany/better-handle-non-pnp-uploads
2 parents 2824e51 + e1419e0 commit 3b521a4

File tree

6 files changed

+42
-20
lines changed

6 files changed

+42
-20
lines changed

src/components/pnp/pnp.ts

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,54 @@
1-
import { WorkBook } from '~/common/xlsx.util';
2-
import { type Downloadable } from '../file/dto';
1+
import { InputException, NotFoundException } from '~/common';
2+
import { type Sheet, WorkBook } from '~/common/xlsx.util';
3+
import { type Downloadable, type FileVersion } from '../file/dto';
34
import { PlanningSheet } from './planning-sheet';
45
import { ProgressSheet } from './progress-sheet';
56

67
const ParsedPnp = Symbol('Parsed PnP');
78

89
export class Pnp {
9-
constructor(protected workbook: WorkBook) {}
10+
constructor(protected workbook: WorkBook, protected fileName?: string) {}
1011

1112
/**
1213
* Create PnP from Downloadable.
1314
* Will reuse an existing instance from a previous call.
1415
*/
15-
static async fromDownloadable(obj: Downloadable<unknown>) {
16+
static async fromDownloadable(obj: Downloadable<FileVersion>) {
1617
const promise = obj.download() as Promise<Buffer> & { [ParsedPnp]?: Pnp };
1718
if (!promise[ParsedPnp]) {
18-
promise[ParsedPnp] = Pnp.fromBuffer(await promise);
19+
promise[ParsedPnp] = Pnp.fromBuffer(await promise, obj.name);
1920
}
2021
return promise[ParsedPnp]!;
2122
}
2223

23-
static fromBuffer(buffer: Buffer) {
24+
static fromBuffer(buffer: Buffer, name?: string) {
2425
const book = WorkBook.fromBuffer(buffer);
2526
PlanningSheet.register(book);
2627
ProgressSheet.register(book);
27-
return new Pnp(book);
28+
return new Pnp(book, name);
2829
}
2930

3031
get planning() {
31-
return this.workbook.sheet<PlanningSheet>('Planning');
32+
return this.sheet<PlanningSheet>('Planning');
3233
}
3334

3435
get progress() {
35-
return this.workbook.sheet<ProgressSheet>('Progress');
36+
return this.sheet<ProgressSheet>('Progress');
37+
}
38+
39+
protected sheet<TSheet extends Sheet>(name: string): TSheet {
40+
try {
41+
return this.workbook.sheet(name);
42+
} catch (e) {
43+
if (e instanceof NotFoundException && this.fileName?.match(/\bUBT\b/)) {
44+
throw new NotPnPFile(
45+
`It appears you are uploading a _budget_ excel file, not a _PnP_ file.`,
46+
e,
47+
);
48+
}
49+
throw e;
50+
}
3651
}
3752
}
53+
54+
export class NotPnPFile extends InputException {}

src/components/product-progress/step-progress-extractor.service.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { entries } from '@seedcompany/common';
33
import { assert } from 'ts-essentials';
44
import type { MergeExclusive } from 'type-fest';
55
import type { Cell, Column, Row } from '~/common/xlsx.util';
6-
import type { Downloadable } from '../file/dto';
6+
import type { Downloadable, FileVersion } from '../file/dto';
77
import {
88
extractScripture,
99
findStepColumns,
@@ -45,7 +45,7 @@ type ExtractedRow = MergeExclusive<
4545
@Injectable()
4646
export class StepProgressExtractor {
4747
async extract(
48-
file: Downloadable<unknown>,
48+
file: Downloadable<FileVersion>,
4949
result: PnpProgressExtractionResult,
5050
) {
5151
const pnp = await Pnp.fromDownloadable(file);

src/components/product/pnp-product-sync.service.ts

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { DateTime } from 'luxon';
77
import { DateInterval, type ID } from '~/common';
88
import { ILogger, Logger, ResourceLoader } from '~/core';
99
import { type Downloadable, type FileVersion } from '../file/dto';
10+
import { NotPnPFile } from '../pnp';
1011
import {
1112
type PnpExtractionResult,
1213
PnpProblemType,
@@ -67,10 +68,12 @@ export class PnpProductSyncService {
6768
result,
6869
);
6970
} catch (e) {
70-
this.logger.error(e.message, {
71-
id: pnp.id,
72-
exception: e,
73-
});
71+
if (!(e instanceof NotPnPFile)) {
72+
this.logger.error(e.message, {
73+
id: pnp.id,
74+
exception: e,
75+
});
76+
}
7477
return [];
7578
}
7679
if (productRows.length === 0) {

src/components/product/product.extractor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { assert } from 'ts-essentials';
55
import { type MergeExclusive } from 'type-fest';
66
import { type CalendarDate, type DateInterval } from '~/common';
77
import { type Cell, type Column, type Row } from '~/common/xlsx.util';
8-
import { type Downloadable } from '../file/dto';
8+
import { type Downloadable, type FileVersion } from '../file/dto';
99
import {
1010
extractScripture,
1111
findStepColumns,
@@ -31,7 +31,7 @@ import { type ProductStep, type ProductStep as Step } from './dto';
3131
@Injectable()
3232
export class ProductExtractor {
3333
async extract(
34-
file: Downloadable<unknown>,
34+
file: Downloadable<FileVersion>,
3535
engagementRange: DateInterval | null,
3636
availableSteps: readonly ProductStep[],
3737
result: PnpPlanningExtractionResult,

src/components/progress-summary/progress-summary.extractor.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
fiscalYear,
99
} from '~/common';
1010
import { type Column, type Row } from '~/common/xlsx.util';
11-
import { type Downloadable } from '../file/dto';
11+
import { type Downloadable, type FileVersion } from '../file/dto';
1212
import { Pnp, type ProgressSheet } from '../pnp';
1313
import {
1414
PnpProblemType,
@@ -19,7 +19,7 @@ import { type ProgressSummary as Progress } from './dto';
1919
@Injectable()
2020
export class ProgressSummaryExtractor {
2121
async extract(
22-
file: Downloadable<unknown>,
22+
file: Downloadable<FileVersion>,
2323
date: CalendarDate,
2424
result: PnpProgressExtractionResult,
2525
) {

src/repl.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as fs from 'fs/promises';
66
// eslint-disable-next-line no-restricted-imports
77
import * as lodash from 'lodash';
88
import { DateTime, Duration, Interval } from 'luxon';
9+
import { basename } from 'node:path';
910
import { CalendarDate, DateInterval } from '~/common';
1011
import * as common from '~/common';
1112
import './polyfills';
@@ -46,7 +47,8 @@ runRepl({
4647
session,
4748
sessionFor: session.withRoles,
4849
Resources,
49-
loadPnp: (filepath: string) => Pnp.fromBuffer(readFileSync(filepath)),
50+
loadPnp: (filepath: string) =>
51+
Pnp.fromBuffer(readFileSync(filepath), basename(filepath)),
5052
};
5153
},
5254
});

0 commit comments

Comments
 (0)