diff --git a/.gitignore b/.gitignore index 02551b4..80bc72c 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules dist .env .idea +.dockerignore diff --git a/src/datasources/db/participantAPI.ts b/src/datasources/db/participantAPI.ts index 311ba26..270ec09 100644 --- a/src/datasources/db/participantAPI.ts +++ b/src/datasources/db/participantAPI.ts @@ -130,7 +130,7 @@ export class ParticipantAPI extends DataSource { } async engagementTypes (offset?: number, limit?: number) { - return await DBUtils.getAllEntity(this.connection, Engagement, 'e', offset, limit); + return await DBUtils.getAllEntity(this.connection, EngagementType, 'et', offset, limit); } async engagementTypeByEngagementId (id: number) { @@ -170,6 +170,7 @@ export class ParticipantAPI extends DataSource { * @param participant to be created */ async createParticipant (participant: any) { + genDateRange(participant); let inserts: any; await this.connection.transaction(async (entityManager: EntityManager) => { inserts = await entityManager.getRepository(Participant) @@ -201,8 +202,9 @@ export class ParticipantAPI extends DataSource { delete participant.keepLock; await this.connection.transaction(async (entityManager: EntityManager) => { if (await LockUtils.isLocked(entityManager, Participant, 'p', participant.id, userId)) { - throw new GraphQLError('Participant is locked by another user'); + throw new UserInputError('Attempting to update locked resource'); } + genDateRange(participant); const workshops = participant.workshopIds; delete participant.workshopIds; await ActionLogger.log(entityManager, Participant, 'p', participant, userId); @@ -212,6 +214,17 @@ export class ParticipantAPI extends DataSource { .set({ ...participant }) .where('id = :id', { id: participant.id }) .execute().then(value => { if (value.affected !== 1) { throw new UserInputError('ID not found'); } }); + // check for engagements before or after dateRange + const engagements = await entityManager.getRepository(Engagement) + .createQueryBuilder('e') + .select() + .where('e."participantId" = :pid', { pid: participant.id }) + .andWhere('not :pdr @> e."dateRange"', { pdr: participant.dateRange }) + .getMany(); + if (engagements.length !== 0) { + throw new UserInputError('Engagements with ids: ' + engagements.map((e) => { return `${e.id} ,`; }) + ' are are outside of dataRange'); + } + // add and remove workshop relations workshops && await entityManager.getRepository(Participant) .createQueryBuilder('w') .relation(Participant, 'workshopIds') @@ -241,6 +254,16 @@ export class ParticipantAPI extends DataSource { if (overlapping.length > 0) { throw new UserInputError('Engagements with ids: ' + overlapping.map((e) => { return e.id + ', '; }) + 'are overlapping'); } + // check if participant is active + const participant = await entityManager.getRepository(Participant) + .createQueryBuilder('p') + .select() + .where('p.id = :pid', { pid: engagement.participantId }) + .andWhere('not p."dateRange" @> :edr', { edr: engagement.dateRange }) + .getOne(); + if (participant) { + throw new UserInputError('Participant ist not active in the specified dateRange'); + } inserts = await entityManager.getRepository(Engagement) .createQueryBuilder('engagement') .insert() @@ -280,6 +303,20 @@ export class ParticipantAPI extends DataSource { if (overlapping.length > 0) { throw new UserInputError('Engagements with ids: ' + overlapping.map((e) => { return e.id + ', '; }) + 'are overlapping'); } + // check if participant is active + if (engagement.dateRange && engagement.participantId) { + const participant = await entityManager.getRepository(Participant) + .createQueryBuilder('p') + .select() + .where('p.id = :pid', { pid: engagement.participantId }) + .andWhere('not p."dateRange" @> :edr', { edr: engagement.dateRange }) + .getOne(); + if (participant) { + throw new UserInputError('Participant ist not active in the specified dateRange'); + } + } else if (engagement.dateRange || engagement.dateRange) { + throw new UserInputError('Please specify participantId adn the dateRange'); + } await entityManager.getRepository(Engagement) .createQueryBuilder('engagement') .update() diff --git a/src/model/Participant.ts b/src/model/Participant.ts index dedf9b8..d623143 100644 --- a/src/model/Participant.ts +++ b/src/model/Participant.ts @@ -29,16 +29,9 @@ export class Participant implements Lockable { id: number; @Column({ - type: 'date', - default: () => 'CURRENT_DATE' + type: 'daterange' }) - start: Date; - - @Column({ - type: 'date', - nullable: true - }) - end: Date; + dateRange: Date[]; @OneToOne(type => ContactInformation, contactInformation => contactInformation.participantId, { nullable: false diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index e040362..b55e6a8 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -410,8 +410,7 @@ export default gql` """ type Participant { id: ID! - start: Date! - end: Date + dateRange: DateRange! contactInformation: ContactInformation! usernamefLotte: String usernameSlack: String @@ -436,8 +435,7 @@ export default gql` input ParticipantCreateInput { "if not set, CURRENT_DATE will be used" - start: Date - end: Date + dateRange: DateRangeInput! "must create contactinformation first, if you want to use new" contactInformationId: ID! usernamefLotte: String @@ -452,9 +450,7 @@ export default gql` input ParticipantUpdateInput { id: ID! - "if not set, CURRENT_DATE will be used" - start: Date - end: Date + dateRange: DateRangeInput "must create contactinformation first, if you want to use new" contactInformationId: ID usernamefLotte: String @@ -564,7 +560,7 @@ export default gql` input EngagementCreateInput { engagementTypeId: ID! - dateRange: DateRangeInput + dateRange: DateRangeInput! participantId: ID! cargoBikeId: ID! }