generic methods to lock and unlock Entities

pull/14/head
leonnicolas 4 years ago
parent 614f9a652c
commit 14b9d3445a
No known key found for this signature in database
GPG Key ID: 088D0743E2B65C07

@ -7,6 +7,7 @@ import { Equipment } from '../../model/Equipment';
import { Engagement } from '../../model/Engagement'; import { Engagement } from '../../model/Engagement';
import { Provider } from '../../model/Provider'; import { Provider } from '../../model/Provider';
import { TimeFrame } from '../../model/TimeFrame'; import { TimeFrame } from '../../model/TimeFrame';
import { LockUtils } from './utils';
/** /**
* extended datasource to feed resolvers with data about cargoBikes * extended datasource to feed resolvers with data about cargoBikes
@ -66,7 +67,7 @@ export class CargoBikeAPI extends DataSource {
} }
async lockCargoBike (id: number, req: any, dataSources: any) { async lockCargoBike (id: number, req: any, dataSources: any) {
if (await this.lockEntity(CargoBike, 'cargobike', id, req, dataSources)) { if (await LockUtils.lockEntity(this.connection, CargoBike, 'cargobike', id, req, dataSources)) {
return this.findCargoBikeById(id); return this.findCargoBikeById(id);
} else { } else {
return new GraphQLError('CargoBike is locked by other user'); return new GraphQLError('CargoBike is locked by other user');
@ -77,103 +78,16 @@ export class CargoBikeAPI extends DataSource {
return this.unlockEntity(CargoBike, 'cargobike', id, req, dataSources); return this.unlockEntity(CargoBike, 'cargobike', id, req, dataSources);
} }
/**
* locks any entity that implemts Lockable
*/
async lockEntity (target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) { async lockEntity (target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
const token = req.headers.authorization?.replace('Bearer ', ''); return LockUtils.lockEntity(this.connection, target, alias, id, req, dataSources);
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();
// eslint-disable-next-line eqeqeq
if (!lock?.lockedUntil || lock?.lockedBy == userId) {
// no lock -> set lock
await this.connection.getRepository(target)
.createQueryBuilder(alias)
.update()
.set({
lockedUntil: () => 'CURRENT_TIMESTAMP + INTERVAL \'10 MINUTE\'',
lockedBy: userId
})
.where('id = :id', { id: id })
.execute();
return true;
} else {
// lock was set
return false;
}
} }
async unlockEntity (target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) { async unlockEntity (target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
const token = req.headers.authorization?.replace('Bearer ', ''); return LockUtils.unlockEntity(this.connection, target, alias, id, req, dataSources);
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;
}
} }
async isLocked (id: number, req: any, dataSources: any) { async isLocked (id: number, req: any, dataSources: any) {
const token = req.headers.authorization?.replace('Bearer ', ''); return LockUtils.isLocked(this.connection, CargoBike, 'cargobike', id, req, dataSources);
const userId = await dataSources.userAPI.getUserId(token);
const lock = await this.connection.getRepository(CargoBike)
.createQueryBuilder('cargobike')
.select([
'cargobike' + '.lockedUntil',
'cargobike' + '.lockedBy'
])
.where('id = :id', {
id: id
})
.andWhere('cargobike' + '.lockedUntil > CURRENT_TIMESTAMP')
.getOne();
if (!lock?.lockedUntil) {
// no lock
return false;
// eslint-disable-next-line eqeqeq
} else if (lock?.lockedBy == userId) {
// user has locked
return false;
} else {
// enity is locked by other user
return true;
}
} }
/** /**

@ -209,4 +209,56 @@ export class LendingStationAPI extends DataSource {
inserts.generatedMaps[0].id = inserts.identifiers[0].id; inserts.generatedMaps[0].id = inserts.identifiers[0].id;
return inserts.generatedMaps[0]; return inserts.generatedMaps[0];
} }
/* async updateTimeFrame (timeFrame: any) {
try {
await this.connection.transaction(async (entityManager: EntityManager) => {
if (timeFrame.to === undefined) {
timeFrame.to = '';
}
timeFrame.dateRange = '[' + timeFrame.from + ',' + timeFrame.to + ')';
// checking for overlapping time frames
const overlapping = await entityManager.getRepository(TimeFrame)
.createQueryBuilder('timeframe')
.update()
values([])
.select([
'timeframe.id'
])
.where('timeframe."cargoBikeId" = :id', { id: timeFrame.cargoBikeId })
.andWhere('timeframe."dateRange" && :tr', { tr: timeFrame.dateRange })
.getMany();
console.log(overlapping);
if (overlapping.length !== 0) {
throw new UserInputError('TimeFrames with ids: ' + overlapping.map((e) => { return e.id + ', '; }) + 'are overlapping');
}
inserts = await entityManager.getRepository(TimeFrame)
.createQueryBuilder('timeframe')
.insert()
.returning('*')
.values([timeFrame])
.execute();
await entityManager.getRepository(TimeFrame)
.createQueryBuilder()
.relation(TimeFrame, 'cargoBike')
.of(inserts.identifiers[0].id)
.set(timeFrame.cargoBikeId);
await entityManager.getRepository(TimeFrame)
.createQueryBuilder()
.relation(TimeFrame, 'lendingStation')
.of(inserts.identifiers[0].id)
.set(timeFrame.lendingStationId);
});
} catch (e) {
console.log(e);
if (e instanceof UserInputError) {
return e;
} else if (e instanceof QueryFailedError) {
return e;
}
return new ApolloError('Transaction could not be completed');
}
inserts.generatedMaps[0].id = inserts.identifiers[0].id;
return inserts.generatedMaps[0];
}*/
} }

