Skip to content

Commit

Permalink
Merge pull request #535 from JiscSD/OC-732
Browse files Browse the repository at this point in the history
OC-732: Preparing for scheduled notifications
  • Loading branch information
finlay-jisc authored Nov 21, 2023
2 parents 2b8f8d1 + 0434555 commit d41ebdc
Show file tree
Hide file tree
Showing 15 changed files with 182 additions and 113 deletions.
4 changes: 1 addition & 3 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,9 @@
"test:local": "STAGE=local jest --runInBand --testTimeout=60000",
"test:watch": "npm run test:local -- --watch",
"reindex": "ts-node prisma/reindex.ts",
"convertAffiliations": "ts-node prisma/convertAffiliations.ts",
"insertTestTopics": "ts-node prisma/insertTestTopics.ts",
"convertPublicationBookmarks": "ts-node prisma/convertPublicationBookmarks.ts",
"createVersionedDOIs": "ts-node -r tsconfig-paths/register prisma/createVersionedDOIs.ts",
"updateLinksStatus": "ts-node -r tsconfig-paths/register prisma/updateLinksStatus.ts",
"insertDummyEvent": "ts-node -r tsconfig-paths/register prisma/insertDummyEvent.ts",
"format:check": "npx prettier --check src/",
"format:write": "npx prettier --write src/",
"lint:check": "eslint src/",
Expand Down
30 changes: 0 additions & 30 deletions api/prisma/convertPublicationBookmarks.ts

This file was deleted.

28 changes: 28 additions & 0 deletions api/prisma/insertDummyEvent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import * as client from '../src/lib/client';

// Expects an email address to be supplied to send a notification to. Should be executed like this:
// npm run insertDummyEvent test.example@domain.com
const insertDummyEvent = async (): Promise<string> => {
if (process.argv[2]) {
const to = process.argv[2];
const data = {
to
};
await client.prisma.event.create({
data: {
type: 'dummy',
data
}
});

return 'Done';
} else {
console.log('No to address supplied! Please supply one.');

return 'Failed';
}
};

insertDummyEvent()
.then((message) => console.log(message))
.catch((err) => console.log(err));
37 changes: 0 additions & 37 deletions api/prisma/insertTestTopics.ts

This file was deleted.

9 changes: 9 additions & 0 deletions api/prisma/migrations/20231116102106_events/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-- CreateTable
CREATE TABLE "Event" (
"id" TEXT NOT NULL,
"type" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"data" JSONB NOT NULL,

CONSTRAINT "Event_pkey" PRIMARY KEY ("id")
);
43 changes: 25 additions & 18 deletions api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,15 @@ model Images {
}

model Publication {
id String @id @default(cuid())
url_slug String @unique @default(cuid())
type PublicationType
doi String
publicationFlags PublicationFlags[]
PublicationBookmarks PublicationBookmarks[]
linkedTo Links[] @relation("from")
linkedFrom Links[] @relation("to")
versions PublicationVersion[]
id String @id @default(cuid())
url_slug String @unique @default(cuid())
type PublicationType
doi String
publicationFlags PublicationFlags[]
PublicationBookmarks PublicationBookmarks[]
linkedTo Links[] @relation("from")
linkedFrom Links[] @relation("to")
versions PublicationVersion[]
}

