Add FIRST_RUN_AGE variable
Allows setting the maximum age of voicemails to fetch on the first run. Other changes: - Refactor `from` to `age` in function parameters - Improve README
This commit is contained in:
parent
39cd664b3c
commit
0946158005
18
README.md
18
README.md
@ -5,7 +5,7 @@
|
|||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
# Required API/authentication variables:
|
# Required API endpoint/authentication variables
|
||||||
SONAR_URL=https://instance.sonar.software/api/graphql
|
SONAR_URL=https://instance.sonar.software/api/graphql
|
||||||
SONAR_TOKEN=
|
SONAR_TOKEN=
|
||||||
RC_APP_KEY=
|
RC_APP_KEY=
|
||||||
@ -17,15 +17,25 @@ RC_LOGIN_PASSWORD=
|
|||||||
# Set to any value to enable use of RingCentral's sandbox API
|
# Set to any value to enable use of RingCentral's sandbox API
|
||||||
RC_SANDBOX=
|
RC_SANDBOX=
|
||||||
|
|
||||||
|
# The database to use
|
||||||
|
# valid options: pg, sqlite
|
||||||
|
# default: sqlite
|
||||||
DB_ENGINE=sqlite # can be pg
|
DB_ENGINE=sqlite # can be pg
|
||||||
# only used when DB_ENGINE=pg
|
|
||||||
|
# Only used when DB_ENGINE=pg
|
||||||
DB_URL=
|
DB_URL=
|
||||||
# only used when DB_ENGINE=sqlite
|
# Only used when DB_ENGINE=sqlite
|
||||||
|
# default: voicemails.db
|
||||||
DB_FILE=voicemails.db
|
DB_FILE=voicemails.db
|
||||||
|
|
||||||
# A mapping of extension number to Sonar Ticket Group
|
# A mapping of extension number to Sonar Ticket Group
|
||||||
# Only the voicemail boxes of these extensions will be checked
|
# Only the voicemail boxes of these extensions will be checked
|
||||||
EXTENSION_TICKET_GROUPS=1:1,2:2,2:3
|
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
|
## Deployment
|
||||||
@ -45,6 +55,8 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
# ... see Configuration above
|
# ... see Configuration above
|
||||||
DB_FILE: /data/voicemails.db
|
DB_FILE: /data/voicemails.db
|
||||||
|
# so the created tickets show the correct 'Received' date & time
|
||||||
|
TZ: America/Creston
|
||||||
volumes:
|
volumes:
|
||||||
- data:/data
|
- data:/data
|
||||||
```
|
```
|
||||||
|
20
src/index.ts
20
src/index.ts
@ -30,6 +30,22 @@ function getExtensionToTicketGroupMapping() {
|
|||||||
return mapping;
|
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() {
|
async function initSonar() {
|
||||||
const sonar = new Sonar(process.env.SONAR_URL!, process.env.SONAR_TOKEN!);
|
const sonar = new Sonar(process.env.SONAR_URL!, process.env.SONAR_TOKEN!);
|
||||||
// simple query to test API cedentials
|
// simple query to test API cedentials
|
||||||
@ -79,9 +95,7 @@ async function main() {
|
|||||||
const db = await initDB();
|
const db = await initDB();
|
||||||
|
|
||||||
console.log("Starting ticketizer...");
|
console.log("Starting ticketizer...");
|
||||||
const intervals = ticketize(sonar, rcsdk, db, {
|
const intervals = ticketize(sonar, rcsdk, db, getTicketizeConfig());
|
||||||
extensionToTicketGroup: getExtensionToTicketGroupMapping(),
|
|
||||||
});
|
|
||||||
|
|
||||||
["SIGINT", "SIGTERM", "SIGQUIT"].forEach((sig) => {
|
["SIGINT", "SIGTERM", "SIGQUIT"].forEach((sig) => {
|
||||||
process.on(sig, async () => {
|
process.on(sig, async () => {
|
||||||
|
@ -49,6 +49,7 @@ function rcapi(short: string, version = "v1.0") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface TicketizeConfig {
|
interface TicketizeConfig {
|
||||||
|
firstRunAge: number;
|
||||||
extensionToTicketGroup: { [key: string]: number };
|
extensionToTicketGroup: { [key: string]: number };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,7 +63,7 @@ export function ticketize(
|
|||||||
sonar: Sonar,
|
sonar: Sonar,
|
||||||
rcsdk: SDK,
|
rcsdk: SDK,
|
||||||
db: Knex,
|
db: Knex,
|
||||||
{ extensionToTicketGroup }: TicketizeConfig
|
{ firstRunAge, extensionToTicketGroup }: TicketizeConfig
|
||||||
) {
|
) {
|
||||||
/**
|
/**
|
||||||
* Uploads a file to Sonar, returning its ID.
|
* 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 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(
|
const result = await rcsdk.get(
|
||||||
rcapi(`/account/~/extension/${extensionId}/message-store`),
|
rcapi(`/account/~/extension/${extensionId}/message-store`),
|
||||||
{
|
{
|
||||||
messageType: "VoiceMail",
|
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[];
|
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.
|
* seconds old.
|
||||||
* @param extension
|
* @param extension
|
||||||
* @param from
|
* @param age
|
||||||
*/
|
*/
|
||||||
async function storeExtensionVoicemails(
|
async function storeExtensionVoicemails(extension: RCExtension, age: number) {
|
||||||
extension: RCExtension,
|
const messages = await getExtensionVoicemails(extension.id, age);
|
||||||
from: number
|
|
||||||
) {
|
|
||||||
const messages = await getExtensionVoicemails(extension.id, from);
|
|
||||||
const isStored = await Promise.all(
|
const isStored = await Promise.all(
|
||||||
messages.map((message) => isMessageStored(message.id))
|
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
|
* 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) {
|
async function fetchAndStoreNewVoicemails(firstRun = false) {
|
||||||
const extensions = await getValidRCExtensions();
|
const extensions = await getValidRCExtensions();
|
||||||
return Promise.all(
|
return Promise.all(
|
||||||
extensions.map((extension) =>
|
extensions.map((extension) =>
|
||||||
storeExtensionVoicemails(extension, firstRun ? 86400 : 900)
|
storeExtensionVoicemails(extension, firstRun ? firstRunAge : 300)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user