development
- combine functions.database and database.helpers - monitor image folders for changes - warning message for config table update - properly track replacement workers - show cemetery maps on burial sites - show parent cemetery maps on child cemetery sites - linting and polishpull/11/head
parent
190d17cabd
commit
d41117a44a
17
bin/www.js
17
bin/www.js
|
|
@ -23,6 +23,7 @@ const clusterSettings = {
|
|||
exec: `${directoryName}/wwwProcess.js`
|
||||
};
|
||||
cluster.setupPrimary(clusterSettings);
|
||||
let doShutdown = false;
|
||||
const activeWorkers = new Map();
|
||||
for (let index = 0; index < processCount; index += 1) {
|
||||
const worker = cluster.fork();
|
||||
|
|
@ -41,8 +42,11 @@ cluster.on('message', (worker, message) => {
|
|||
cluster.on('exit', (worker) => {
|
||||
debug(`Worker ${(worker.process.pid ?? 0).toString()} has been killed`);
|
||||
activeWorkers.delete(worker.process.pid ?? 0);
|
||||
debug('Starting another worker');
|
||||
cluster.fork();
|
||||
if (!doShutdown) {
|
||||
debug('Starting another worker');
|
||||
const newWorker = cluster.fork();
|
||||
activeWorkers.set(newWorker.process.pid ?? 0, newWorker);
|
||||
}
|
||||
});
|
||||
const ntfyStartupConfig = getConfigProperty('application.ntfyStartup');
|
||||
if (ntfyStartupConfig !== undefined) {
|
||||
|
|
@ -75,7 +79,16 @@ if (process.env.STARTUP_TEST === 'true') {
|
|||
debug(`Killing processes in ${killSeconds} seconds...`);
|
||||
setTimeout(() => {
|
||||
debug('Killing processes');
|
||||
doShutdown = true;
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(0);
|
||||
}, secondsToMillis(killSeconds));
|
||||
}
|
||||
exitHook(() => {
|
||||
doShutdown = true;
|
||||
debug('Shutting down...');
|
||||
for (const worker of activeWorkers.values()) {
|
||||
debug(`Killing worker ${worker.process.pid}`);
|
||||
worker.kill();
|
||||
}
|
||||
});
|
||||
|
|
|
|||
21
bin/www.ts
21
bin/www.ts
|
|
@ -39,6 +39,7 @@ const clusterSettings = {
|
|||
|
||||
cluster.setupPrimary(clusterSettings)
|
||||
|
||||
let doShutdown = false
|
||||
const activeWorkers = new Map<number, Worker>()
|
||||
|
||||
for (let index = 0; index < processCount; index += 1) {
|
||||
|
|
@ -62,8 +63,12 @@ cluster.on('exit', (worker) => {
|
|||
debug(`Worker ${(worker.process.pid ?? 0).toString()} has been killed`)
|
||||
activeWorkers.delete(worker.process.pid ?? 0)
|
||||
|
||||
debug('Starting another worker')
|
||||
cluster.fork()
|
||||
if (!doShutdown) {
|
||||
debug('Starting another worker')
|
||||
const newWorker = cluster.fork()
|
||||
|
||||
activeWorkers.set(newWorker.process.pid ?? 0, newWorker)
|
||||
}
|
||||
})
|
||||
|
||||
const ntfyStartupConfig = getConfigProperty('application.ntfyStartup')
|
||||
|
|
@ -107,7 +112,19 @@ if (process.env.STARTUP_TEST === 'true') {
|
|||
setTimeout(() => {
|
||||
debug('Killing processes')
|
||||
|
||||
doShutdown = true
|
||||
|
||||
// eslint-disable-next-line unicorn/no-process-exit
|
||||
process.exit(0)
|
||||
}, secondsToMillis(killSeconds))
|
||||
}
|
||||
|
||||
exitHook(() => {
|
||||
doShutdown = true
|
||||
debug('Shutting down...')
|
||||
|
||||
for (const worker of activeWorkers.values()) {
|
||||
debug(`Killing worker ${worker.process.pid}`)
|
||||
worker.kill()
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ export const config = {
|
|||
settings: {
|
||||
adminCleanup: {},
|
||||
burialSites: {},
|
||||
cemeteries: {},
|
||||
contracts: {},
|
||||
dynamicsGP: {
|
||||
integrationIsEnabled: false
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ export const config: Config = {
|
|||
settings: {
|
||||
adminCleanup: {},
|
||||
burialSites: {},
|
||||
cemeteries: {},
|
||||
contracts: {},
|
||||
dynamicsGP: {
|
||||
integrationIsEnabled: false
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ export declare const configDefaultValues: {
|
|||
'settings.latitudeMin': number;
|
||||
'settings.longitudeMax': number;
|
||||
'settings.longitudeMin': number;
|
||||
'settings.cemeteries.refreshImageChanges': boolean;
|
||||
'settings.burialSites.burialSiteNameSegments': ConfigBurialSiteNameSegments;
|
||||
'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': boolean;
|
||||
'settings.burialSites.refreshImageChanges': boolean;
|
||||
'settings.contracts.burialSiteIdIsRequired': boolean;
|
||||
'settings.contracts.contractEndDateIsRequired': boolean;
|
||||
'settings.contracts.deathAgePeriods': string[];
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ export const configDefaultValues = {
|
|||
'settings.latitudeMin': -90,
|
||||
'settings.longitudeMax': 180,
|
||||
'settings.longitudeMin': -180,
|
||||
'settings.cemeteries.refreshImageChanges': false,
|
||||
'settings.burialSites.burialSiteNameSegments': {
|
||||
includeCemeteryKey: false,
|
||||
separator: '-',
|
||||
|
|
@ -44,6 +45,7 @@ export const configDefaultValues = {
|
|||
}
|
||||
},
|
||||
'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': false,
|
||||
'settings.burialSites.refreshImageChanges': false,
|
||||
'settings.contracts.burialSiteIdIsRequired': true,
|
||||
'settings.contracts.contractEndDateIsRequired': false,
|
||||
'settings.contracts.deathAgePeriods': [
|
||||
|
|
|
|||
|
|
@ -49,6 +49,8 @@ export const configDefaultValues = {
|
|||
'settings.longitudeMax': 180,
|
||||
'settings.longitudeMin': -180,
|
||||
|
||||
'settings.cemeteries.refreshImageChanges': false,
|
||||
|
||||
'settings.burialSites.burialSiteNameSegments': {
|
||||
includeCemeteryKey: false,
|
||||
separator: '-',
|
||||
|
|
@ -66,6 +68,8 @@ export const configDefaultValues = {
|
|||
|
||||
'settings.burialSites.burialSiteNameSegments.includeCemeteryKey': false,
|
||||
|
||||
'settings.burialSites.refreshImageChanges': false,
|
||||
|
||||
'settings.contracts.burialSiteIdIsRequired': true,
|
||||
'settings.contracts.contractEndDateIsRequired': false,
|
||||
'settings.contracts.deathAgePeriods': [
|
||||
|
|
|
|||
|
|
@ -11,7 +11,9 @@ const baseSQL = `select l.burialSiteId,
|
|||
l.burialSiteNameSegment5,
|
||||
l.burialSiteName,
|
||||
l.burialSiteStatusId, s.burialSiteStatus,
|
||||
|
||||
l.cemeteryId, m.cemeteryName,
|
||||
m.cemeteryLatitude, m.cemeteryLongitude,
|
||||
m.cemeterySvg, l.cemeterySvgId, l.burialSiteImage,
|
||||
l.burialSiteLatitude, l.burialSiteLongitude
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,9 @@ const baseSQL = `select l.burialSiteId,
|
|||
l.burialSiteNameSegment5,
|
||||
l.burialSiteName,
|
||||
l.burialSiteStatusId, s.burialSiteStatus,
|
||||
|
||||
l.cemeteryId, m.cemeteryName,
|
||||
m.cemeteryLatitude, m.cemeteryLongitude,
|
||||
m.cemeterySvg, l.cemeterySvgId, l.burialSiteImage,
|
||||
l.burialSiteLatitude, l.burialSiteLongitude
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,10 @@
|
|||
import { acquireConnection } from './pool.js';
|
||||
export default async function getCemetery(cemeteryId, connectedDatabase) {
|
||||
return await _getCemetery('cemeteryId', cemeteryId, connectedDatabase);
|
||||
}
|
||||
export async function getCemeteryByKey(cemeteryKey, connectedDatabase) {
|
||||
return await _getCemetery('cemeteryKey', cemeteryKey, connectedDatabase);
|
||||
}
|
||||
async function _getCemetery(keyColumn, cemeteryIdOrKey, connectedDatabase) {
|
||||
const database = connectedDatabase ?? (await acquireConnection());
|
||||
const cemetery = database
|
||||
|
|
@ -6,7 +12,11 @@ async function _getCemetery(keyColumn, cemeteryIdOrKey, connectedDatabase) {
|
|||
m.cemeteryLatitude, m.cemeteryLongitude, m.cemeterySvg,
|
||||
m.cemeteryAddress1, m.cemeteryAddress2, m.cemeteryCity, m.cemeteryProvince, m.cemeteryPostalCode,
|
||||
m.cemeteryPhoneNumber,
|
||||
|
||||
p.cemeteryId as parentCemeteryId, p.cemeteryName as parentCemeteryName,
|
||||
p.cemeteryLatitude as parentCemeteryLatitude, p.cemeteryLongitude as parentCemeteryLongitude,
|
||||
p.cemeterySvg as parentCemeterySvg,
|
||||
|
||||
m.recordCreate_userName, m.recordCreate_timeMillis,
|
||||
m.recordUpdate_userName, m.recordUpdate_timeMillis,
|
||||
m.recordDelete_userName, m.recordDelete_timeMillis,
|
||||
|
|
@ -30,9 +40,3 @@ async function _getCemetery(keyColumn, cemeteryIdOrKey, connectedDatabase) {
|
|||
}
|
||||
return cemetery;
|
||||
}
|
||||
export default async function getCemetery(cemeteryId, connectedDatabase) {
|
||||
return await _getCemetery('cemeteryId', cemeteryId, connectedDatabase);
|
||||
}
|
||||
export async function getCemeteryByKey(cemeteryKey, connectedDatabase) {
|
||||
return await _getCemetery('cemeteryKey', cemeteryKey, connectedDatabase);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,20 @@ import type { Cemetery } from '../types/recordTypes.js'
|
|||
|
||||
import { acquireConnection } from './pool.js'
|
||||
|
||||
export default async function getCemetery(
|
||||
cemeteryId: number | string,
|
||||
connectedDatabase?: PoolConnection
|
||||
): Promise<Cemetery | undefined> {
|
||||
return await _getCemetery('cemeteryId', cemeteryId, connectedDatabase)
|
||||
}
|
||||
|
||||
export async function getCemeteryByKey(
|
||||
cemeteryKey: string,
|
||||
connectedDatabase?: PoolConnection
|
||||
): Promise<Cemetery | undefined> {
|
||||
return await _getCemetery('cemeteryKey', cemeteryKey, connectedDatabase)
|
||||
}
|
||||
|
||||
async function _getCemetery(
|
||||
keyColumn: 'cemeteryId' | 'cemeteryKey',
|
||||
cemeteryIdOrKey: number | string,
|
||||
|
|
@ -17,7 +31,11 @@ async function _getCemetery(
|
|||
m.cemeteryLatitude, m.cemeteryLongitude, m.cemeterySvg,
|
||||
m.cemeteryAddress1, m.cemeteryAddress2, m.cemeteryCity, m.cemeteryProvince, m.cemeteryPostalCode,
|
||||
m.cemeteryPhoneNumber,
|
||||
|
||||
p.cemeteryId as parentCemeteryId, p.cemeteryName as parentCemeteryName,
|
||||
p.cemeteryLatitude as parentCemeteryLatitude, p.cemeteryLongitude as parentCemeteryLongitude,
|
||||
p.cemeterySvg as parentCemeterySvg,
|
||||
|
||||
m.recordCreate_userName, m.recordCreate_timeMillis,
|
||||
m.recordUpdate_userName, m.recordUpdate_timeMillis,
|
||||
m.recordDelete_userName, m.recordDelete_timeMillis,
|
||||
|
|
@ -44,17 +62,3 @@ async function _getCemetery(
|
|||
|
||||
return cemetery
|
||||
}
|
||||
|
||||
export default async function getCemetery(
|
||||
cemeteryId: number | string,
|
||||
connectedDatabase?: PoolConnection
|
||||
): Promise<Cemetery | undefined> {
|
||||
return await _getCemetery('cemeteryId', cemeteryId, connectedDatabase)
|
||||
}
|
||||
|
||||
export async function getCemeteryByKey(
|
||||
cemeteryKey: string,
|
||||
connectedDatabase?: PoolConnection
|
||||
): Promise<Cemetery | undefined> {
|
||||
return await _getCemetery('cemeteryKey', cemeteryKey, connectedDatabase)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,14 +3,14 @@ import { type DateString } from '@cityssm/utils-datetime';
|
|||
import type { Contract } from '../types/recordTypes.js';
|
||||
export interface GetContractsFilters {
|
||||
burialSiteId?: number | string;
|
||||
contractTime?: '' | 'current' | 'future' | 'past';
|
||||
contractStartDateString?: DateString;
|
||||
contractEffectiveDateString?: string;
|
||||
contractStartDateString?: DateString;
|
||||
contractTime?: '' | 'current' | 'future' | 'past';
|
||||
deceasedName?: string;
|
||||
contractTypeId?: number | string;
|
||||
cemeteryId?: number | string;
|
||||
burialSiteName?: string;
|
||||
burialSiteNameSearchType?: '' | 'startsWith' | 'endsWith';
|
||||
burialSiteNameSearchType?: '' | 'endsWith' | 'startsWith';
|
||||
burialSiteTypeId?: number | string;
|
||||
funeralHomeId?: number | string;
|
||||
notWorkOrderId?: number | string;
|
||||
|
|
|
|||
|
|
@ -24,16 +24,16 @@ import { acquireConnection } from './pool.js'
|
|||
export interface GetContractsFilters {
|
||||
burialSiteId?: number | string
|
||||
|
||||
contractTime?: '' | 'current' | 'future' | 'past'
|
||||
contractStartDateString?: DateString
|
||||
contractEffectiveDateString?: string
|
||||
contractStartDateString?: DateString
|
||||
contractTime?: '' | 'current' | 'future' | 'past'
|
||||
|
||||
deceasedName?: string
|
||||
contractTypeId?: number | string
|
||||
cemeteryId?: number | string
|
||||
|
||||
burialSiteName?: string
|
||||
burialSiteNameSearchType?: '' | 'startsWith' | 'endsWith'
|
||||
burialSiteNameSearchType?: '' | 'endsWith' | 'startsWith'
|
||||
|
||||
burialSiteTypeId?: number | string
|
||||
funeralHomeId?: number | string
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { backupDatabase } from '../../helpers/functions.database.js';
|
||||
import { backupDatabase } from '../../helpers/database.helpers.js';
|
||||
export default async function handler(_request, response) {
|
||||
const backupDatabasePath = await backupDatabase();
|
||||
if (typeof backupDatabasePath === 'string') {
|
||||
const backupDatabasePathSplit = backupDatabasePath.split(/[/\\]/g);
|
||||
const backupDatabasePathSplit = backupDatabasePath.split(/[/\\]/);
|
||||
const fileName = backupDatabasePathSplit.at(-1);
|
||||
response.json({
|
||||
success: true,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import type { Request, Response } from 'express'
|
||||
|
||||
import { backupDatabase } from '../../helpers/functions.database.js'
|
||||
import { backupDatabase } from '../../helpers/database.helpers.js'
|
||||
|
||||
export default async function handler(
|
||||
_request: Request,
|
||||
|
|
@ -9,7 +9,7 @@ export default async function handler(
|
|||
const backupDatabasePath = await backupDatabase()
|
||||
|
||||
if (typeof backupDatabasePath === 'string') {
|
||||
const backupDatabasePathSplit = backupDatabasePath.split(/[/\\]/g)
|
||||
const backupDatabasePathSplit = backupDatabasePath.split(/[/\\]/)
|
||||
|
||||
const fileName = backupDatabasePathSplit.at(-1)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import type { Request, Response } from 'express';
|
||||
export default function handler(request: Request<unknown, unknown, {
|
||||
workOrderId: string;
|
||||
burialSiteId: string;
|
||||
workOrderId: string;
|
||||
}>, response: Response): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import addWorkOrderBurialSite from '../../database/addWorkOrderBurialSite.js';
|
|||
import getBurialSites from '../../database/getBurialSites.js';
|
||||
export default async function handler(request, response) {
|
||||
const success = await addWorkOrderBurialSite({
|
||||
workOrderId: request.body.workOrderId,
|
||||
burialSiteId: request.body.burialSiteId
|
||||
burialSiteId: request.body.burialSiteId,
|
||||
workOrderId: request.body.workOrderId
|
||||
}, request.session.user);
|
||||
const results = await getBurialSites({
|
||||
workOrderId: request.body.workOrderId
|
||||
|
|
|
|||
|
|
@ -7,14 +7,14 @@ export default async function handler(
|
|||
request: Request<
|
||||
unknown,
|
||||
unknown,
|
||||
{ workOrderId: string; burialSiteId: string }
|
||||
{ burialSiteId: string; workOrderId: string; }
|
||||
>,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
const success = await addWorkOrderBurialSite(
|
||||
{
|
||||
workOrderId: request.body.workOrderId,
|
||||
burialSiteId: request.body.burialSiteId
|
||||
burialSiteId: request.body.burialSiteId,
|
||||
workOrderId: request.body.workOrderId
|
||||
},
|
||||
request.session.user as User
|
||||
)
|
||||
|
|
@ -26,6 +26,7 @@ export default async function handler(
|
|||
{
|
||||
limit: -1,
|
||||
offset: 0,
|
||||
|
||||
includeContractCount: false
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
import type { Request, Response } from 'express';
|
||||
export default function handler(request: Request, response: Response): Promise<void>;
|
||||
import { type AddWorkOrderCommentForm } from '../../database/addWorkOrderComment.js';
|
||||
export default function handler(request: Request<unknown, unknown, AddWorkOrderCommentForm>, response: Response): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -6,13 +6,10 @@ import addWorkOrderComment, {
|
|||
import getWorkOrderComments from '../../database/getWorkOrderComments.js'
|
||||
|
||||
export default async function handler(
|
||||
request: Request,
|
||||
request: Request<unknown, unknown, AddWorkOrderCommentForm>,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
await addWorkOrderComment(
|
||||
request.body as AddWorkOrderCommentForm,
|
||||
request.session.user as User
|
||||
)
|
||||
await addWorkOrderComment(request.body, request.session.user as User)
|
||||
|
||||
const workOrderComments = await getWorkOrderComments(
|
||||
request.body.workOrderId as string
|
||||
|
|
|
|||
|
|
@ -10,8 +10,8 @@ export default async function handler(request, response) {
|
|||
}, {
|
||||
limit: -1,
|
||||
offset: 0,
|
||||
includeInterments: true,
|
||||
includeFees: false,
|
||||
includeInterments: true,
|
||||
includeTransactions: false
|
||||
});
|
||||
response.json({
|
||||
|
|
|
|||
|
|
@ -26,8 +26,9 @@ export default async function handler(
|
|||
{
|
||||
limit: -1,
|
||||
offset: 0,
|
||||
includeInterments: true,
|
||||
|
||||
includeFees: false,
|
||||
includeInterments: true,
|
||||
includeTransactions: false
|
||||
}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
import type { Request, Response } from 'express';
|
||||
export default function handler(request: Request, response: Response): Promise<void>;
|
||||
import { type AddWorkOrderMilestoneForm } from '../../database/addWorkOrderMilestone.js';
|
||||
export default function handler(request: Request<unknown, unknown, AddWorkOrderMilestoneForm>, response: Response): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -6,17 +6,17 @@ import addWorkOrderMilestone, {
|
|||
import getWorkOrderMilestones from '../../database/getWorkOrderMilestones.js'
|
||||
|
||||
export default async function handler(
|
||||
request: Request,
|
||||
request: Request<unknown, unknown, AddWorkOrderMilestoneForm>,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
const success = await addWorkOrderMilestone(
|
||||
request.body as AddWorkOrderMilestoneForm,
|
||||
request.body,
|
||||
request.session.user as User
|
||||
)
|
||||
|
||||
const workOrderMilestones = await getWorkOrderMilestones(
|
||||
{
|
||||
workOrderId: request.body.workOrderId as string
|
||||
workOrderId: request.body.workOrderId
|
||||
},
|
||||
{
|
||||
orderBy: 'completion'
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
import type { Request, Response } from 'express';
|
||||
export default function handler(request: Request, response: Response): Promise<void>;
|
||||
import { type CloseWorkOrderForm } from '../../database/closeWorkOrder.js';
|
||||
export default function handler(request: Request<unknown, unknown, CloseWorkOrderForm>, response: Response): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -5,11 +5,11 @@ import closeWorkOrder, {
|
|||
} from '../../database/closeWorkOrder.js'
|
||||
|
||||
export default async function handler(
|
||||
request: Request,
|
||||
request: Request<unknown, unknown, CloseWorkOrderForm>,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
const success = await closeWorkOrder(
|
||||
request.body as CloseWorkOrderForm,
|
||||
request.body,
|
||||
request.session.user as User
|
||||
)
|
||||
|
||||
|
|
@ -17,4 +17,3 @@ export default async function handler(
|
|||
success
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,2 +1,5 @@
|
|||
import type { Request, Response } from 'express';
|
||||
export default function handler(request: Request, response: Response): Promise<void>;
|
||||
export default function handler(request: Request<unknown, unknown, {
|
||||
workOrderId: string;
|
||||
workOrderMilestoneId: string;
|
||||
}>, response: Response): Promise<void>;
|
||||
|
|
|
|||
|
|
@ -4,19 +4,23 @@ import completeWorkOrderMilestone from '../../database/completeWorkOrderMileston
|
|||
import getWorkOrderMilestones from '../../database/getWorkOrderMilestones.js'
|
||||
|
||||
export default async function handler(
|
||||
request: Request,
|
||||
request: Request<
|
||||
unknown,
|
||||
unknown,
|
||||
{ workOrderId: string; workOrderMilestoneId: string }
|
||||
>,
|
||||
response: Response
|
||||
): Promise<void> {
|
||||
const success = await completeWorkOrderMilestone(
|
||||
{
|
||||
workOrderMilestoneId: request.body.workOrderMilestoneId as string
|
||||
workOrderMilestoneId: request.body.workOrderMilestoneId
|
||||
},
|
||||
request.session.user as User
|
||||
)
|
||||
|
||||
const workOrderMilestones = await getWorkOrderMilestones(
|
||||
{
|
||||
workOrderId: request.body.workOrderId as string
|
||||
workOrderId: request.body.workOrderId
|
||||
},
|
||||
{
|
||||
orderBy: 'completion'
|
||||
|
|
|
|||
|
|
@ -2,4 +2,4 @@ export declare const useTestDatabases: boolean;
|
|||
export declare const sunriseDBLive = "data/sunrise.db";
|
||||
export declare const sunriseDBTesting = "data/sunrise-testing.db";
|
||||
export declare const sunriseDB: string;
|
||||
export declare const backupFolder = "data/backups";
|
||||
export declare function backupDatabase(): Promise<false | string>;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import fs from 'node:fs/promises';
|
||||
import Debug from 'debug';
|
||||
import { DEBUG_NAMESPACE } from '../debug.config.js';
|
||||
import { getConfigProperty } from './config.helpers.js';
|
||||
|
|
@ -10,4 +11,15 @@ if (useTestDatabases) {
|
|||
export const sunriseDBLive = 'data/sunrise.db';
|
||||
export const sunriseDBTesting = 'data/sunrise-testing.db';
|
||||
export const sunriseDB = useTestDatabases ? sunriseDBTesting : sunriseDBLive;
|
||||
export const backupFolder = 'data/backups';
|
||||
const backupFolder = 'data/backups';
|
||||
export async function backupDatabase() {
|
||||
const databasePathSplit = sunriseDB.split(/[/\\]/);
|
||||
const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}`;
|
||||
try {
|
||||
await fs.copyFile(sunriseDB, backupDatabasePath);
|
||||
return backupDatabasePath;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import fs from 'node:fs/promises'
|
||||
|
||||
import Debug from 'debug'
|
||||
|
||||
import { DEBUG_NAMESPACE } from '../debug.config.js'
|
||||
|
|
@ -19,4 +21,17 @@ export const sunriseDBTesting = 'data/sunrise-testing.db'
|
|||
|
||||
export const sunriseDB = useTestDatabases ? sunriseDBTesting : sunriseDBLive
|
||||
|
||||
export const backupFolder = 'data/backups'
|
||||
const backupFolder = 'data/backups'
|
||||
|
||||
export async function backupDatabase(): Promise<false | string> {
|
||||
const databasePathSplit = sunriseDB.split(/[/\\]/)
|
||||
|
||||
const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}`
|
||||
|
||||
try {
|
||||
await fs.copyFile(sunriseDB, backupDatabasePath)
|
||||
return backupDatabasePath
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
export declare function backupDatabase(): Promise<false | string>;
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
import fs from 'node:fs/promises';
|
||||
import { backupFolder, sunriseDB as databasePath } from '../helpers/database.helpers.js';
|
||||
export async function backupDatabase() {
|
||||
const databasePathSplit = databasePath.split(/[/\\]/);
|
||||
const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}`;
|
||||
try {
|
||||
await fs.copyFile(databasePath, backupDatabasePath);
|
||||
return backupDatabasePath;
|
||||
}
|
||||
catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import fs from 'node:fs/promises'
|
||||
|
||||
import {
|
||||
backupFolder,
|
||||
sunriseDB as databasePath
|
||||
} from '../helpers/database.helpers.js'
|
||||
|
||||
export async function backupDatabase(): Promise<false | string> {
|
||||
const databasePathSplit = databasePath.split(/[/\\]/)
|
||||
|
||||
const backupDatabasePath = `${backupFolder}/${databasePathSplit.at(-1)}.${Date.now().toString()}`
|
||||
|
||||
try {
|
||||
await fs.copyFile(databasePath, backupDatabasePath)
|
||||
return backupDatabasePath
|
||||
} catch {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
|
@ -1,34 +1,83 @@
|
|||
import fs from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import chokidar from 'chokidar';
|
||||
import Debug from 'debug';
|
||||
import { DEBUG_NAMESPACE } from '../debug.config.js';
|
||||
import { getConfigProperty } from './config.helpers.js';
|
||||
let burialSiteImages;
|
||||
const debug = Debug(`${DEBUG_NAMESPACE}:images.helpers`);
|
||||
/*
|
||||
* Burial Site Images
|
||||
*/
|
||||
const burialSiteImagesFolder = path.join(getConfigProperty('settings.publicInternalPath'), 'images', 'burialSites');
|
||||
const burialSiteImageFileExtensions = ['jpg', 'jpeg', 'png'];
|
||||
let burialSiteImages = [];
|
||||
export async function getBurialSiteImages() {
|
||||
if (burialSiteImages === undefined) {
|
||||
const files = await fs.readdir(path.join(getConfigProperty('settings.publicInternalPath'), 'images', 'burialSites'));
|
||||
if (burialSiteImages.length === 0) {
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
const files = await fs.readdir(burialSiteImagesFolder);
|
||||
const images = [];
|
||||
for (const file of files) {
|
||||
const lowerCaseFileName = file.toLowerCase();
|
||||
if (lowerCaseFileName.endsWith('.jpg') ||
|
||||
lowerCaseFileName.endsWith('.jpeg') ||
|
||||
lowerCaseFileName.endsWith('.png')) {
|
||||
images.push(file);
|
||||
for (const fileExtension of burialSiteImageFileExtensions) {
|
||||
if (lowerCaseFileName.endsWith(`.${fileExtension}`)) {
|
||||
images.push(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
burialSiteImages = images;
|
||||
}
|
||||
return burialSiteImages;
|
||||
}
|
||||
let cemeterySVGs;
|
||||
function clearCachedBurialSiteImages() {
|
||||
debug('Burial site images folder changed.');
|
||||
burialSiteImages = [];
|
||||
}
|
||||
if (getConfigProperty('settings.burialSites.refreshImageChanges')) {
|
||||
debug('Burial site images watcher enabled.');
|
||||
const burialSitesWatcher = chokidar.watch(burialSiteImagesFolder, {
|
||||
ignoreInitial: true,
|
||||
persistent: true
|
||||
});
|
||||
burialSitesWatcher.on('add', clearCachedBurialSiteImages);
|
||||
burialSitesWatcher.on('change', clearCachedBurialSiteImages);
|
||||
burialSitesWatcher.on('unlink', clearCachedBurialSiteImages);
|
||||
}
|
||||
/*
|
||||
* Cemetery SVGs
|
||||
*/
|
||||
const cemeterySVGsFolder = path.join(getConfigProperty('settings.publicInternalPath'), 'images', 'cemeteries');
|
||||
const cemeterySVGFileExtensions = ['svg'];
|
||||
let cemeterySVGs = [];
|
||||
export async function getCemeterySVGs() {
|
||||
if (cemeterySVGs === undefined) {
|
||||
const files = await fs.readdir(path.join(getConfigProperty('settings.publicInternalPath'), 'images', 'cemeteries'));
|
||||
if (cemeterySVGs.length === 0) {
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
const files = await fs.readdir(cemeterySVGsFolder);
|
||||
const SVGs = [];
|
||||
for (const file of files) {
|
||||
if (file.toLowerCase().endsWith('.svg')) {
|
||||
SVGs.push(file);
|
||||
const lowerCaseFileName = file.toLowerCase();
|
||||
for (const fileExtension of cemeterySVGFileExtensions) {
|
||||
if (lowerCaseFileName.endsWith(`.${fileExtension}`)) {
|
||||
SVGs.push(file);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
cemeterySVGs = SVGs;
|
||||
}
|
||||
return cemeterySVGs;
|
||||
}
|
||||
function clearCachedCemeterySVGs() {
|
||||
debug('Cemetery SVGs folder changed.');
|
||||
cemeterySVGs = [];
|
||||
}
|
||||
if (getConfigProperty('settings.cemeteries.refreshImageChanges')) {
|
||||
debug('Cemetery SVGs watcher enabled.');
|
||||
const cemeteryWatcher = chokidar.watch(cemeterySVGsFolder, {
|
||||
ignoreInitial: true,
|
||||
persistent: true
|
||||
});
|
||||
cemeteryWatcher.on('add', clearCachedCemeterySVGs);
|
||||
cemeteryWatcher.on('change', clearCachedCemeterySVGs);
|
||||
cemeteryWatcher.on('unlink', clearCachedCemeterySVGs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,44 @@
|
|||
import fs from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
|
||||
import chokidar from 'chokidar'
|
||||
import Debug from 'debug'
|
||||
|
||||
import { DEBUG_NAMESPACE } from '../debug.config.js'
|
||||
|
||||
import { getConfigProperty } from './config.helpers.js'
|
||||
|
||||
let burialSiteImages: string[] | undefined
|
||||
const debug = Debug(`${DEBUG_NAMESPACE}:images.helpers`)
|
||||
|
||||
/*
|
||||
* Burial Site Images
|
||||
*/
|
||||
|
||||
const burialSiteImagesFolder = path.join(
|
||||
getConfigProperty('settings.publicInternalPath'),
|
||||
'images',
|
||||
'burialSites'
|
||||
)
|
||||
|
||||
const burialSiteImageFileExtensions = ['jpg', 'jpeg', 'png']
|
||||
|
||||
let burialSiteImages: string[] = []
|
||||
|
||||
export async function getBurialSiteImages(): Promise<string[]> {
|
||||
if (burialSiteImages === undefined) {
|
||||
const files = await fs.readdir(
|
||||
path.join(
|
||||
getConfigProperty('settings.publicInternalPath'),
|
||||
'images',
|
||||
'burialSites'
|
||||
)
|
||||
)
|
||||
if (burialSiteImages.length === 0) {
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
const files = await fs.readdir(burialSiteImagesFolder)
|
||||
|
||||
const images: string[] = []
|
||||
|
||||
for (const file of files) {
|
||||
const lowerCaseFileName = file.toLowerCase()
|
||||
if (
|
||||
lowerCaseFileName.endsWith('.jpg') ||
|
||||
lowerCaseFileName.endsWith('.jpeg') ||
|
||||
lowerCaseFileName.endsWith('.png')
|
||||
) {
|
||||
images.push(file)
|
||||
|
||||
for (const fileExtension of burialSiteImageFileExtensions) {
|
||||
if (lowerCaseFileName.endsWith(`.${fileExtension}`)) {
|
||||
images.push(file)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -34,21 +48,53 @@ export async function getBurialSiteImages(): Promise<string[]> {
|
|||
return burialSiteImages
|
||||
}
|
||||
|
||||
let cemeterySVGs: string[] | undefined
|
||||
function clearCachedBurialSiteImages(): void {
|
||||
debug('Burial site images folder changed.')
|
||||
burialSiteImages = []
|
||||
}
|
||||
|
||||
if (getConfigProperty('settings.burialSites.refreshImageChanges')) {
|
||||
debug('Burial site images watcher enabled.')
|
||||
|
||||
const burialSitesWatcher = chokidar.watch(burialSiteImagesFolder, {
|
||||
ignoreInitial: true,
|
||||
persistent: true
|
||||
})
|
||||
|
||||
burialSitesWatcher.on('add', clearCachedBurialSiteImages)
|
||||
burialSitesWatcher.on('change', clearCachedBurialSiteImages)
|
||||
burialSitesWatcher.on('unlink', clearCachedBurialSiteImages)
|
||||
}
|
||||
|
||||
/*
|
||||
* Cemetery SVGs
|
||||
*/
|
||||
|
||||
const cemeterySVGsFolder = path.join(
|
||||
getConfigProperty('settings.publicInternalPath'),
|
||||
'images',
|
||||
'cemeteries'
|
||||
)
|
||||
|
||||
const cemeterySVGFileExtensions = ['svg']
|
||||
|
||||
let cemeterySVGs: string[] = []
|
||||
|
||||
export async function getCemeterySVGs(): Promise<string[]> {
|
||||
if (cemeterySVGs === undefined) {
|
||||
const files = await fs.readdir(path.join(
|
||||
getConfigProperty('settings.publicInternalPath'),
|
||||
'images',
|
||||
'cemeteries'
|
||||
))
|
||||
if (cemeterySVGs.length === 0) {
|
||||
// eslint-disable-next-line security/detect-non-literal-fs-filename
|
||||
const files = await fs.readdir(cemeterySVGsFolder)
|
||||
|
||||
const SVGs: string[] = []
|
||||
|
||||
for (const file of files) {
|
||||
if (file.toLowerCase().endsWith('.svg')) {
|
||||
SVGs.push(file)
|
||||
const lowerCaseFileName = file.toLowerCase()
|
||||
|
||||
for (const fileExtension of cemeterySVGFileExtensions) {
|
||||
if (lowerCaseFileName.endsWith(`.${fileExtension}`)) {
|
||||
SVGs.push(file)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -57,3 +103,21 @@ export async function getCemeterySVGs(): Promise<string[]> {
|
|||
|
||||
return cemeterySVGs
|
||||
}
|
||||
|
||||
function clearCachedCemeterySVGs(): void {
|
||||
debug('Cemetery SVGs folder changed.')
|
||||
cemeterySVGs = []
|
||||
}
|
||||
|
||||
if (getConfigProperty('settings.cemeteries.refreshImageChanges')) {
|
||||
debug('Cemetery SVGs watcher enabled.')
|
||||
|
||||
const cemeteryWatcher = chokidar.watch(cemeterySVGsFolder, {
|
||||
ignoreInitial: true,
|
||||
persistent: true
|
||||
})
|
||||
|
||||
cemeteryWatcher.on('add', clearCachedCemeterySVGs)
|
||||
cemeteryWatcher.on('change', clearCachedCemeterySVGs)
|
||||
cemeteryWatcher.on('unlink', clearCachedCemeterySVGs)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
"better-sqlite3": "^11.9.1",
|
||||
"bulma-tooltip": "^3.0.2",
|
||||
"camelcase": "^8.0.0",
|
||||
"chokidar": "^4.0.3",
|
||||
"compression": "^1.8.0",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cross-env": "^7.0.3",
|
||||
|
|
@ -60,6 +61,7 @@
|
|||
"@types/http-errors": "^2.0.4",
|
||||
"@types/leaflet": "^1.9.17",
|
||||
"@types/mssql": "^9.1.7",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node-windows": "^0.1.6",
|
||||
"@types/papaparse": "^5.3.15",
|
||||
"@types/randomcolor": "^0.5.9",
|
||||
|
|
@ -2037,11 +2039,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "18.18.13",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.18.13.tgz",
|
||||
"integrity": "sha512-vXYZGRrSCreZmq1rEjMRLXJhiy8MrIeVasx+PCVlP414N7CJLHnMf+juVvjdprHyH+XRy3zKZLHeNueOpJCn0g==",
|
||||
"version": "22.14.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz",
|
||||
"integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"undici-types": "~5.26.4"
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node-windows": {
|
||||
|
|
@ -2606,6 +2609,7 @@
|
|||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
|
||||
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
|
|
@ -3082,12 +3086,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
|
||||
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/bindings": {
|
||||
|
|
@ -3469,44 +3477,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
],
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
|
||||
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
"readdirp": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
"node": ">= 14.16.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar/node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/chownr": {
|
||||
|
|
@ -6269,6 +6251,21 @@
|
|||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||
"integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
|
|
@ -7135,6 +7132,7 @@
|
|||
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
},
|
||||
|
|
@ -9415,6 +9413,31 @@
|
|||
"url": "https://opencollective.com/nodemon"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/chokidar": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
|
||||
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
"glob-parent": "~5.1.2",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.6.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 8.10.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
|
|
@ -9424,6 +9447,19 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/nodemon/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
|
|
@ -9477,6 +9513,7 @@
|
|||
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
|
||||
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
|
@ -10568,15 +10605,16 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/readdirp": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"picomatch": "^2.2.1"
|
||||
},
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
|
||||
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.10.0"
|
||||
"node": ">= 14.18.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "individual",
|
||||
"url": "https://paulmillr.com/funding/"
|
||||
}
|
||||
},
|
||||
"node_modules/refa": {
|
||||
|
|
@ -12388,9 +12426,10 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/unicorn-magic": {
|
||||
"version": "0.1.0",
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
"better-sqlite3": "^11.9.1",
|
||||
"bulma-tooltip": "^3.0.2",
|
||||
"camelcase": "^8.0.0",
|
||||
"chokidar": "^4.0.3",
|
||||
"compression": "^1.8.0",
|
||||
"cookie-parser": "^1.4.7",
|
||||
"cross-env": "^7.0.3",
|
||||
|
|
@ -83,6 +84,7 @@
|
|||
"@types/http-errors": "^2.0.4",
|
||||
"@types/leaflet": "^1.9.17",
|
||||
"@types/mssql": "^9.1.7",
|
||||
"@types/node": "^22.14.1",
|
||||
"@types/node-windows": "^0.1.6",
|
||||
"@types/papaparse": "^5.3.15",
|
||||
"@types/randomcolor": "^0.5.9",
|
||||
|
|
|
|||
|
|
@ -485,7 +485,7 @@ async function importFromMasterCSV(): Promise<void> {
|
|||
* Interment Record
|
||||
*/
|
||||
|
||||
let deceasedContractStartDateString: DateString | ''
|
||||
let deceasedContractStartDateString: '' | DateString
|
||||
let deceasedContractId: number
|
||||
|
||||
if (masterRow.CM_DECEASED_NAME !== '') {
|
||||
|
|
|
|||
|
|
@ -30,8 +30,12 @@ export interface Config {
|
|||
fees: {
|
||||
taxPercentageDefault?: number;
|
||||
};
|
||||
cemeteries: {
|
||||
refreshImageChanges?: boolean;
|
||||
};
|
||||
burialSites: {
|
||||
burialSiteNameSegments?: ConfigBurialSiteNameSegments;
|
||||
refreshImageChanges?: boolean;
|
||||
};
|
||||
contracts: {
|
||||
burialSiteIdIsRequired?: boolean;
|
||||
|
|
|
|||
|
|
@ -42,8 +42,13 @@ export interface Config {
|
|||
taxPercentageDefault?: number
|
||||
}
|
||||
|
||||
cemeteries: {
|
||||
refreshImageChanges?: boolean
|
||||
}
|
||||
|
||||
burialSites: {
|
||||
burialSiteNameSegments?: ConfigBurialSiteNameSegments
|
||||
refreshImageChanges?: boolean
|
||||
}
|
||||
|
||||
contracts: {
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ export interface BurialSite extends Record {
|
|||
cemeteryName?: string;
|
||||
cemeterySvg?: string;
|
||||
cemeterySvgId?: string;
|
||||
cemeteryLatitude?: number;
|
||||
cemeteryLongitude?: number;
|
||||
burialSiteImage?: string;
|
||||
burialSiteLatitude?: number;
|
||||
burialSiteLongitude?: number;
|
||||
|
|
@ -69,6 +71,9 @@ export interface Cemetery extends Record {
|
|||
cemeteryName: string;
|
||||
parentCemeteryId?: number | null;
|
||||
parentCemeteryName?: string | null;
|
||||
parentCemeteryLatitude?: number | null;
|
||||
parentCemeteryLongitude?: number | null;
|
||||
parentCemeterySvg?: string | null;
|
||||
cemeteryLatitude?: number;
|
||||
cemeteryLongitude?: number;
|
||||
cemeterySvg?: string;
|
||||
|
|
|
|||
|
|
@ -19,6 +19,9 @@ export interface BurialSite extends Record {
|
|||
cemeterySvg?: string
|
||||
cemeterySvgId?: string
|
||||
|
||||
cemeteryLatitude?: number
|
||||
cemeteryLongitude?: number
|
||||
|
||||
burialSiteImage?: string
|
||||
|
||||
burialSiteLatitude?: number
|
||||
|
|
@ -97,6 +100,10 @@ export interface Cemetery extends Record {
|
|||
parentCemeteryId?: number | null
|
||||
parentCemeteryName?: string | null
|
||||
|
||||
parentCemeteryLatitude?: number | null
|
||||
parentCemeteryLongitude?: number | null
|
||||
parentCemeterySvg?: string | null
|
||||
|
||||
cemeteryLatitude?: number
|
||||
cemeteryLongitude?: number
|
||||
cemeterySvg?: string
|
||||
|
|
|
|||
|
|
@ -26,6 +26,13 @@
|
|||
Config Table Management
|
||||
</h1>
|
||||
|
||||
<div class="message is-warning">
|
||||
<div class="message-body">
|
||||
<strong>Never change the meaning of the values in these tables.</strong><br />
|
||||
When in doubt, create a new value instead of changing an existing one.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tabs is-boxed">
|
||||
<ul role="presentation">
|
||||
<li class="is-active">
|
||||
|
|
|
|||
|
|
@ -113,6 +113,14 @@
|
|||
<div class="panel-block is-block">
|
||||
<% if (burialSite.burialSiteLatitude && burialSite.burialSiteLongitude) { %>
|
||||
<div id="burialSite--leaflet" data-latitude="<%= burialSite.burialSiteLatitude %>" data-longitude="<%= burialSite.burialSiteLongitude %>" style="height:300px"></div>
|
||||
<% } else if (burialSite.cemeteryLatitude && burialSite.cemeteryLongitude) { %>
|
||||
<div class="message is-info">
|
||||
<p class="message-body">
|
||||
<strong>Coordinates not available for this burial site.</strong><br />
|
||||
Coordinates for the cemetery are shown instead.
|
||||
</p>
|
||||
</div>
|
||||
<div id="burialSite--leaflet" data-latitude="<%= burialSite.cemeteryLatitude %>" data-longitude="<%= burialSite.cemeteryLongitude %>" style="height:300px"></div>
|
||||
<% } else { %>
|
||||
<div class="message is-info">
|
||||
<p class="message-body">
|
||||
|
|
|
|||
|
|
@ -121,6 +121,14 @@
|
|||
<div class="panel-block is-block">
|
||||
<% if (cemetery.cemeteryLatitude && cemetery.cemeteryLongitude) { %>
|
||||
<div id="cemetery--leaflet" data-latitude="<%= cemetery.cemeteryLatitude %>" data-longitude="<%= cemetery.cemeteryLongitude %>" style="height:300px"></div>
|
||||
<% } else if (cemetery.parentCemeteryLatitude && cemetery.parentCemeteryLongitude) { %>
|
||||
<div class="message is-info">
|
||||
<p class="message-body">
|
||||
<strong>Coordinates not available for this child cemtery.</strong><br />
|
||||
Coordinates for the parent cemetery are shown instead.
|
||||
</p>
|
||||
</div>
|
||||
<div id="cemetery--leaflet" data-latitude="<%= cemetery.parentCemeteryLatitude %>" data-longitude="<%= cemetery.parentCemeteryLongitude %>" style="height:300px"></div>
|
||||
<% } else { %>
|
||||
<div class="message is-info">
|
||||
<p class="message-body">
|
||||
|
|
|
|||
Loading…
Reference in New Issue