model PublicationVersion {
Expand Down Expand Up @@ -195,15 +195,15 @@ model PublicationBookmarks {
}

model Topic {
id String @id @default(cuid())
title String
language Languages @default(en)
translations TopicTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parents Topic[] @relation("TopicHierarchy")
children Topic[] @relation("TopicHierarchy")
publicationVersions PublicationVersion[]
id String @id @default(cuid())
title String
language Languages @default(en)
translations TopicTranslation[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
parents Topic[] @relation("TopicHierarchy")
children Topic[] @relation("TopicHierarchy")
publicationVersions PublicationVersion[]
}

model Bookmark {
Expand All @@ -225,6 +225,13 @@ model TopicTranslation {
topic Topic @relation(fields: [topicId], references: [id], onDelete: Cascade)
}

model Event {
id String @id @default(cuid())
type String
createdAt DateTime @default(now())
data Json
}

enum ImageExtension {
png
jpg
Expand Down
25 changes: 0 additions & 25 deletions api/prisma/versioningMigration.md

This file was deleted.

9 changes: 9 additions & 0 deletions api/serverless.yml
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,12 @@ functions:
path: ${self:custom.versions.v1}/topics
method: GET
cors: true

# Events
dailyEventCheck:
handler: src/components/event/routes.dailyEventCheck
events:
# TODO: uncomment schedule below when functionality has been tested.
# - schedule: cron(0 7 ? * * *) # Every day at 7 a.m.
# TODO: remove schedule below when functionality has been tested.
- schedule: cron(0 * ? * * *) # Every hour, on the hour.
23 changes: 23 additions & 0 deletions api/src/components/event/__tests__/processEvent.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import * as client from 'lib/client';
import * as testUtils from 'lib/testUtils';
import * as eventController from 'event/controller';

describe('Process events', () => {
beforeAll(async () => {
await testUtils.clearDB();
});

test('Process a dummy event', async () => {
const data = {
to: '[email protected]'
};
await client.prisma.event.create({
data: {
type: 'dummy',
data
}
});
const processEvents = await eventController.dailyEventCheck();
expect(processEvents.body).toEqual(JSON.stringify({ message: 'Processed 1 event' }));
});
});
43 changes: 43 additions & 0 deletions api/src/components/event/controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import * as I from 'interface';
import * as email from 'email';
import * as response from 'lib/response';
import * as eventService from 'event/service';
import { Prisma } from '@prisma/client';

/**
* @todo: Remove code related to dummy events once functionality has been tested.
*/
export const dailyEventCheck = async (): Promise<I.JSONResponse> => {
// Collect all pending dummy events
const events = await eventService.getByTypes(['dummy']);

let successCount = 0;
let failureCount = 0;

// Send an email to an address specified in the event json
for (const dummyEvent of events) {
if (dummyEvent.data) {
const eventData = dummyEvent.data as Prisma.JsonObject;

if (eventData.to) {
await email.dummyEventNotification(eventData.to as string);
// Delete event record when done
await eventService.deleteEvent(dummyEvent.id);
successCount++;
} else {
console.log('Unable to process event; no to address provided', dummyEvent.id);
failureCount++;
}
}
}

if (failureCount) {
return response.json(200, {
message: `Finished with ${failureCount} error${failureCount !== 1 ? 's' : ''}`
});
}

return response.json(200, {
message: `Processed ${successCount} event${successCount !== 1 ? 's' : ''}`
});
};
3 changes: 3 additions & 0 deletions api/src/components/event/routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as eventController from 'event/controller';

export const dailyEventCheck = eventController.dailyEventCheck;
16 changes: 16 additions & 0 deletions api/src/components/event/service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import * as client from 'lib/client';
import * as I from 'lib/interface';

export const getByTypes = async (types: I.EventType[]) =>
client.prisma.event.findMany({
where: {
type: {
in: types
}
}
});

export const deleteEvent = async (id: string) =>
client.prisma.event.delete({
where: { id }
});
15 changes: 15 additions & 0 deletions api/src/lib/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -719,3 +719,18 @@ export const notifyCoAuthorCancelledApproval = async (options: NotifyCoAuthorCan
subject: 'A co-author has cancelled their approval'
});
};

/**
* @todo: remove once functionality has been tested.
*/
export const dummyEventNotification = async (to: string): Promise<void> => {
const html = '<p>This is a test notification to demonstrate the scheduled notification functionality.</p>';
const text = 'This is a test notification to demonstrate the scheduled notification functionality.';

await send({
html: standardHTMLEmailTemplate('Dummy event nofication', html, 'This was sent by a scheduled function'),
text,
to,
subject: 'Dummy event nofication'
});
};
7 changes: 7 additions & 0 deletions api/src/lib/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -828,6 +828,7 @@ export interface UserEmployment {
organisation: string;
}

// Topics
export interface TopicTranslation {
language: Languages;
value: string;
Expand Down Expand Up @@ -861,3 +862,9 @@ export interface TopicsPaginatedResults {
createdAt: Date;
}[];
}

// Events
/**
* @todo remove once functionality has been tested.
*/
export type EventType = 'dummy';
3 changes: 3 additions & 0 deletions api/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@
"bookmark/*": [
"src/components/bookmark/*"
],
"event/*": [
"src/components/event/*"
],
"lib/*": [
"src/lib/*"
],
Expand Down

0 comments on commit d41ebdc

Please sign in to comment.