Skip to content

Commit

Permalink
Merge pull request #20 from Serhiy1/dev/serhiy/13-add-event-hash
Browse files Browse the repository at this point in the history
Calculate and add hashes to events in the user response
  • Loading branch information
Serhiy1 authored Apr 12, 2024
2 parents 1da09c4 + 6a32eb0 commit 5818353
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 96 deletions.
33 changes: 33 additions & 0 deletions openapi/schemas/Response/EventDetails.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
type: object
properties:
projectId:
type: string
format: uuid
eventId:
type: string
format: uuid
eventDate:
type: string
format: date
eventName:
type: string
eventType:
type: string
eventCreator:
$ref: './ProjectCollaborator.yaml'
customMetaData:
type: object
additionalProperties:
type: string
attachments:
type: array
items:
$ref: '../Request/AttachmentRequest.yaml'

required:
- eventCreator
- projectId
- eventId
- eventDate
- eventName
- eventType
35 changes: 6 additions & 29 deletions openapi/schemas/Response/EventResponse.yaml
Original file line number Diff line number Diff line change
@@ -1,33 +1,10 @@
type: object
properties:
projectId:
hash:
type: string
format: uuid
eventId:
type: string
format: uuid
eventDate:
type: string
format: date
eventName:
type: string
eventType:
type: string
eventCreator:
$ref: './ProjectCollaborator.yaml'
customMetaData:
type: object
additionalProperties:
type: string
attachments:
type: array
items:
$ref: '../Request/AttachmentRequest.yaml'
description: Hash of the event, containing all the fields of the event + the projectId + eventId and createdDate, in SHA256 format
event:
$ref: './EventDetails.yaml'
required:
- eventCreator
- projectId
- eventId
- eventDate
- eventName
- eventType
- attachments
- hash
- event
27 changes: 23 additions & 4 deletions src/app/models/database/event.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import crypto from "crypto";
import mongoose, { HydratedDocument, model, Schema } from "mongoose";

import { AttachmentRequest, EventRequest, EventResponse } from "../types/projects";
import { AttachmentRequest, EventDetails, EventRequest, EventResponse } from "../types/projects";
import { Project, ProjectDocument } from "./project";
import { Tenancy, TenancyDocument } from "./tenancy";

Expand All @@ -20,10 +21,12 @@ interface IEvent extends IEventArgs {
_id: mongoose.Types.ObjectId;
}


interface IEventMethods {
ToEventResponse: () => Promise<EventResponse>;
IsPartOfProject: (projectId: ProjectDocument) => Promise<boolean>;
IsVisibleToCollaborator: (collaboratorId: mongoose.Types.ObjectId) => boolean;
sha256EventHash: (resp: EventDetails) => string;
}

interface IEventQueryHelpers {}
Expand All @@ -38,7 +41,7 @@ interface IEventModel extends mongoose.Model<IEvent, IEventQueryHelpers, IEventM
) => Promise<EventDocument>;
}

