From fe416200fb6f33e8a3fffb472cec4a2c77bfb68c Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 17 Oct 2023 15:15:28 +0200 Subject: [PATCH 1/5] migration to fix wrong event date times --- .../20231017141022-fix-event-dates.ts | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 backend/src/db/migrations/20231017141022-fix-event-dates.ts diff --git a/backend/src/db/migrations/20231017141022-fix-event-dates.ts b/backend/src/db/migrations/20231017141022-fix-event-dates.ts new file mode 100644 index 000000000..d3a28afde --- /dev/null +++ b/backend/src/db/migrations/20231017141022-fix-event-dates.ts @@ -0,0 +1,68 @@ +import { getDriver } from '../../db/neo4j' + +export const description = ` +Transform event start and end date of format 'YYYY-MM-DD HH:MM:SS' in CEST +to ISOString in UTC. +` + +export async function up(next) { + const driver = getDriver() + const session = driver.session() + const transaction = session.beginTransaction() + + try { + const events = await transaction.run(` + MATCH (event:Event) + WHERE NOT event.eventStart CONTAINS 'T' + RETURN event.id, event.eventStart, event.eventEnd + `) + for (const event of events.records) { + let [id, eventStart, eventEnd] = event + let date = new Date(eventStart) + date.setHours(date.getHours() - 2) + eventStart = date.toISOString() + if (eventEnd) { + date = new Date(eventEnd) + date.setHours(date.getHours() - 2) + eventEnd = date.toISOString() + } + await transaction.run(` + MATCH (e:Event { id: '${id}' }) + SET e.eventStart = '${eventStart}' + SET (CASE WHEN e.eventEnd THEN e END).eventEnd = '${eventEnd}' + RETURN e + `) + } + await transaction.commit() + next() + } catch (error) { + // eslint-disable-next-line no-console + console.log(error) + await transaction.rollback() + // eslint-disable-next-line no-console + console.log('rolled back') + throw new Error(error) + } finally { + session.close() + } +} + +export async function down(next) { + const driver = getDriver() + const session = driver.session() + const transaction = session.beginTransaction() + + try { + // No sense in running this down + next() + } catch (error) { + // eslint-disable-next-line no-console + console.log(error) + await transaction.rollback() + // eslint-disable-next-line no-console + console.log('rolled back') + throw new Error(error) + } finally { + session.close() + } +} From fe3e5dc483ccfe478dfb5ffb5049451f28182e93 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Tue, 17 Oct 2023 15:35:38 +0200 Subject: [PATCH 2/5] fix cypher statement --- backend/src/db/migrations/20231017141022-fix-event-dates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/db/migrations/20231017141022-fix-event-dates.ts b/backend/src/db/migrations/20231017141022-fix-event-dates.ts index d3a28afde..b7e23479c 100644 --- a/backend/src/db/migrations/20231017141022-fix-event-dates.ts +++ b/backend/src/db/migrations/20231017141022-fix-event-dates.ts @@ -29,7 +29,7 @@ export async function up(next) { await transaction.run(` MATCH (e:Event { id: '${id}' }) SET e.eventStart = '${eventStart}' - SET (CASE WHEN e.eventEnd THEN e END).eventEnd = '${eventEnd}' + SET (CASE WHEN exists(e.eventEnd) THEN e END).eventEnd = '${eventEnd}' RETURN e `) } From 44d6f31574fc48e18f09d7febed55ad91b71cfd7 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 26 Oct 2023 16:40:41 +0200 Subject: [PATCH 3/5] timezone offset in migration 1 hour, check event date string for ISO format --- backend/src/db/migrations/20231017141022-fix-event-dates.ts | 4 ++-- backend/src/schema/resolvers/helpers/events.ts | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/src/db/migrations/20231017141022-fix-event-dates.ts b/backend/src/db/migrations/20231017141022-fix-event-dates.ts index b7e23479c..3c4302f13 100644 --- a/backend/src/db/migrations/20231017141022-fix-event-dates.ts +++ b/backend/src/db/migrations/20231017141022-fix-event-dates.ts @@ -19,11 +19,11 @@ export async function up(next) { for (const event of events.records) { let [id, eventStart, eventEnd] = event let date = new Date(eventStart) - date.setHours(date.getHours() - 2) + date.setHours(date.getHours() - 1) eventStart = date.toISOString() if (eventEnd) { date = new Date(eventEnd) - date.setHours(date.getHours() - 2) + date.setHours(date.getHours() - 1) eventEnd = date.toISOString() } await transaction.run(` diff --git a/backend/src/schema/resolvers/helpers/events.ts b/backend/src/schema/resolvers/helpers/events.ts index 835088d8c..d4fc1fb11 100644 --- a/backend/src/schema/resolvers/helpers/events.ts +++ b/backend/src/schema/resolvers/helpers/events.ts @@ -34,6 +34,8 @@ const validateEventDate = (dateString) => { const date = new Date(dateString) if (date.toString() === 'Invalid Date') throw new UserInputError('Event start date must be a valid date!') + if (date.toISOString() !== dateString) + throw new UserInputError('Event start date must be in ISO format!') const now = new Date() if (date.getTime() < now.getTime()) { throw new UserInputError('Event start date must be in the future!') @@ -44,6 +46,8 @@ const validateEventEnd = (start, end) => { const endDate = new Date(end) if (endDate.toString() === 'Invalid Date') throw new UserInputError('Event end date must be a valid date!') + if (endDate.toISOString() !== end) + throw new UserInputError('Event end date must be in ISO format!') const startDate = new Date(start) if (endDate < startDate) throw new UserInputError('Event end date must be a after event start date!') From fdf38af4e969fd6315647ab21dbe845bbe4896a3 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 26 Oct 2023 16:49:15 +0200 Subject: [PATCH 4/5] unit tests for ISO format of event dates --- backend/src/schema/resolvers/posts.spec.ts | 51 ++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/backend/src/schema/resolvers/posts.spec.ts b/backend/src/schema/resolvers/posts.spec.ts index 7a549449f..b816e25aa 100644 --- a/backend/src/schema/resolvers/posts.spec.ts +++ b/backend/src/schema/resolvers/posts.spec.ts @@ -374,6 +374,31 @@ describe('CreatePost', () => { }) }) + describe('with event start in no ISO format', () => { + it('throws an error', async () => { + const now = new Date() + const eventStart = new Date(now.getFullYear(), now.getMonth() - 1).toISOString() + await expect( + mutate({ + mutation: createPostMutation(), + variables: { + ...variables, + postType: 'Event', + eventInput: { + eventStart: eventStart.split('T')[0], + }, + }, + }), + ).resolves.toMatchObject({ + errors: [ + { + message: 'Event start date must be in ISO format!', + }, + ], + }) + }) + }) + describe('with event start date in the past', () => { it('throws an error', async () => { const now = new Date() @@ -423,6 +448,32 @@ describe('CreatePost', () => { }) }) + describe('with valid start date and not ISO formated end date', () => { + it('throws an error', async () => { + const now = new Date() + const eventEnd = new Date(now.getFullYear(), now.getMonth() + 2).toISOString() + await expect( + mutate({ + mutation: createPostMutation(), + variables: { + ...variables, + postType: 'Event', + eventInput: { + eventStart: new Date(now.getFullYear(), now.getMonth() + 1).toISOString(), + eventEnd: eventEnd.split('T')[0], + }, + }, + }), + ).resolves.toMatchObject({ + errors: [ + { + message: 'Event end date must be in ISO format!', + }, + ], + }) + }) + }) + describe('with valid start date and end date before start date', () => { it('throws an error', async () => { const now = new Date() From ca737f4bca28b8341081f87bd592ef7631b760b5 Mon Sep 17 00:00:00 2001 From: Moriz Wahl Date: Thu, 2 Nov 2023 10:52:10 +0100 Subject: [PATCH 5/5] do not test migrations --- backend/jest.config.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/jest.config.js b/backend/jest.config.js index d1cc7bd3f..a4a0ce1df 100644 --- a/backend/jest.config.js +++ b/backend/jest.config.js @@ -7,7 +7,8 @@ module.exports = { '!**/node_modules/**', '!**/test/**', '!**/build/**', - '!**/src/**/?(*.)+(spec|test).ts?(x)' + '!**/src/**/?(*.)+(spec|test).ts?(x)', + '!**/src/db/migrations/**' ], coverageThreshold: { global: {