new generic lock/unlock functions

pull/14/head
leonnicolas 4 years ago
parent 81a7870cbb
commit 595f66f3dc
No known key found for this signature in database
GPG Key ID: 088D0743E2B65C07

@ -32,7 +32,7 @@ export class CargoBikeAPI extends DataSource {
}
/**
* Finds cargo bike by id, retuns null if id was not found
* Finds cargo bike by id, returns null if id was not found
* @param param0 id of bike
*/
async findCargoBikeById (id: number) {
@ -67,40 +67,16 @@ export class CargoBikeAPI extends DataSource {
.loadOne();
}
async lockCargoBike (id: number, req: any, dataSources: any) {
if (await LockUtils.lockEntity(this.connection, CargoBike, 'cargobike', id, req, dataSources)) {
return this.findCargoBikeById(id);
} else {
return new GraphQLError('CargoBike is locked by other user');
}
}
async unlockCargoBike (id: number, req: any, dataSources: any) {
return this.unlockEntity(CargoBike, 'cargobike', id, req, dataSources);
}
async lockEntity (target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
return LockUtils.lockEntity(this.connection, target, alias, id, req, dataSources);
}
async unlockEntity (target: ObjectType<Lockable>, alias: string, id: number, req: any, dataSources: any) {
return LockUtils.unlockEntity(this.connection, target, alias, id, req, dataSources);
}
async isLocked (id: number, req: any, dataSources: any) {
return LockUtils.isLocked(this.connection, CargoBike, 'cargobike', id, req, dataSources);
}
/**
* Updates CargoBike and return updated cargoBike
* @param param0 cargoBike to be updated
*/
async updateCargoBike (cargoBike: any, req: any, dataSources: any) {
async updateCargoBike (cargoBike: any, userId:number) {
// TODO lock cargoBike can return error to save one sql query, this will be a complex sql query
if (!await this.checkId(CargoBike, 'cargobike', cargoBike.id)) {
return new GraphQLError('ID not found');
}
if (!await this.lockCargoBike(cargoBike.id, req, dataSources)) {
if (!await LockUtils.lockEntity(this.connection, CargoBike, 'cb', cargoBike.id, userId)) {
return new GraphQLError('Bike locked by other user');
}
const keepLock = cargoBike?.keepLock;
@ -124,7 +100,7 @@ export class CargoBikeAPI extends DataSource {
.of(cargoBike.id)
.addAndRemove(equipmentTypeIds, await this.equipmentTypeByCargoBikeId(cargoBike.id)); // TODO remove all existing relations
});
!keepLock && await this.unlockCargoBike(cargoBike.id, req, dataSources);
!keepLock && await LockUtils.unlockEntity(this.connection, CargoBike, 'cb', cargoBike.id, userId);
return await this.findCargoBikeById(cargoBike.id);
}
@ -183,6 +159,16 @@ export class CargoBikeAPI extends DataSource {
.loadOne();
}
async bikeEventsByCargoBikeId (id: number, offset: number = 0, limit:number = 100) {
return await this.connection.getRepository(CargoBike)
.createQueryBuilder('cb')
.skip(offset)
.take(limit)
.relation(CargoBike, 'bikeEvents')
.of(id)
.loadMany();
}
async createBikeEventType (bikeEventType: any) {
return (await this.connection.getRepository(BikeEventType)
.createQueryBuilder('bet')
@ -229,6 +215,14 @@ export class CargoBikeAPI extends DataSource {
.getOne();
}
async lockBikeEvent (id: number, userId: number) {
return await LockUtils.lockEntity(this.connection, BikeEvent, 'be', id, userId);
}
async unlockBikeEvent (id: number, userId: number) {
return await LockUtils.unlockEntity(this.connection, BikeEvent, 'be', id, userId);
}
async findEquipmentById (id: number) {
return await this.connection.getRepository(Equipment)
.createQueryBuilder('equipment')
@ -248,6 +242,12 @@ export class CargoBikeAPI extends DataSource {
return result === 1;
}
/**
* Returns equipment of one cargoBike
* @param offset
* @param limit
* @param id
*/
async equipmentByCargoBikeId (offset: number, limit: number, id: number) {
return await this.connection.getRepository(Equipment)
.createQueryBuilder('equipment')
@ -282,16 +282,12 @@ export class CargoBikeAPI extends DataSource {
.getOne())?.cargoBike;
}
async lockEquipment (id: number, req: any, dataSources: any) {
if (await this.lockEntity(Equipment, 'equipment', id, req, dataSources)) {
return this.findEquipmentById(id);
} else {
return new GraphQLError('Equipment locked by other user');
}
async lockEquipment (id: number, userId: number) {
return LockUtils.lockEntity(this.connection, Equipment, 'e', id, userId);
}
async unlockEquipment (id: number, req: any, dataSources: any) {
return await this.unlockEntity(Equipment, 'equipment', id, req, dataSources);
async unlockEquipment (id: number, userId: number) {
return await LockUtils.unlockEntity(this.connection, Equipment, 'equipment', id, userId);
}
/**
@ -299,12 +295,12 @@ 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: any, req: any, dataSources: any) {
async updateEquipment (equipment: any, userId: number) {
// TODO let lock cargoBike can return error to save one sql query, this will be a complex sql query
if (!await this.checkId(Equipment, 'alias', equipment.id)) {
return new GraphQLError('ID not found in DB');
}
if (!await this.lockEntity(Equipment, 'equipment', equipment.id, req, dataSources)) {
if (!await LockUtils.lockEntity(this.connection, Equipment, 'equipment', equipment.id, userId)) {
return new GraphQLError('Equipment locked by other user');
}
const keepLock = equipment.keepLock;
@ -324,7 +320,7 @@ export class CargoBikeAPI extends DataSource {
.relation(Equipment, 'cargoBike')
.of(equipment.id)
.set(cargoBikeId);
!keepLock && this.unlockCargoBike(equipment.id, req, dataSources);
!keepLock && LockUtils.unlockEntity(this.connection, Equipment, 'e', equipment.id, userId);
return this.findEquipmentById(equipment.id);
}
return this.findEquipmentById(equipment.id);

@ -5,6 +5,7 @@ import { Connection, EntityManager, getConnection, QueryFailedError } from 'type
import { CargoBike } from '../../model/CargoBike';
import { LendingStation } from '../../model/LendingStation';
import { TimeFrame } from '../../model/TimeFrame';
import { LockUtils } from './utils';
export class LendingStationAPI extends DataSource {
connection : Connection
@ -81,6 +82,26 @@ export class LendingStationAPI extends DataSource {
.getMany().catch(() => { return []; });
}
async timeFrameById (id: number) {
return await this.connection.getRepository(TimeFrame)
.createQueryBuilder('tf')
.select()
.where('id = :id', { id: id })
.getOne();
}
async lockLendingStationById (id: number, uId: number) {
return await LockUtils.lockEntity(this.connection, LendingStation, 'ls', id, uId);
}
unlockLendingStationById (id: number, uId: number) {
return LockUtils.unlockEntity(this.connection, LendingStation, 'ls', id, uId);
}
async lockTimeFrame (id: number, userId: number) {
return await LockUtils.lockEntity(this.connection, TimeFrame, 'tf', id, userId);
}
/**
* Counts all timeframes with one lendingStation that overlap with today's date
* @param id of lendingStation
@ -115,22 +136,14 @@ export class LendingStationAPI extends DataSource {
*/
async createLendingStation (lendingStation: any) {
let inserts: any;
try {
await this.connection.transaction(async entiyManager => {
inserts = await entiyManager.createQueryBuilder(LendingStation, 'lendingstation')
.insert()
.values([lendingStation])
.returning('*')
.execute();
await entiyManager.getRepository(LendingStation)
.createQueryBuilder('lendingstation')
.relation(LendingStation, 'contactPersons')
.of(lendingStation.id)
.add(lendingStation?.contactPersonIds.map((e: any) => { return Number(e); }));
});
} catch (e :any) {
return new GraphQLError('Transaction could not be completed');
}
await this.connection.transaction(async entiyManager => {
inserts = await entiyManager.createQueryBuilder(LendingStation, 'lendingstation')
.insert()
.values([lendingStation])
.returning('*')
.execute();
});
const newLendingStaion = inserts.generatedMaps[0];
newLendingStaion.id = inserts.identifiers[0].id;
return newLendingStaion;

@ -3,6 +3,7 @@ import { Connection, EntityManager, getConnection } from 'typeorm';
import { Provider } from '../../model/Provider';
import { Organisation } from '../../model/Organisation';
import { UserInputError } from 'apollo-server';
import { CargoBike } from '../../model/CargoBike';
export class ProviderAPI extends DataSource {
connection : Connection
@ -36,6 +37,14 @@ export class ProviderAPI extends DataSource {
.getOne();
}
async providerByCargoBikeId (id: number) {
return await this.connection.getRepository(CargoBike)
.createQueryBuilder('cb')
.relation(CargoBike, 'provider')
.of(id)
.loadOne();
}
async organisationByProviderId (id: number) {
return await this.connection.getRepository(Provider)
.createQueryBuilder()

@ -1,5 +1,6 @@
import { Connection, ObjectType } from 'typeorm';
import { CargoBike, Lockable } from '../../model/CargoBike';
import { GraphQLError } from 'graphql';
export function genDateRange (struct: any) {
if (struct.to === undefined) {
@ -14,23 +15,33 @@ export function genDateRange (struct: any) {
}
}
/**
* Can be used in resolvers to specify if entry is locked by other user.
* Returns true if locked by other user.
* @param parent
* @param dataSources
* @param req user request
*/
export function isLocked (parent: any, { dataSources, req }: { dataSources: any; req: any }) {
return dataSources.userAPI.getUserId(LockUtils.getToken(req)).then((value: number) => {
return value !== parent.lockedBy && new Date() <= new Date(parent.lockedUntil);
});
}
export class LockUtils {
static getToken (req: any) : string {
return req.headers.authorization?.replace('Bearer ', '');
}
/**
* Locks any Entity, that
* @param connection
* @param target
* @param alias
* @param id
* @param req
* @param dataSources
*/
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);
static async findById (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, userId: number): Promise<Lockable> {
return await connection.getRepository(target)
.createQueryBuilder(alias)
.select()
.where(alias + '.id = :id', { id: id })
.getOne();
}
static async lockEntity (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, userId: number): Promise<Lockable> {
const lock = await connection.getRepository(target)
.createQueryBuilder(alias)
.select([
@ -44,7 +55,7 @@ export class LockUtils {
.getOne();
// eslint-disable-next-line eqeqeq
if (!lock?.lockedUntil || lock?.lockedBy == userId) {
// no lock -> set lock
// no lock -> set lock
await connection.getRepository(target)
.createQueryBuilder(alias)
.update()
@ -54,25 +65,14 @@ export class LockUtils {
})
.where('id = :id', { id: id })
.execute();
return true;
return await this.findById(connection, target, alias, id, userId);
} else {
// lock was set
return false;
// lock was set
throw new GraphQLError('Entry locked by other user');
}
}
/**
* Unlocks any entity that implements Lockable.
* @param connection
* @param target
* @param alias
* @param id
* @param req
* @param dataSources
*/
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);
static async unlockEntity (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, userId: number): Promise<boolean> {
const lock = await connection.getRepository(target)
.createQueryBuilder(alias)
.select([
@ -115,9 +115,7 @@ export class LockUtils {
* @param req
* @param dataSources
*/
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);
static async isLocked (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number, userId: number) {
const lock = await connection.getRepository(CargoBike)
.createQueryBuilder(alias)
.select([
@ -135,4 +133,22 @@ export class LockUtils {
// eslint-disable-next-line eqeqeq
} else return lock?.lockedBy != userId;
}
/**
* Returns true if id is found in database
* @param connection
* @param target
* @param alias
* @param id
*/
static async checkId (connection: Connection, target: ObjectType<Lockable>, alias: string, id: number) {
const result = await connection.getRepository(target)
.createQueryBuilder(alias)
.select([
alias + '.id'
])
.where('id = :id', { id: id })
.getCount();
return result === 1;
}
}

@ -45,12 +45,14 @@ require('dotenv').config();
async function authenticate (req: any, res: any, next: any) {
if (process.env.NODE_ENV === 'develop') {
req.permissions = requiredPermissions.map((e) => e.name);
req.userId = await userAPI.getUserId(req.headers.authorization?.replace('Bearer ', ''));
next();
} else {
const token = req.headers.authorization?.replace('Bearer ', '');
if (token) {
if (await userAPI.validateToken(token)) {
req.permissions = await userAPI.getUserPermissions(token);
req.userId = await userAPI.getUserId(req.headers.authorization?.replace('Bearer ', ''));
next();
} else {
res.status(401);

@ -1,12 +1,12 @@
/* eslint no-unused-vars: "off" */
import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, TreeLevelColumn } from 'typeorm';
import { CargoBike } from './CargoBike';
import { CargoBike, Lockable } from './CargoBike';
import { BikeEventType } from './BikeEventType';
import { Participant } from './Participant';
import { type } from 'os';
@Entity()
export class BikeEvent {
export class BikeEvent implements Lockable {
@PrimaryGeneratedColumn()
id: number;
@ -61,4 +61,15 @@ export class BikeEvent {
name: 'bikeEventTypeId'
})
bikeEventTypeId: number;
@Column({
nullable: true,
type: 'timestamp'
})
lockedUntil: Date;
@Column({
nullable: true
})
lockedBy: number;
}

@ -1,10 +1,10 @@
import { Entity, PrimaryGeneratedColumn, ManyToOne, Column, JoinColumn } from 'typeorm';
import { Participant } from './Participant';
import { CargoBike } from './CargoBike';
import { CargoBike, Lockable } from './CargoBike';
import { EngagementType } from './EngagementType';
@Entity()
export class Engagement {
export class Engagement implements Lockable {
@PrimaryGeneratedColumn()
id: number;
@ -62,4 +62,15 @@ export class Engagement {
default: false
})
roleBringer: boolean;
@Column({
nullable: true,
type: 'timestamp'
})
lockedUntil: Date;
@Column({
nullable: true
})
lockedBy: number;
}

@ -3,6 +3,7 @@ import { TimeFrame } from './TimeFrame';
import { Organisation } from './Organisation';
import { Address } from './Provider';
import { ContactInformation } from './ContactInformation';
import { Lockable } from './CargoBike';
export class LoanPeriod {
/**
@ -30,7 +31,7 @@ export class LoanPeriod {
}
@Entity()
export class LendingStation {
export class LendingStation implements Lockable {
@PrimaryGeneratedColumn()
id: number;
@ -63,4 +64,15 @@ export class LendingStation {
name: 'organisationId'
})
organisationId: number;
@Column({
nullable: true,
type: 'timestamp'
})
lockedUntil: Date;
@Column({
nullable: true
})
lockedBy: number;
}

@ -2,9 +2,10 @@ import { PrimaryGeneratedColumn, OneToOne, OneToMany, Column, Entity, JoinColumn
import { LendingStation } from './LendingStation';
import { Address, Provider } from './Provider';
import { ContactInformation } from './ContactInformation';
import { Lockable } from './CargoBike';
@Entity()
export class Organisation {
export class Organisation implements Lockable {
@PrimaryGeneratedColumn()
id: number;
@ -38,4 +39,15 @@ export class Organisation {
@Column(type => Address)
address: Address;
@Column({
nullable: true,
type: 'timestamp'
})
lockedUntil: Date;
@Column({
nullable: true
})
lockedBy: number;
}

@ -2,9 +2,10 @@ import { Entity, PrimaryGeneratedColumn, Column, OneToOne, JoinColumn, OneToMany
import { ContactInformation } from './ContactInformation';
import { Engagement } from './Engagement';
import { Workshop } from './Workshop';
import { Lockable } from './CargoBike';
@Entity()
export class Participant {
export class Participant implements Lockable {
@PrimaryGeneratedColumn()
id: number;
@ -68,4 +69,15 @@ export class Participant {
default: false
})
memberADFC: boolean;
@Column({
nullable: true,
type: 'timestamp'
})
lockedUntil: Date;
@Column({
nullable: true
})
lockedBy: number;
}

@ -1,12 +1,12 @@
import { Entity, PrimaryGeneratedColumn, Column, ManyToOne } from 'typeorm';
import { LendingStation } from './LendingStation';
import { CargoBike } from './CargoBike';
import { CargoBike, Lockable } from './CargoBike';
/**
* When was a cargoBike at what lendingStation
*/
@Entity()
export class TimeFrame {
export class TimeFrame implements Lockable {
@PrimaryGeneratedColumn()
id: number;
@ -25,4 +25,15 @@ export class TimeFrame {
@ManyToOne(type => CargoBike, cargoBike => cargoBike.timeFrames)
cargoBike: CargoBike;
@Column({
nullable: true,
type: 'timestamp'
})
lockedUntil: Date;
@Column({
nullable: true
})
lockedBy: number;
}

@ -1,5 +1,6 @@
import { Permission } from '../datasources/userserver/permission';
import { GraphQLError } from 'graphql';
import { isLocked } from '../datasources/db/utils';
export default {
Query: {
@ -59,24 +60,29 @@ export default {
lendingStation (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.lendingStationAPI.lendingStationByCargoBikeId(parent.id);
},
isLocked (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.cargoBikeAPI.isLocked(parent.id, req, dataSources);
bikeEvents (parent: any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.cargoBikeAPI.bikeEventsByCargoBikeId(parent.id, offset, limit);
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req }),
lockedBy (): any {
return null;
},
timeFrames (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.lendingStationAPI.timeFramesByCargoBikeId(parent.id, req, dataSources);
return dataSources.lendingStationAPI.timeFramesByCargoBikeId(parent.id);
},
equipmentType (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.cargoBikeAPI.equipmentTypeByCargoBikeId(parent.id, req, dataSources);
return dataSources.cargoBikeAPI.equipmentTypeByCargoBikeId(parent.id);
},
provider (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.providerAPI.providerByCargoBikeId(parent.id);
}
},
Equipment: {
cargoBike (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.cargoBikeAPI.cargoBikeByEquipmentId(parent.id);
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
BikeEvent: {
cargoBike (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
@ -90,7 +96,11 @@ export default {
},
related (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.cargoBikeAPI.relatedByBikeEventId(parent.id);
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
BikeEventType: {
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Mutation: {
createCargoBike: (_: any, { cargoBike }: { cargoBike: any }, { dataSources, req }: { dataSources: any, req: any }) => {
@ -102,21 +112,21 @@ export default {
},
lockCargoBikeById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.cargoBikeAPI.lockCargoBike(id, req, dataSources);
return dataSources.cargoBikeAPI.lockCargoBike(id, req.userId);
} else {
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);
return dataSources.cargoBikeAPI.unlockCargoBike(id, req.userId);
} 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);
return dataSources.cargoBikeAPI.updateCargoBike(cargoBike, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}
@ -128,6 +138,20 @@ export default {
return new GraphQLError('Insufficient Permissions');
}
},
lockBikeEventById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.cargoBikeAPI.lockBikeEvent(id, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}
},
unlockBikeEventById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.cargoBikeAPI.unlockBikeEvent(id, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}
},
createEquipment: (_: any, { equipment }: { equipment: any }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.cargoBikeAPI.createEquipment({ equipment });
@ -137,21 +161,21 @@ export default {
},
lockEquipmentById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.cargoBikeAPI.lockEquipment(id, req, dataSources);
return dataSources.cargoBikeAPI.lockEquipment(id, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}
},
unlockEquipment: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
unlockEquipmentById: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.cargoBikeAPI.unlockEquipment(id, req, dataSources);
return dataSources.cargoBikeAPI.unlockEquipment(id, req.userId);
} 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, req, dataSources);
return dataSources.cargoBikeAPI.updateEquipment(equipment, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}

@ -1,6 +1,7 @@
import { GraphQLError } from 'graphql';
import { Permission } from '../datasources/userserver/permission';
import { Person } from '../model/Person';
import { isLocked } from '../datasources/db/utils';
export default {
Query: {
@ -26,7 +27,8 @@ export default {
} else {
return new GraphQLError('Insufficient Permissions');
}
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Person: {
contactInformation: (parent: Person, __: any, { dataSources, req }: { dataSources: any, req: any }) => {
@ -35,7 +37,8 @@ export default {
} else {
return new GraphQLError('Insufficient Permissions');
}
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
ContactInformation: {
person: (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) => {
@ -44,7 +47,8 @@ export default {
} else {
return new GraphQLError('Insufficient Permissions');
}
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Mutation: {
createContactPerson: (_: any, { contactPerson }: { contactPerson: any }, { dataSources, req }: { dataSources: any, req: any }) => {

@ -1,6 +1,7 @@
import { Permission } from '../datasources/userserver/permission';
import { GraphQLError } from 'graphql';
import { LendingStation } from '../model/LendingStation';
import { isLocked } from '../datasources/db/utils';
export default {
Query: {
@ -35,6 +36,12 @@ export default {
},
cargoBikes (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.lendingStationAPI.cargoBikesByLendingStationId(parent.id);
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
LoanPeriod: {
loanTimes (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return parent.loanTimes.split(',');
}
},
TimeFrame: {
@ -50,7 +57,8 @@ export default {
},
lendingStation (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
return dataSources.lendingStationAPI.lendingStationByTimeFrameId(parent.id);
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Mutation: {
createLendingStation: (_: any, { lendingStation }:{ lendingStation: LendingStation }, { dataSources, req }:{dataSources: any, req: any }) => {
@ -60,6 +68,16 @@ export default {
return new GraphQLError('Insufficient Permissions');
}
},
lockLendingStationById: (_: any, { id }:{ id: number }, { dataSources, req }:{dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.lendingStationAPI.lockLendingStationById(id, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}
},
unlockLendingStationById: (_: any, { id }:{ id: number }, { dataSources, req }:{dataSources: any, req: any }) => {
return dataSources.lendingStationAPI.unlockLendingStationById(id, req.userId);
},
updateLendingStation: (_: any, { lendingStation }:{ lendingStation: LendingStation }, { dataSources, req }:{dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.lendingStationAPI.updateLendingStation({ lendingStation });
@ -73,6 +91,13 @@ export default {
} else {
return new GraphQLError('Insufficient Permissions');
}
},
lockTimeFrame: (_: any, { id }:{ id: number }, { dataSources, req }:{dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteBike)) {
return dataSources.lendingStationAPI.lockTimeFrame(id, req.userId);
} else {
return new GraphQLError('Insufficient Permissions');
}
}
}
};

@ -1,6 +1,7 @@
import { GraphQLError } from 'graphql';
import { Permission } from '../datasources/userserver/permission';
import { EngagementType } from '../model/EngagementType';
import { isLocked } from '../datasources/db/utils';
export default {
Query: {
@ -25,7 +26,8 @@ export default {
},
contactInformation (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) {
return (dataSources.participantAPI.contactInformationByParticipantId(parent.id));
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Engagement: {
cargoBike (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) {
@ -43,7 +45,8 @@ export default {
to (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) {
const str = (parent.dateRange as string).split(',')[1].replace(')', '');
return (str.length > 0) ? str : null;
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Mutation: {
createParticipant: (_: any, { participant }: { participant: any }, { dataSources, req }: { dataSources: any, req: any }) => {

@ -1,5 +1,6 @@
import { GraphQLError } from 'graphql';
import { Permission } from '../datasources/userserver/permission';
import { isLocked } from '../datasources/db/utils';
export default {
Query: {
@ -31,7 +32,8 @@ export default {
},
privatePerson: (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) => {
return dataSources.providerAPI.privatePersonByProviderId(parent.id);
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Organisation: {
provider: (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) => {
@ -39,7 +41,8 @@ export default {
},
contactInformation: (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) => {
return dataSources.providerAPI.contactInformationByOrganisationId(parent.id);
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Mutation: {
createProvider: (_: any, { provider }: { provider: number }, { dataSources, req }: { dataSources: any, req: any }) => {

@ -1,5 +1,6 @@
import { Permission } from '../datasources/userserver/permission';
import { GraphQLError } from 'graphql';
import { isLocked } from '../datasources/db/utils';
export default {
Query: {
@ -24,7 +25,11 @@ export default {
},
trainer2: (parent: any, __:any, { dataSources, req }: { dataSources: any, req: any }) => {
return dataSources.workshopAPI.trainer2ByWorkshopId(parent.id);
}
},
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
WorkshopType: {
isLocked: (parent: any, __: any, { dataSources, req }: { dataSources: any; req: any }) => isLocked(parent, { dataSources, req })
},
Mutation: {
createWorkshop: (_: any, { workshop }: { workshop: number }, { dataSources, req }: { dataSources: any, req: any }) => {

@ -31,7 +31,7 @@ type CargoBike {
Does not refer to an extra table in the database.
"""
dimensionsAndLoad: DimensionsAndLoad!
bikeEvents: [BikeEvent]
bikeEvents(offset: Int, limit: Int): [BikeEvent]
equipment(offset: Int!, limit: Int!): [Equipment]
"Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2"
equipmentType: [EquipmentType]
@ -184,6 +184,116 @@ input InsuranceDataUpdateInput {
notes: String
}
"How are the dimensions and how much weight can handle a bike. This data is merged in the CargoBike table and the BikeModel table."
type DimensionsAndLoad {
hasCoverBox: Boolean!
lockable: Boolean!
boxLength: Float!
boxWidth: Float!
boxHeight: Float!
maxWeightBox: Float!
maxWeightLuggageRack: Float!
maxWeightTotal: Float!
bikeLength: Float!
bikeWidth: Float
bikeHeight: Float
bikeWeight: Float
}
input DimensionsAndLoadCreateInput {
hasCoverBox: Boolean!
lockable: Boolean!
boxLength: Float!
boxWidth: Float!
boxHeight: Float!
maxWeightBox: Float!
maxWeightLuggageRack: Float!
maxWeightTotal: Float!
bikeLength: Float!
bikeWidth: Float
bikeHeight: Float
bikeWeight: Float
}
input DimensionsAndLoadUpdateInput {
hasCoverBox: Boolean
lockable: Boolean
boxLength: Float
boxWidth: Float
boxHeight: Float
maxWeightBox: Float
maxWeightLuggageRack: Float
maxWeightTotal: Float
bikeLength: Float
bikeWidth: Float
bikeHeight: Float
bikeWeight: Float
}
"""
Some Technical Info about the bike.
This should be 1-1 Relation with the CargoBike.
So no id needed for mutation. One Mutation for the CargoBike will be enough.
"""
type TechnicalEquipment {
bicycleShift: String!
isEBike: Boolean!
hasLightSystem: Boolean!
specialFeatures: String
}
input TechnicalEquipmentCreateInput {
bicycleShift: String!
isEBike: Boolean!
hasLightSystem: Boolean!
specialFeatures: String
}
input TechnicalEquipmentUpdateInput {
bicycleShift: String
isEBike: Boolean
hasLightSystem: Boolean
specialFeatures: String
}
"""
The Security Info about the bike.
his should be 1-1 Relation with the CargoBike.
So no id needed for mutation. One Mutation for the CargoBike will be enough.
"""
type Security {
frameNumber: String!
keyNumberFrameLock: String
keyNumberAXAChain: String
policeCoding: String
adfcCoding: String
}
input SecurityCreateInput {
frameNumber: String!
keyNumberFrameLock: String
keyNumberAXAChain: String
policeCoding: String
adfcCoding: String
}
input SecurityUpdateInput {
frameNumber: String
keyNumberFrameLock: String
keyNumberAXAChain: String
policeCoding: String
adfcCoding: String
}
enum StickerBikeNameState {
OK
IMPROVE
PRODUCED
NONEED
MISSING
UNKNOWN
}
enum Group{
KL
LI
@ -195,18 +305,6 @@ enum Group{
TK
}
"""
The BikeModel can be used for instantiate new bikes with a given model.
It should only be used to fill in default values.
Even bikes of the same model can have different properties.
"""
type BikeModel {
id: ID!
name: String!
dimensionsAndLoad: DimensionsAndLoad!
technicalEquipment: TechnicalEquipment!
}
type Participant {
id: ID!
start: Date!
@ -225,6 +323,10 @@ type Participant {
"""
distributedActiveBikeParte: Boolean!
engagement: [Engagement]
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input ParticipantCreateInput {
@ -250,6 +352,10 @@ type Workshop {
workshopType: WorkshopType!
trainer1: Participant!
trainer2: Participant
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input WorkshopCreateInput {
@ -264,6 +370,10 @@ input WorkshopCreateInput {
type WorkshopType {
id: ID!
name: String!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input WorkshopTypeCreateInput {
@ -274,6 +384,10 @@ type EngagementType {
id: ID!
name: String!
description: String!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input EngagementTypeCreateInput {
@ -296,6 +410,10 @@ type Engagement {
roleMentor: Boolean!
roleAmbulance: Boolean!
roleBringer: Boolean!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input EngagementCreateInput {
@ -341,16 +459,6 @@ enum OrganisationArea {
ZB
}
type ChainSwap {
id: ID!
"""
TODO why is this a string"
"""
mechanic: String
timeOfSwap: Date
keyNumberOldAXAChain: String
}
"""
This type represents a piece of equipment that represents a real physical object.
The object must be unique. So it is possible to tell it apart from similar objects by a serial number.
@ -358,35 +466,27 @@ The object must be unique. So it is possible to tell it apart from similar objec
type Equipment {
id: ID!
serialNo: String!
"""
TODO unclear what this means. tomy fragen
"""
investable: Boolean
title: String!
description: String
cargoBike: CargoBike
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input EquipmentCreateInput {
serialNo: String!
"""
TODO unclear what this means. tomy fragen
"""
title: String!
description: String
investable: Boolean
cargoBikeId: ID
}
input EquipmentUpdateInput {
id: ID!
serialNo: String
"""
TODO unclear what this means. tomy fragen
"""
title: String
description: String
investable: Boolean
cargoBikeId: ID
"will keep Bike locked if set to true, default = false"
keepLock: Boolean
@ -396,6 +496,10 @@ type EquipmentType {
id: ID!
name: String!
description: String!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input EquipmentTypeCreateInput {
@ -423,6 +527,10 @@ type BikeEvent {
"""
documents: [String]!
remark: String
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input BikeEventCreateInput {
@ -442,6 +550,8 @@ input BikeEventCreateInput {
type BikeEventType {
id: ID!
name: String!
isLocked: Boolean!
lockedUntil: Date
}
input BikeEventTypeInput {
@ -449,116 +559,6 @@ input BikeEventTypeInput {
name: String
}
"How are the dimensions and how much weight can handle a bike. This data is merged in the CargoBike table and the BikeModel table."
type DimensionsAndLoad {
hasCoverBox: Boolean!
lockable: Boolean!
boxLength: Float!
boxWidth: Float!
boxHeight: Float!
maxWeightBox: Float!
maxWeightLuggageRack: Float!
maxWeightTotal: Float!
bikeLength: Float!
bikeWidth: Float
bikeHeight: Float
bikeWeight: Float
}
input DimensionsAndLoadCreateInput {
hasCoverBox: Boolean!
lockable: Boolean!
boxLength: Float!
boxWidth: Float!
boxHeight: Float!
maxWeightBox: Float!
maxWeightLuggageRack: Float!
maxWeightTotal: Float!
bikeLength: Float!
bikeWidth: Float
bikeHeight: Float
bikeWeight: Float
}
input DimensionsAndLoadUpdateInput {
hasCoverBox: Boolean
lockable: Boolean
boxLength: Float
boxWidth: Float
boxHeight: Float
maxWeightBox: Float
maxWeightLuggageRack: Float
maxWeightTotal: Float
bikeLength: Float
bikeWidth: Float
bikeHeight: Float
bikeWeight: Float
}
"""
Some Technical Info about the bike.
This should be 1-1 Relation with the CargoBike.
So no id needed for mutation. One Mutation for the CargoBike will be enough.
"""
type TechnicalEquipment {
bicycleShift: String!
isEBike: Boolean!
hasLightSystem: Boolean!
specialFeatures: String
}
input TechnicalEquipmentCreateInput {
bicycleShift: String!
isEBike: Boolean!
hasLightSystem: Boolean!
specialFeatures: String
}
input TechnicalEquipmentUpdateInput {
bicycleShift: String
isEBike: Boolean
hasLightSystem: Boolean
specialFeatures: String
}
"""
The Security Info about the bike.
his should be 1-1 Relation with the CargoBike.
So no id needed for mutation. One Mutation for the CargoBike will be enough.
"""
type Security {
frameNumber: String!
keyNumberFrameLock: String
keyNumberAXAChain: String
policeCoding: String
adfcCoding: String
}
input SecurityCreateInput {
frameNumber: String!
keyNumberFrameLock: String
keyNumberAXAChain: String
policeCoding: String
adfcCoding: String
}
input SecurityUpdateInput {
frameNumber: String
keyNumberFrameLock: String
keyNumberAXAChain: String
policeCoding: String
adfcCoding: String
}
enum StickerBikeNameState {
OK
IMPROVE
PRODUCED
NONEED
MISSING
UNKNOWN
}
"(dt. Anbieter) bezieht sich auf die Beziehung einer Person oder Organisation zum Lastenrad"
type Provider {
id: ID!
@ -566,6 +566,10 @@ type Provider {
privatePerson: ContactInformation
organisation: Organisation
cargoBikes: [CargoBike]
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
"(dt. Anbieter)"
@ -585,6 +589,10 @@ type Person {
name: String!
firstName: String!
contactInformation: [ContactInformation]
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input PersonCreateInput {
@ -600,6 +608,10 @@ type ContactInformation {
email: String
email2: String
note: String
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input ContactInformationCreateInput {
@ -626,6 +638,10 @@ type ContactPerson {
id: ID!
intern: Boolean!
contactInformation: ContactInformation!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input ContactPersonCreateInput {
@ -652,6 +668,10 @@ type Organisation {
provider: Provider
contactInformation: ContactInformation
otherData: String
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input OrganisationCreateInput {
@ -680,6 +700,10 @@ type LendingStation {
cargoBikes: [CargoBike]
"Total amount of cargoBikes currently assigned to the lending station"
numCargoBikes: Int!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
"""
@ -715,7 +739,7 @@ type LoanPeriod {
Loan times from and until for each day of the week.
Starting with Monday from, Monday to, Tuesday from, ..., Sunday to
"""
times: [String]
loanTimes: [String]
}
"""
@ -729,7 +753,7 @@ input LoanPeriodInput {
Loan times from and until for each day of the week.
Starting with Monday from, Monday to, Tuesday from, ..., Sunday to
"""
times: [String]
loanTimes: [String]
}
"(dt. Zeitscheibe) When was a bike where"
@ -742,6 +766,10 @@ type TimeFrame {
note: String
lendingStation: LendingStation!
cargoBike: CargoBike!
isLocked: Boolean!
"null if not locked by other user"
lockedBy: ID
lockedUntil: Date
}
input TimeFrameCreateInput {
@ -828,7 +856,7 @@ type Mutation {
"lock equipment returns true if bike is not locked or if it doesnt exist"
lockEquipmentById(id: ID!): Equipment!
"unlock Equipment, returns true if Bike does not exist"
unlockEquipment(id: ID!): Boolean!
unlockEquipmentById(id: ID!): Boolean!
"update Equipment, returns updated equipment. CargoBike will be null, if cargoBikeId is not set. Pass null for cargoBikeIs to delete the relation"
updateEquipment(equipment: EquipmentUpdateInput!): Equipment!
createEquipmentType(equipmentType: EquipmentTypeCreateInput!): EquipmentType!
@ -837,15 +865,20 @@ type Mutation {
creates new lendingStation and returns lendingStation with new ID
"""
createLendingStation(lendingStation: LendingStationCreateInput): LendingStation!
lockLendingStationById(id: ID!): LendingStation
unlockLendingStationById(id: ID!): Boolean!
"updates lendingStation of given ID with supplied fields and returns updated lendingStation"
updateLendingStation(lendingStation: LendingStationUpdateInput!): LendingStation!
createTimeFrame(timeFrame: TimeFrameCreateInput!): TimeFrame!
lockTimeFrame(id: ID!): TimeFrame
"""
BIKEEVENT
"""
createBikeEventType(name: String!): BikeEventType!
"creates new BikeEvent"
createBikeEvent(bikeEvent: BikeEventCreateInput!): BikeEvent!
lockBikeEventById(id: ID!): BikeEvent
unlockBikeEventById(id: ID!): Boolean!
"create participant"
createParticipant(participant: ParticipantCreateInput!): Participant!
createWorkshopType(workshopType: WorkshopTypeCreateInput!): WorkshopType!

Loading…
Cancel
Save