const EventSchema = new Schema<IEvent, IEventModel>({
const EventSchema = new Schema<IEvent, IEventModel, IEventMethods, IEventQueryHelpers>({
_id: { type: Schema.Types.ObjectId, required: true },
projectId: { type: Schema.Types.ObjectId, required: true, ref: "Project" },
eventDate: { type: Date, required: true },
Expand Down Expand Up @@ -94,6 +97,13 @@ EventSchema.static(
}
);

EventSchema.method("sha256EventHash", function sha256EventHash(obj: EventDetails): string {
// Create a hash from the object
const json = JSON.stringify(obj);
const hash = crypto.createHash("sha256").update(json).digest("hex");
return hash;
})

EventSchema.method("ToEventResponse", async function ToEventResponse(): Promise<EventResponse> {
const tenancy = await Tenancy.findById(this.eventCreator);
let tenancyInfo: { friendlyName: string; tenantID: string };
Expand All @@ -103,7 +113,7 @@ EventSchema.method("ToEventResponse", async function ToEventResponse(): Promise<
tenancyInfo = tenancy.toProjectCollaboratorResponse();
}

const obj: EventResponse = {
const obj: EventDetails = {
eventId: this._id.toString(),
projectId: this.projectId.toString(),
eventDate: this.eventDate.toString(),
Expand All @@ -113,7 +123,16 @@ EventSchema.method("ToEventResponse", async function ToEventResponse(): Promise<
eventCreator: tenancyInfo,
attachments: this.attachments,
};
return obj;

const hash = this.sha256EventHash(obj)

// create a new object with the hash
const response: EventResponse = {
hash: hash,
event : obj
};

return response;
});

EventSchema.method("IsPartOfProject", async function IsPartOfProject(project: ProjectDocument): Promise<boolean> {
Expand Down
9 changes: 7 additions & 2 deletions src/app/models/openapi/PublicProjects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ export interface components {
hashValue?: string;
};
};
EventResponse: {
EventDetails: {
/** Format: uuid */
projectId: string;
/** Format: uuid */
Expand All @@ -232,7 +232,12 @@ export interface components {
customMetaData?: {
[key: string]: string | undefined;
};
attachments: components["schemas"]["AttachmentRequest"][];
attachments?: components["schemas"]["AttachmentRequest"][];
};
EventResponse: {
/** @description Hash of the event, containing all the fields of the event + the projectId + eventId and createdDate, in SHA256 format */
hash: string;
event: components["schemas"]["EventDetails"];
};
ProjectDiffResponse: {
projectName?: {
Expand Down
9 changes: 7 additions & 2 deletions src/app/models/openapi/projects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,7 +394,7 @@ export interface components {
hashValue?: string;
};
};
EventResponse: {
EventDetails: {
/** Format: uuid */
projectId: string;
/** Format: uuid */
Expand All @@ -407,7 +407,12 @@ export interface components {
customMetaData?: {
[key: string]: string | undefined;
};
attachments: components["schemas"]["AttachmentRequest"][];
attachments?: components["schemas"]["AttachmentRequest"][];
};
EventResponse: {
/** @description Hash of the event, containing all the fields of the event + the projectId + eventId and createdDate, in SHA256 format */
hash: string;
event: components["schemas"]["EventDetails"];
};
ProjectDiffResponse: {
projectName?: {
Expand Down
1 change: 1 addition & 0 deletions src/app/models/types/projects.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export type ProjectRequest = components["schemas"]["ProjectRequest"];
export type ProjectDiffResponse = components["schemas"]["ProjectDiffResponse"];
export type AttachmentRequest = components["schemas"]["AttachmentRequest"];
export type EventResponse = components["schemas"]["EventResponse"];
export type EventDetails = components["schemas"]["EventDetails"];
export type ProjectDiffRequest = components["schemas"]["ProjectDiffRequest"];
export type EventRequest = components["schemas"]["EventRequest"];
export type ProjectCollaborator = components["schemas"]["ProjectCollaborator"];
Expand Down
54 changes: 44 additions & 10 deletions src/test/database/event.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { expect, test } from "@jest/globals";
import crypto from "crypto";

import { Event, EventDocument } from "../../app/models/database/event";
import { Project } from "../../app/models/database/project";
Expand Down Expand Up @@ -28,24 +29,57 @@ test("test NewEventFromRequest Static Function", async () => {
});

test("ToEventResponse Method", async () => {
const eventdata = CreateRandomEventRequest();
const eventData = CreateRandomEventRequest();
const tenancy = await CreateRandomTenancy();
const project = await Project.NewProjectFromRequest(CreateRandomProjectRequest(), tenancy);

const event = await Event.NewEventFromRequest(eventdata, project, tenancy);
await event.save();
const event = await Event.NewEventFromRequest(eventData, project, tenancy);

// get the event from the database via id
const eventFromDB = await Event.findById(event._id);

// asseert that the result is not null
// assert that the result is not null
expect(eventFromDB).not.toBeNull();

// assert that the event has the correct properties
const eventResponse = await (eventFromDB as EventDocument).ToEventResponse();
expect(eventResponse).toHaveProperty("eventDate");
expect(eventResponse).toHaveProperty("eventName", eventdata.eventName);
expect(eventResponse).toHaveProperty("eventType", eventdata.eventType);
expect(eventResponse).toHaveProperty("customMetaData");
expect(eventResponse).toHaveProperty("projectId", project.ProjectId.toString());
expect(eventResponse).toHaveProperty("event");
expect(eventResponse.event).toHaveProperty("eventDate");
expect(eventResponse.event).toHaveProperty("eventName", eventData.eventName);
expect(eventResponse.event).toHaveProperty("eventType", eventData.eventType);
expect(eventResponse.event).toHaveProperty("customMetaData");
expect(eventResponse.event).toHaveProperty("projectId", project.ProjectId.toString());

// assert that the hash is created
expect(eventResponse).toHaveProperty("hash");
});


test("Verify that the sha256EventHash method works", async () => {

const eventData = CreateRandomEventRequest();
const tenancy = await CreateRandomTenancy();
const project = await Project.NewProjectFromRequest(CreateRandomProjectRequest(), tenancy);
const event = await Event.NewEventFromRequest(eventData, project, tenancy);

// get the event from the database via id
const eventFromDB = await Event.findById(event._id);
// assert that the result is not null
expect(eventFromDB).not.toBeNull();

// cast the event to an EventDocument
const eventDoc = eventFromDB as EventDocument;

// Get the event hash from the event
const eventResponse = await eventDoc.ToEventResponse();
const eventHash = eventResponse.hash;

// check if the hash is a string
expect(eventHash).toEqual(expect.any(String));

// locally calculate the hash of the event and compare it to the hash
const eventJson = JSON.stringify(eventResponse.event);
const LocalHash = crypto.createHash("sha256").update(eventJson).digest("hex");
expect(eventHash).toBe(LocalHash);


})
11 changes: 5 additions & 6 deletions src/test/database/project.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ test("test ListAllEvents Method", async () => {
// Create events and add them to the project
for (const event of RandomEvents) {
const newEvent = await Event.NewEventFromRequest(event, project, tenancy);
await newEvent.save();
project.events.push(newEvent._id);
}
await project.save();
Expand All @@ -58,11 +57,11 @@ test("test ListAllEvents Method", async () => {

// check that the events have the correct properties
for (const event of eventsFromDB) {
expect(event).toHaveProperty("eventId");
expect(event).toHaveProperty("eventDate");
expect(event).toHaveProperty("eventName");
expect(event).toHaveProperty("eventType");
expect(event).toHaveProperty("customMetaData");
expect(event.event).toHaveProperty("eventId");
expect(event.event).toHaveProperty("eventDate");
expect(event.event).toHaveProperty("eventName");
expect(event.event).toHaveProperty("eventType");
expect(event.event).toHaveProperty("customMetaData");
}
});

Expand Down
Loading

0 comments on commit 5818353

Please sign in to comment.