From 159e91d5dbe5d110fd051d29fb1330043697e0e7 Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Wed, 23 Sep 2020 18:18:38 +0200 Subject: [PATCH] lock and unlock for cargoBike --- src/datasources/db/cargobikeAPI.ts | 49 ++++++++++++++++++++++++++++-- src/model/Equipment.ts | 15 +++++++-- src/resolvers/cargobikeResolver.ts | 13 ++++++-- src/schema/type-defs.ts | 2 ++ 4 files changed, 71 insertions(+), 8 deletions(-) diff --git a/src/datasources/db/cargobikeAPI.ts b/src/datasources/db/cargobikeAPI.ts index 3b60285..45400fa 100644 --- a/src/datasources/db/cargobikeAPI.ts +++ b/src/datasources/db/cargobikeAPI.ts @@ -51,8 +51,12 @@ export class CargoBikeAPI extends DataSource { return this.lockEntity(CargoBike, 'cargobike', id, req, dataSources); } + async unlockCargoBike (id: number, req: any, dataSources: any) { + return this.unlockEntity(CargoBike, 'cargobike', id, req, dataSources); + } + /** - * lock any entity that implemts Lockable + * locks any entity that implemts Lockable */ async lockEntity (target: ObjectType, alias: string, id: number, req: any, dataSources: any) { const token = req.headers.authorization?.replace('Bearer ', ''); @@ -87,6 +91,42 @@ export class CargoBikeAPI extends DataSource { } } + async unlockEntity (target: ObjectType, alias: string, id: number, req: any, dataSources: any) { + const token = req.headers.authorization?.replace('Bearer ', ''); + const userId = await dataSources.userAPI.getUserId(token); + const lock = await this.connection.getRepository(target) + .createQueryBuilder(alias) + .select([ + alias + '.lockedUntil', + alias + '.lockedBy' + ]) + .where('id = :id', { + id: id + }) + .andWhere(alias + '.lockedUntil > CURRENT_TIMESTAMP') + .getOne(); + if (!lock?.lockedUntil) { + // no lock + return true; + // eslint-disable-next-line eqeqeq + } else if (lock?.lockedBy == userId) { + // user can unlock + await this.connection.getRepository(target) + .createQueryBuilder(alias) + .update() + .set({ + lockedUntil: null, + lockedBy: null + }) + .where('id = :id', { id: id }) + .execute(); + return true; + } else { + // enity is locked by other user + return false; + } + } + /** * Updates CargoBike and return updated cargoBike * @param param0 cargoBike to be updated @@ -215,7 +255,7 @@ export class CargoBikeAPI extends DataSource { } async lockEquipment (id: number, req: any, dataSources: any) { - + return this.lockEntity(Equipment, 'equipment', id, req, dataSources); } /** @@ -223,7 +263,10 @@ export class CargoBikeAPI extends DataSource { * Will return updated Equipment joined with CargoBike only if cargoBike is was set in param0 * @param param0 struct with equipment properites */ - async updateEquipment ({ equipment }: { equipment: any }) { + async updateEquipment (equipment: any, req: any, dataSources: any) { + if (!await this.lockEntity(Equipment, 'equipment', equipment.id, req, dataSources)) { + return new GraphQLError('Equipment locked by other user'); + } const cargoBikeId = equipment.cargoBikeId; delete equipment.cargoBikeId; await this.connection.getRepository(Equipment) diff --git a/src/model/Equipment.ts b/src/model/Equipment.ts index ccc3197..fe675dc 100644 --- a/src/model/Equipment.ts +++ b/src/model/Equipment.ts @@ -1,8 +1,8 @@ import { Entity, PrimaryGeneratedColumn, Column, JoinColumn, ManyToOne } from 'typeorm'; -import { CargoBike } from './CargoBike'; +import { CargoBike, Lockable } from './CargoBike'; @Entity() -export class Equipment { +export class Equipment implements Lockable { setValues ({ id, serialNo, title, description, cargoBike }: { id: number, serialNo: string, @@ -39,5 +39,16 @@ export class Equipment { }) cargoBike: CargoBike; + @Column({ + type: 'timestamp', + nullable: true + }) + lockedUntil: Date; + + @Column({ + nullable: true + }) + lockedBy: number; + cargoBikeId: number; } diff --git a/src/resolvers/cargobikeResolver.ts b/src/resolvers/cargobikeResolver.ts index 3f090d0..731567f 100644 --- a/src/resolvers/cargobikeResolver.ts +++ b/src/resolvers/cargobikeResolver.ts @@ -73,6 +73,13 @@ export default { return new GraphQLError('Insufficient Permissions'); } }, + unlockCargoBikeById: (_: any, { id }: { id: number }, { dataSources, req }:{dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.cargoBikeAPI.unlockCargoBike(id, req, dataSources); + } else { + return new GraphQLError('Insufficient Permissions'); + } + }, updateCargoBike: (_: any, { cargoBike }: { cargoBike: any }, { dataSources, req }:{dataSources: any, req: any }) => { if (req.permissions.includes(Permission.WriteBike)) { return dataSources.cargoBikeAPI.updateCargoBike(cargoBike, req, dataSources); @@ -94,16 +101,16 @@ export default { return new GraphQLError('Insufficient Permissions'); } }, - lockEquipmentById: (_: any, { equipment }: { equipment: any }, { dataSources, req }: { dataSources: any, req: any }) => { + lockEquipmentById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => { if (req.permissions.includes(Permission.WriteBike)) { - return dataSources.cargoBikeAPI.lockEquipment(equipment.id, req, dataSources); + return dataSources.cargoBikeAPI.lockEquipment(id, req, dataSources); } else { return new GraphQLError('Insufficient Permissions'); } }, updateEquipment: (_: any, { equipment }: { equipment: any }, { dataSources, req }: { dataSources: any, req: any }) => { if (req.permissions.includes(Permission.WriteBike)) { - return dataSources.cargoBikeAPI.updateEquipment({ equipment }); + return dataSources.cargoBikeAPI.updateEquipment(equipment, req, dataSources); } else { return new GraphQLError('Insufficient Permissions'); } diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index e39957a..62f3a47 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -712,6 +712,8 @@ type Mutation { createCargoBike(cargoBike: CargoBikeCreateInput!): CargoBike! "lock cargoBike returns true if bike is not locked or if it doesnt exist" lockCargoBikeById(id: ID!): Boolean! + "unlock cargoBike" + unlockCargoBikeById(id: ID!): Boolean! "updates cargoBike of given ID with supplied fields and returns updated cargoBike" updateCargoBike(cargoBike: CargoBikeUpdateInput!): CargoBike! "creates new peace of unique Equipment"