Skip to content

Commit

Permalink
Merge pull request #1079 from dm3-org/DSFE3-Halt-delivery
Browse files Browse the repository at this point in the history
Dsfe3 halt delivery
  • Loading branch information
AlexNi245 authored Jul 15, 2024
2 parents 2c59228 + 802882f commit 344165d
Show file tree
Hide file tree
Showing 39 changed files with 1,080 additions and 259 deletions.
13 changes: 13 additions & 0 deletions packages/backend/migrations/20240704093840_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- CreateTable
CREATE TABLE "HaltedMessage" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"encryptedEnvelopContainer" TEXT NOT NULL,
"encryptedContactName" TEXT NOT NULL,
"ownerId" TEXT NOT NULL,

CONSTRAINT "HaltedMessage_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "HaltedMessage" ADD CONSTRAINT "HaltedMessage_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "Account"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
8 changes: 8 additions & 0 deletions packages/backend/migrations/20240704094732_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Warnings:
- You are about to drop the column `encryptedContactName` on the `HaltedMessage` table. All the data in the column will be lost.
*/
-- AlterTable
ALTER TABLE "HaltedMessage" DROP COLUMN "encryptedContactName";
14 changes: 14 additions & 0 deletions packages/backend/migrations/20240704141910_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
Warnings:
- You are about to drop the `HaltedMessage` table. If the table is not empty, all the data it contains will be lost.
*/
-- DropForeignKey
ALTER TABLE "HaltedMessage" DROP CONSTRAINT "HaltedMessage_ownerId_fkey";

-- AlterTable
ALTER TABLE "EncryptedMessage" ADD COLUMN "isHalted" BOOLEAN NOT NULL DEFAULT false;

-- DropTable
DROP TABLE "HaltedMessage";
3 changes: 3 additions & 0 deletions packages/backend/schema.prisma
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
datasource db {
//Use this URL for local development
//url = "postgresql://prisma:prisma@localhost:5433/tests"
url = env("DATABASE_URL")
provider = "postgresql"
}
Expand All @@ -16,6 +18,7 @@ model EncryptedMessage {
conversation Conversation @relation(fields: [conversationId], references: [id])
ownerId String
owner Account @relation(fields: [ownerId], references: [id])
isHalted Boolean @default(false)
}