@ -0,0 +1,101 @@
import { Connection, ObjectType } from 'typeorm';
import { CargoBike, Lockable } from '../../model/CargoBike';
export class LockUtils {
static getToken (req: any) : string {
return req.headers.authorization?.replace('Bearer ', '');
}
/**
* locks any entity that implements Lockable
*/
static async lockEntity (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
const token = this.getToken(req);
const userId = await dataSources.userAPI.getUserId(token);
const lock = await connection.getRepository(target)
.createQueryBuilder(alias)
.select([
alias + '.lockedUntil',
alias + '.lockedBy'
])
.where('id = :id', {
id: id
})
.andWhere(alias + '.lockedUntil > CURRENT_TIMESTAMP')
.getOne();
// eslint-disable-next-line eqeqeq
if (!lock?.lockedUntil || lock?.lockedBy == userId) {
// no lock -> set lock
await connection.getRepository(target)
.createQueryBuilder(alias)
.update()
.set({
lockedUntil: () => 'CURRENT_TIMESTAMP + INTERVAL \'10 MINUTE\'',
lockedBy: userId
})
.where('id = :id', { id: id })
.execute();
return true;
} else {
// lock was set
return false;
}
}
static async unlockEntity (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
const token = this.getToken(req);
const userId = await dataSources.userAPI.getUserId(token);
const lock = await 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 connection.getRepository(target)
.createQueryBuilder(alias)
.update()
.set({
lockedUntil: null,
lockedBy: null
})
.where('id = :id', { id: id })
.execute();
return true;
} else {
// entity is locked by other user
return false;
}
}
static async isLocked (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
const token = this.getToken(req);
const userId = await dataSources.userAPI.getUserId(token);
const lock = await connection.getRepository(CargoBike)
.createQueryBuilder(alias)
.select([
alias + '.lockedUntil',
alias + '.lockedBy'
])
.where('id = :id', {
id: id
})
.andWhere(alias + '.lockedUntil > CURRENT_TIMESTAMP')
.getOne();
if (!lock?.lockedUntil) {
// no lock
return false;
// eslint-disable-next-line eqeqeq
} else return lock?.lockedBy != userId;
}
}
Loading…
Cancel
Save