Skip to content

Commit

Permalink
feat(vdoc): vdoc transformer, to set LF fields from vdoc metadata
Browse files Browse the repository at this point in the history
Many lint, typescript, and other style fixes

Signed-off-by: Andrew Balmos <[email protected]>
  • Loading branch information
abalmos committed Oct 17, 2024
1 parent 0362998 commit c063ca2
Show file tree
Hide file tree
Showing 14 changed files with 515 additions and 314 deletions.
3 changes: 2 additions & 1 deletion src/cws/entries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ export interface FolderEntry extends BaseEntry {
export type Entry = FolderEntry | DocumentEntry;
export type EntryIdLike<T extends BaseEntry = BaseEntry> =
| Pick<Partial<T>, 'LaserficheEntryID' | 'EntryId'>
| EntryId<T>;
| EntryId<T>
| number;

export function getEntryId<T extends BaseEntry>(entry: EntryIdLike<T>) {
return typeof entry === 'number'
Expand Down
92 changes: 44 additions & 48 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,56 +17,33 @@

import { config } from './config.js';

import '@oada/pino-debug';
import { type Logger, pino } from '@oada/pino-debug';

import { join } from 'node:path';

import { CronJob } from 'cron';
import { JsonPointer } from 'json-ptr';
import { backOff } from 'exponential-backoff';
import esMain from 'es-main';
import ksuid from 'ksuid';
import makeDebug from 'debug';
import pTimeout from 'p-timeout';
import { type Logger, pino } from '@oada/pino-debug'

import {
AssumeState,
type Change,
ChangeType,
ListWatch,
} from '@oada/list-lib';
import { type Job, type Json, Service, type WorkerFunction } from '@oada/jobs';
import { type JsonObject, type OADAClient, connect } from '@oada/client';
import {
type default as Resource,
assert as assertResource,
} from '@oada/types/oada/resource.js';

import {
DOCS_LIST,
LF_AUTOMATION_FOLDER,
TRADING_PARTNER_LIST,
selfDocsTree,
tpDocTypesTree,
tpDocsTree,
tpTree,
tree,
} from './tree.js';

import { type Job, type Json, Service, type WorkerContext } from '@oada/jobs';
import { type OADAClient, connect } from '@oada/client';

import type { DocumentEntry, EntryId, EntryIdLike } from './cws/index.js';
import { browse, getEntryId, moveEntry, retrieveEntry } from './cws/index.js';
import { LF_AUTOMATION_FOLDER } from './tree.js';
import { sync } from './sync.js';

const selfChange = new JsonPointer('/body/_meta/services/lf-sync');
const log = pino({base: {service: 'lf-sync'}});

// Stuff from config
const { token, domain } = config.get('oada');
const CONCURRENCY = config.get('concurrency');
const LF_POLL_RATE = config.get('laserfiche.pollRate');
const SYNC_JOB_TIMEOUT = config.get('timeouts.sync');
const ENTRY_JOB_TIMEOUT = config.get('timeouts.getEntry');
const REPORT_PATH = '/bookmarks/services/lf-sync/jobs/reports/docs-synced';
// Const REPORT_PATH = '/bookmarks/services/lf-sync/jobs/reports/docs-synced';

// OADA is rate limited by @oada/client
// LF is *NOT* rate limited, but only has sparse calls per *pending document* at this time
Expand All @@ -77,6 +54,8 @@ const REPORT_PATH = '/bookmarks/services/lf-sync/jobs/reports/docs-synced';
let oada: OADAClient;

async function startService() {
const log = pino({ base: { service: 'lf-sync' } });

log.info('Service: lf-sync');
log.info(`Version: ${process.env.npm_package_version}`);

Expand All @@ -89,6 +68,7 @@ async function startService() {
name: 'lf-sync',
oada: conn,
concurrency: CONCURRENCY,
log,
});

// Poll LF for customer docs that SF drops into the _TrellisAutomation folder
Expand All @@ -106,16 +86,17 @@ async function startService() {

const serv = svc.start();

//const sjc = startSyncJobCreator(conn);
// Const sjc = startSyncJobCreator(conn);

//await Promise.all([serv, sjc]);
// await Promise.all([serv, sjc]);
await serv;
}

/**
*
*/
export function watchLaserfiche(
log: Logger,
task: (file: DocumentEntry) => void,
): (id: EntryIdLike) => void {
const workQueue = new Map<number, number>();
Expand Down Expand Up @@ -180,18 +161,17 @@ interface MetaEntry {
};
}

export interface GetLfEntryConfig {
doc: string;
}
/**
* Retrieve the LF Entry ID for a given trellis document or wait for it to be created
*/
const getLfEntry: WorkerFunction = async function (
async function getLfEntry(
job: Job,
{
oada: conn,
}: {
oada: OADAClient;
},
{ oada: conn, log }: WorkerContext,
): Promise<Json> {
const { doc } = job.config as unknown as any;
const { doc } = job.config as unknown as GetLfEntryConfig;
let data: Record<string, LfMetaEntry> = {};
const { data: meta } = (await conn.get({
path: join('/', doc, '/_meta'),
Expand All @@ -203,10 +183,11 @@ const getLfEntry: WorkerFunction = async function (
}

log.info('Missing LF Entries for vdocs, waiting for remainder');
return waitForLfEntries(conn, doc, meta);
};
return waitForLfEntries(log, conn, doc, meta);
}

async function waitForLfEntries(
log: Logger,
conn: OADAClient,
path: string,
meta: MetaEntry,
Expand All @@ -222,7 +203,7 @@ async function waitForLfEntries(
await changes.return?.();
};

async function watchChanges() {
async function watchChanges(): Promise<Json> {
for await (const change of changes) {
if (selfChange.has(change)) {
log.info(
Expand All @@ -233,6 +214,8 @@ async function waitForLfEntries(
...data,
...(selfChange.get(change) as Record<string, LfMetaEntry>),
};

// eslint-disable-next-line @typescript-eslint/no-loop-func
if (Object.keys(meta.vdoc.pdf).every((key) => data[key])) {
log.info(
`Got a meta entries for every vdoc of ${path}. Fetching entries`,
Expand All @@ -242,6 +225,7 @@ async function waitForLfEntries(
}
}
}
return {};
}

return pTimeout(watchChanges(), { milliseconds: ENTRY_JOB_TIMEOUT });
Expand All @@ -253,11 +237,13 @@ async function waitForLfEntries(
* @returns
*/
// TODO: If the Entry doesn't contain a Path, wait for for a bit
async function entriesFromMeta(metadoc: Record<string, LfMetaEntry>) {
async function entriesFromMeta(
metadoc: Record<string, LfMetaEntry>,
): Promise<Json> {
const entries = [];
for await (const [key, value] of Object.entries(metadoc)) {
const result = await backOff(async () => {
const entry = await retrieveEntry(value.LaserficheEntryID as any);
const entry = await retrieveEntry(value.LaserficheEntryID);
if (entry.Path.startsWith(String.raw`\FSQA\_Incoming`)) {
throw new Error('Entry is still in _Incoming');
} else {
Expand All @@ -273,12 +259,18 @@ async function entriesFromMeta(metadoc: Record<string, LfMetaEntry>) {
]);
}

// eslint-disable-next-line @typescript-eslint/no-unsafe-return
return Object.fromEntries(entries);
}

if (esMain(import.meta)) {
await startService();
}

/**
* Start-up for a given user (token)
*/
/*
async function startSyncJobCreator(conn: OADAClient) {
// Watch for new trading partner documents to process
if (config.get('watch.partners')) {
Expand All @@ -304,6 +296,7 @@ interface SyncJobConfig {
* @param conn oada client connection
* @param doc the
*/
/*
async function queueSyncJob(conn: OADAClient, config: SyncJobConfig) {
const result = await conn.post({
path: `/resources`,
Expand All @@ -329,7 +322,9 @@ async function queueSyncJob(conn: OADAClient, config: SyncJobConfig) {
contentType: 'application/json',
});
}
*/

/*
function watchPartnerDocs(
conn: OADAClient,
callback: (item: Resource, tpKey: string) => void | PromiseLike<void>,
Expand Down Expand Up @@ -413,7 +408,9 @@ function watchPartnerDocs(
);
process.on('beforeExit', async () => watch.stop());
}
*/

/*
function watchSelfDocs(
conn: OADAClient,
callback: (item: Resource) => Promise<void>,
Expand Down Expand Up @@ -486,10 +483,12 @@ function watchSelfDocs(
);
process.on('beforeExit', async () => docTypeWatch.stop());
}
*/

/**
* Report on each item synced
*/
/*
export async function reportItem(conn: OADAClient, item: ReportEntry) {
const key = ksuid.randomSync().string;
const date = new Date().toISOString().split('T')[0];
Expand Down Expand Up @@ -518,7 +517,4 @@ interface ReportEntry {
'Trellis Document Type': string;
'Trellis File ID': string; // The actual binary doc synced,
}

if (esMain(import.meta)) {
await startService();
}
*/
14 changes: 5 additions & 9 deletions src/lfdynamic-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ function sanitize(value: string) {
.slice(0, Math.max(0, ENTITY_NAME_LENGTH));
}

// eslint-disable-next-line sonarjs/cognitive-complexity
export async function handleEntities(
oada: OADAClient,
trellis: TrellisEntry[],
Expand All @@ -194,26 +195,21 @@ export async function handleEntities(
await sql.query/* sql */ `SELECT * FROM SFI_Entities WHERE ("Entity Name")=(${sanitize(tp.name)})`;
let record =
res?.recordset.length > 1
? await removeDupeEntities(Array.from(res.recordset))
: res?.recordset?.[0];
? await removeDupeEntities(Array.from(res.recordset as SqlEntry[]))
: (res?.recordset?.[0] as SqlEntry);
if (!record) {
error('No result for TP', tp.name);
// Does not exist. Create it
try {
await sql.query/* sql */ `INSERT INTO SFI_Entities ("Entity Name") VALUES (${tp.name})`;
res =
await sql.query/* sql */ `SELECT * FROM SFI_Entities WHERE ("Entity Name")=(${tp.name})`;
record = res?.recordset?.[0];
record = res?.recordset?.[0] as SqlEntry;
} catch (error_: unknown) {
error(
error_,
`Was an error updating a LFDynamic entity to match trading partner ${tp.name} [${tp.masterid}]`,
);
if (
// @ts-expect-error error nonsense
error_.message.includes('String or binary data would be truncated')
) {
}

continue;
}
Expand Down Expand Up @@ -313,4 +309,4 @@ export interface SAPVendor {

await main();
// Const rows = grabVendors();
// console.log(rows);
// console.log(rows);
2 changes: 1 addition & 1 deletion src/scripts/lf/clean-dups.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ async function trashDuplicates(root: FolderEntry) {
// This is the same file as another file in the same folder, but with a different intended name. Keep.
if (cleanNameMatch.length === 1) {
console.log(
`[DIFFERENT_NAME] (${newestDoc.EntryId}) ${cleanName} is the same as nother file, but with a different name. Keeping.`,
`[DIFFERENT_NAME] (${newestDoc.EntryId}) ${cleanName} is the same as another file, but with a different name. Keeping.`,
);
} else {
console.log(
Expand Down
1 change: 0 additions & 1 deletion src/scripts/lf/delete-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ if (argv.length !== 3) {

const entryId = Number(argv[2]); // As unknown as EntryId;

// @ts-expect-error Wrong types
const entry = await retrieveEntry(entryId);

// @awlayton: your auto format rules makes this __really__ ugly
Expand Down
5 changes: 1 addition & 4 deletions src/scripts/lf/move-entry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
*/

/* eslint-disable no-console, no-process-exit, unicorn/no-process-exit */
import { type EntryId, moveEntry } from '../../cws/entries.js';
import { argv } from 'node:process';
import { moveEntry } from '../../cws/entries.js';

/* A quick script to move an EntryId to a new location */

Expand All @@ -26,10 +26,7 @@ if (argv.length !== 4) {
process.exit(1);
}

console.log(argv);

const entryId = Number(argv[2]); // As unknown as EntryId;
const path = argv[3] as unknown as `/${string}`;

// @ts-expect-error Wrong types
await moveEntry(entryId, path);
Loading

0 comments on commit c063ca2

Please sign in to comment.