diff --git a/README.md b/README.md index ae43ccc..13ad088 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ ## Configuration ```shell -# Required API/authentication variables: +# Required API endpoint/authentication variables SONAR_URL=https://instance.sonar.software/api/graphql SONAR_TOKEN= RC_APP_KEY= @@ -17,15 +17,25 @@ RC_LOGIN_PASSWORD= # Set to any value to enable use of RingCentral's sandbox API RC_SANDBOX= +# The database to use +# valid options: pg, sqlite +# default: sqlite DB_ENGINE=sqlite # can be pg -# only used when DB_ENGINE=pg + +# Only used when DB_ENGINE=pg DB_URL= -# only used when DB_ENGINE=sqlite +# Only used when DB_ENGINE=sqlite +# default: voicemails.db DB_FILE=voicemails.db # A mapping of extension number to Sonar Ticket Group # Only the voicemail boxes of these extensions will be checked EXTENSION_TICKET_GROUPS=1:1,2:2,2:3 + +# Upon first run, query RingCentral voicemails up to FIRST_RUN_AGE seconds old. +# Useful when the application is restarted after not running for some time. +# default: 86400 (1 day) +FIRST_RUN_AGE=86400 ``` ## Deployment @@ -45,6 +55,8 @@ services: environment: # ... see Configuration above DB_FILE: /data/voicemails.db + # so the created tickets show the correct 'Received' date & time + TZ: America/Creston volumes: - data:/data ``` diff --git a/src/index.ts b/src/index.ts index e7f30b0..a65bd70 100644 --- a/src/index.ts +++ b/src/index.ts @@ -30,6 +30,22 @@ function getExtensionToTicketGroupMapping() { return mapping; } +const DEFAULT_FIRST_RUN_AGE = 86400; + +function getTicketizeConfig() { + const firstRunAge = process.env.FIRST_RUN_AGE + ? parseInt(process.env.FIRST_RUN_AGE) + : DEFAULT_FIRST_RUN_AGE; + if (isNaN(firstRunAge) || firstRunAge <= 0) { + throw new Error("FIRST_RUN_AGE must be a valid positive integer"); + } + + return { + firstRunAge, + extensionToTicketGroup: getExtensionToTicketGroupMapping(), + }; +} + async function initSonar() { const sonar = new Sonar(process.env.SONAR_URL!, process.env.SONAR_TOKEN!); // simple query to test API cedentials @@ -79,9 +95,7 @@ async function main() { const db = await initDB(); console.log("Starting ticketizer..."); - const intervals = ticketize(sonar, rcsdk, db, { - extensionToTicketGroup: getExtensionToTicketGroupMapping(), - }); + const intervals = ticketize(sonar, rcsdk, db, getTicketizeConfig()); ["SIGINT", "SIGTERM", "SIGQUIT"].forEach((sig) => { process.on(sig, async () => { diff --git a/src/ticketize.ts b/src/ticketize.ts index f7a30bb..40d38c6 100644 --- a/src/ticketize.ts +++ b/src/ticketize.ts @@ -49,6 +49,7 @@ function rcapi(short: string, version = "v1.0") { } interface TicketizeConfig { + firstRunAge: number; extensionToTicketGroup: { [key: string]: number }; } @@ -62,7 +63,7 @@ export function ticketize( sonar: Sonar, rcsdk: SDK, db: Knex, - { extensionToTicketGroup }: TicketizeConfig + { firstRunAge, extensionToTicketGroup }: TicketizeConfig ) { /** * Uploads a file to Sonar, returning its ID. @@ -92,17 +93,17 @@ export function ticketize( } /** - * Returns `extensionId`s messages that are up to `from` seconds old. + * Returns `extensionId`s messages that are up to `age` seconds old. * * @param extensionId - * @param from how many seconds ago to retrieve messages from + * @param age the maximum age (in seconds) of voicemails to fetch */ - async function getExtensionVoicemails(extensionId: number, from = 86000) { + async function getExtensionVoicemails(extensionId: number, age = 86000) { const result = await rcsdk.get( rcapi(`/account/~/extension/${extensionId}/message-store`), { messageType: "VoiceMail", - dateFrom: new Date(Date.now() - from * 1000).toISOString(), + dateFrom: new Date(Date.now() - age * 1000).toISOString(), } ); return (await result.json()).records as RCMessage[]; @@ -305,16 +306,13 @@ export function ticketize( } /** - * Retrieves and stores the voicemails for `extension` that are up to `from` + * Retrieves and stores the voicemails for `extension` that are up to `age` * seconds old. * @param extension - * @param from + * @param age */ - async function storeExtensionVoicemails( - extension: RCExtension, - from: number - ) { - const messages = await getExtensionVoicemails(extension.id, from); + async function storeExtensionVoicemails(extension: RCExtension, age: number) { + const messages = await getExtensionVoicemails(extension.id, age); const isStored = await Promise.all( messages.map((message) => isMessageStored(message.id)) ); @@ -335,15 +333,15 @@ export function ticketize( /** * Fetch and store new voicemails. If this is the first run, we get the last - * day's worth of voicemails. Otherwise, we fetch only the last 15 minutes. + * day's worth of voicemails. Otherwise, we fetch only the last 5 minutes. * - * @param firstRun whether this is the first run or not + * @param firstRun whether this is the first run */ async function fetchAndStoreNewVoicemails(firstRun = false) { const extensions = await getValidRCExtensions(); return Promise.all( extensions.map((extension) => - storeExtensionVoicemails(extension, firstRun ? 86400 : 900) + storeExtensionVoicemails(extension, firstRun ? firstRunAge : 300) ) ); }