model Conversation {
Expand Down
2 changes: 2 additions & 0 deletions packages/backend/schemas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/AddMessageB
yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/AddMessageRequest.ts --type _AddMessageRequest -o ./src/schema/storage/AddMessageRequest.schema.json --no-type-check \

yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/PaginatedRequest.ts --type _PaginatedRequest -o ./src/schema/storage/PaginatedRequest.schema.json --no-type-check \

yarn ts-json-schema-generator -f tsconfig.json --path schema/storage/AddHaltedMessageRequest.ts --type _AddHaltedMessageRequest -o ./src/schema/storage/AddHaltedMessageRequest.schema.json --no-type-check \
12 changes: 11 additions & 1 deletion packages/backend/src/persistence/getDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import { createClient } from 'redis';
import Pending from './pending';
import Session from './session';
import Storage from './storage';
import { MessageRecord } from './storage/postgres/dto/MessageRecord';
import { ConversationRecord } from './storage/postgres/dto/ConversationRecord';
import { MessageRecord } from './storage/postgres/dto/MessageRecord';

export enum RedisPrefix {
Conversation = 'conversation:',
Expand Down Expand Up @@ -88,6 +88,10 @@ export async function getDatabase(
getNumberOfConverations: Storage.getNumberOfConversations(prisma),
//Storage Toggle Hide Conversation
toggleHideConversation: Storage.toggleHideConversation(prisma),
//Storage Get Halted Messages
getHaltedMessages: Storage.getHaltedMessages(prisma),
//Storage Delete Halted Message
clearHaltedMessage: Storage.clearHaltedMessage(prisma),
//Get the user db migration status
getUserDbMigrationStatus: Storage.getUserDbMigrationStatus(redis),
//Set the user db migration status to true
Expand Down Expand Up @@ -145,6 +149,12 @@ export interface IDatabase extends ISessionDatabase {
encryptedContactName: string,
isHidden: boolean,
) => Promise<boolean>;
getHaltedMessages: (ensName: string) => Promise<MessageRecord[]>;
clearHaltedMessage: (
ensName: string,
aliasName: string,
messageId: string,
) => Promise<boolean>;
getUserDbMigrationStatus: (ensName: string) => Promise<boolean>;
setUserDbMigrated: (ensName: string) => Promise<void>;
}
Expand Down
4 changes: 4 additions & 0 deletions packages/backend/src/persistence/storage/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { toggleHideConversation } from './postgres/toggleHideConversation';
import { MessageRecord } from './postgres/dto/MessageRecord';
import { getUserDbMigrationStatus } from './getUserDbMigrationStatus';
import { setUserDbMigrated } from './setUserDbMigrated';
import { getHaltedMessages } from './postgres/haltedMessage/getHaltedMessages';
import { clearHaltedMessage } from './postgres/haltedMessage/clearHaltedMessage';

export default {
getUserStorageOld,
Expand All @@ -23,6 +25,8 @@ export default {
getNumberOfConversations,
getNumberOfMessages,
toggleHideConversation,
getHaltedMessages,
clearHaltedMessage,
getUserDbMigrationStatus,
setUserDbMigrated,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ export const addMessageBatch =
);
//store each message in the db
const createMessagePromises = messageBatch.map(
({ messageId, createdAt, encryptedEnvelopContainer }) => {
({
messageId,
createdAt,
encryptedEnvelopContainer,
isHalted,
}) => {
//The database stores the date as an ISO 8601 string. Hence we need to convert it to a Date object
const createAtDate = new Date(createdAt);
return db.encryptedMessage.create({
Expand All @@ -32,6 +37,7 @@ export const addMessageBatch =
conversationId: conversation.id,
encryptedContactName,
encryptedEnvelopContainer,
isHalted,
},
});
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ export type MessageRecord = {
messageId: string;
//The actual encrypted message
encryptedEnvelopContainer: string;
//The message is halted if the message hasnot been delivered yet
isHalted: boolean;
};
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ export const editMessageBatch =
encryptedContactName: string,
editMessageBatchPayload: MessageRecord[],
) => {
console.log('editMessageBatchPayload', editMessageBatchPayload);
const account = await getOrCreateAccount(db, ensName);

await Promise.all(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { PrismaClient } from '@prisma/client';
import { clearHaltedMessage } from './clearHaltedMessage';
import { getOrCreateAccount } from '../utils/getOrCreateAccount';
import { addMessageBatch } from '../addMessageBatch';

// Mock the PrismaClient
const mockDb = new PrismaClient();

describe('deleteHaltedMessage', () => {
let prismaClient: PrismaClient;

beforeEach(async () => {
prismaClient = new PrismaClient();
});

afterEach(async () => {
await prismaClient.encryptedMessage.deleteMany({});
await prismaClient.conversation.deleteMany({});
await prismaClient.account.deleteMany({});

prismaClient.$disconnect();
});
it('should return false if account does not exist', async () => {
const result = await clearHaltedMessage(mockDb)(
'bob.eth',
'bob.eth',
'messageId',
);
expect(result).toBe(false);
});

it('should return false if message does not exist', async () => {
const result = await clearHaltedMessage(mockDb)(
'existing',
'existing',
'messageId',
);
expect(result).toBe(false);
});

it('should return true if message is successfully deleted', async () => {
const account = await getOrCreateAccount(prismaClient, 'bob.eth');
//create message first
const messageRecord1 = {
messageId: 'messageId1',
createdAt: 123,
encryptedEnvelopContainer: 'encryptedEnvelopContainer',
isHalted: true,
};
const messageRecord2 = {
messageId: 'messageId2',
createdAt: 456,
encryptedEnvelopContainer: 'encryptedEnvelopContainer',
isHalted: false,
};

await addMessageBatch(prismaClient)('bob.eth', 'alice.eth', [
messageRecord1,
messageRecord2,
]);

const result = await clearHaltedMessage(mockDb)(
'bob.eth',
'bob.eth',
'messageId1',
);
expect(result).toBe(true);
});
it('should rename to aliasName', async () => {
const account = await getOrCreateAccount(prismaClient, 'bob.eth');
//create message first
const messageRecord1 = {
messageId: 'messageId1',
createdAt: 123,
encryptedEnvelopContainer: 'encryptedEnvelopContainer',
isHalted: true,
};
const messageRecord2 = {
messageId: 'messageId2',
createdAt: 456,
encryptedEnvelopContainer: 'encryptedEnvelopContainer',
isHalted: false,
};

await addMessageBatch(prismaClient)('bob.eth', 'alice.eth', [
messageRecord1,
messageRecord2,
]);

const beforeClearHaltedMessage =
await prismaClient.encryptedMessage.findFirst({
where: {
id: 'messageId1',
},
});

expect(beforeClearHaltedMessage?.encryptedContactName).toBe(
'alice.eth',
);

const result = await clearHaltedMessage(mockDb)(
'bob.eth',
'0x123.addr.dm3.eth',
'messageId1',
);

const message = await prismaClient.encryptedMessage.findFirst({
where: {
id: 'messageId1',
},
});

expect(message?.encryptedContactName).toBe('0x123.addr.dm3.eth');
expect(result).toBe(true);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { PrismaClient } from '@prisma/client';

export const clearHaltedMessage =
(db: PrismaClient) =>
/**
*
* @param ensName the ensName the messages have been stored originally i.E alice.eth
* @param aliasName the aliasNamespace the cleint uses after resolving the ensName i.E Alice. ie addr.user.dm3.eth
* @param messageId the messageId
* @returns
*/
async (ensName: string, aliasName: string, messageId: string) => {
//Find the account first we want to get the messages for
const account = await db.account.findFirst({
where: {
id: ensName,
},
});
//If the contact does not exist, there is no message that can be deleted
if (!account) {
console.log('cleatHaltedMessages: account not found');
return false;
}

const message = await db.encryptedMessage.findFirst({
where: {
id: messageId,
ownerId: account.id,
},
});

if (!message) {
console.log(`cleatHaltedMessages: message ${messageId} not found`);
return false;
}

try {
await db.encryptedMessage.update({
where: {
id: messageId,
},
data: {
//Message is no longer halted
isHalted: false,
//Use alias name
encryptedContactName: aliasName,
},
});

await db.conversation.update({
where: {
id: message.conversationId,
},
data: {
encryptedContactName: aliasName,
},
});
return true;
} catch (e) {
console.error('clear halted error', e);
return false;
}
};
Loading

0 comments on commit 344165d

Please sign in to comment.