From 297b5592e56e47a97a9cd8d4565bbce83d10de17 Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Sun, 20 Sep 2020 14:04:44 +0200 Subject: [PATCH 1/4] implemented bike lendingstation relation --- src/datasources/db/cargobikeAPI.ts | 13 +++++++++++-- src/datasources/db/lendingstationAPI.ts | 6 +++--- src/model/CargoBike.ts | 3 ++- src/model/LendingStation.ts | 4 +++- src/schema/type-defs.ts | 8 ++++++-- 5 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/datasources/db/cargobikeAPI.ts b/src/datasources/db/cargobikeAPI.ts index ee94e41..bab71f0 100644 --- a/src/datasources/db/cargobikeAPI.ts +++ b/src/datasources/db/cargobikeAPI.ts @@ -30,7 +30,7 @@ export class CargoBikeAPI extends DataSource { * @param param0 id of bike */ async findCargoBikeById ({ id }:{id: any}) { - return await this.connection.manager.getRepository(CargoBike).findOne({ id: id }); + return (await this.connection.manager.getRepository(CargoBike).findByIds([id], { relations: ['lendingStation'] }))[0]; /* .createQueryBuilder() .select('cargoBike') .from(CargoBike, 'cargoBike') @@ -42,19 +42,28 @@ export class CargoBikeAPI extends DataSource { * Updates CargoBike and return updated cargoBike * @param param0 cargoBike to be updated */ - async updateCargoBike ({ cargoBike }:{ cargoBike: CargoBike }) { + async updateCargoBike ({ cargoBike }:{ cargoBike: any }) { const bike = await this.connection.manager.createQueryBuilder() .select('cargoBike') .from(CargoBike, 'cargoBike') .where('cargoBike.id = :id', { id: cargoBike.id }) .getOne(); if (bike) { + const lendingStationId = cargoBike.lendingStationId; + delete cargoBike.lendingStationId; await this.connection.manager .createQueryBuilder() .update(CargoBike) .set({ ...cargoBike }) .where('id = :id', { id: bike.id }) .execute(); + if (lendingStationId || lendingStationId === null) { + await this.connection.getRepository(CargoBike) + .createQueryBuilder() + .relation(CargoBike, 'lendingStation') + .of(cargoBike.id) + .set(lendingStationId); + } return await this.findCargoBikeById({ id: bike.id }); } else { return new GraphQLError('ID not in database'); diff --git a/src/datasources/db/lendingstationAPI.ts b/src/datasources/db/lendingstationAPI.ts index fc75017..c9b13d5 100644 --- a/src/datasources/db/lendingstationAPI.ts +++ b/src/datasources/db/lendingstationAPI.ts @@ -1,6 +1,7 @@ import { DataSource } from 'apollo-datasource'; import { GraphQLError } from 'graphql'; import { Connection, getConnection } from 'typeorm'; +import { CargoBike } from '../../model/CargoBike'; import { LendingStation } from '../../model/LendingStation'; export class LendingStationAPI extends DataSource { @@ -24,9 +25,8 @@ export class LendingStationAPI extends DataSource { */ async getLendingStations () { return await this.connection.manager - .createQueryBuilder() - .select('lendingStation') - .from(LendingStation, 'lendingStation') + .createQueryBuilder(LendingStation, 'lendingStation') + .leftJoinAndSelect('CargoBike', 'cargoBike', 'cargoBike.lendingStation = lendingStation.id')// ('lendingStation.cargoBikes', 'cargoBike.lendingStation', 'cargoBike', 'cargoBike.lendingStationId = lendingStation.id') .getMany() || new GraphQLError('Internal Server Error: could not query data from table lendingStation'); } diff --git a/src/model/CargoBike.ts b/src/model/CargoBike.ts index 8472442..e012c9d 100644 --- a/src/model/CargoBike.ts +++ b/src/model/CargoBike.ts @@ -131,7 +131,8 @@ export class CargoBike extends Bike { // This relation is a little redundant because one could also check all LoanPeriods for current station @ManyToOne(type => LendingStation, lendingStation => lendingStation.cargoBikes, { - nullable: true + nullable: true, + eager: true }) lendingStation: LendingStation; diff --git a/src/model/LendingStation.ts b/src/model/LendingStation.ts index 642c5d5..21af80d 100644 --- a/src/model/LendingStation.ts +++ b/src/model/LendingStation.ts @@ -23,7 +23,9 @@ export class LendingStation { @OneToMany(type => LoanPeriod, loanPeriod => loanPeriod.lendingStation) loanPeriods: LoanPeriod[]; - @OneToMany(type => CargoBike, cargoBike => cargoBike.lendingStation) + @OneToMany(type => CargoBike, cargoBike => cargoBike.lendingStation, { + eager: false + }) cargoBikes: CargoBike[]; @ManyToOne(type => Organization, organization => organization.lendingStations) diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index 19f9469..1323f8b 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -39,7 +39,7 @@ type CargoBike { provider: Provider coordinator: Participant insuranceData: InsuranceData! - lendingstation: LendingStation + lendingStation: LendingStation taxes: Taxes "null if not locked by other user" lockedBy: ID @@ -104,7 +104,7 @@ input CargoBikeUpdateInput { dimensionsAndLoad: DimensionsAndLoadUpdateInput "Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2" otherEquipment: [String] - + lendingStationId: ID "Sticker State" stickerBikeNameState: StickerBikeNameState note: String @@ -518,6 +518,9 @@ type LendingStation { address: Address! loanTimes: LoanTimes loanPeriods: [LoanPeriod]! + cargoBikes: [CargoBike] + "Totola Amount of cargoBikes currently assigned to the lending station" + numCargoBikes: Int! } input LendingStationCreateInput { @@ -535,6 +538,7 @@ input LendingStationUpdateInput { address: AddressUpdateInput loanTimes: LoanTimesInput loanPeriods: [LoanPeriodUpdateInput] + } """ From 8f5d98c975330ba708094e8d7343abfc1f6642ad Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Mon, 21 Sep 2020 12:18:55 +0200 Subject: [PATCH 2/4] sr/model/* included suggested changes from fLotte --- src/datasources/db/lendingstationAPI.ts | 1 - src/datasources/db/participantAPI.ts | 22 ++++++++++++++++ src/index.ts | 12 ++++++--- src/model/BikeEvent.ts | 24 ++++++++++++++--- src/model/CargoBike.ts | 8 +----- src/model/ChainSwap.ts | 22 ---------------- src/model/ContactInformation.ts | 6 +---- src/model/ContactPerson.ts | 28 ++++++++++++++++++++ src/model/Engagement.ts | 15 +++++++++++ src/model/LendingStation.ts | 6 ++--- src/model/Organization.ts | 5 +++- src/model/Participant.ts | 20 +++----------- src/model/Provider.ts | 20 +++++++------- src/model/Workshop.ts | 8 +++++- src/resolvers/participantResolvers.ts | 19 ++++++++++++++ src/schema/type-defs.ts | 35 ++++++++++++++++++++++--- 16 files changed, 173 insertions(+), 78 deletions(-) create mode 100644 src/datasources/db/participantAPI.ts delete mode 100644 src/model/ChainSwap.ts create mode 100644 src/model/ContactPerson.ts create mode 100644 src/resolvers/participantResolvers.ts diff --git a/src/datasources/db/lendingstationAPI.ts b/src/datasources/db/lendingstationAPI.ts index c9b13d5..7658041 100644 --- a/src/datasources/db/lendingstationAPI.ts +++ b/src/datasources/db/lendingstationAPI.ts @@ -1,7 +1,6 @@ import { DataSource } from 'apollo-datasource'; import { GraphQLError } from 'graphql'; import { Connection, getConnection } from 'typeorm'; -import { CargoBike } from '../../model/CargoBike'; import { LendingStation } from '../../model/LendingStation'; export class LendingStationAPI extends DataSource { diff --git a/src/datasources/db/participantAPI.ts b/src/datasources/db/participantAPI.ts new file mode 100644 index 0000000..65a8ae4 --- /dev/null +++ b/src/datasources/db/participantAPI.ts @@ -0,0 +1,22 @@ +import { DataSource } from 'apollo-datasource'; +import { Connection, getConnection } from 'typeorm'; + +export class ParticipantAPI extends DataSource { + connection : Connection + constructor () { + super(); + this.connection = getConnection(); + } + + async getParticipantById (id: number) { + return { + id: 2 + }; + } + + async engagementByParticipantId (id: number) { + return { + id: 3 + }; + } +} diff --git a/src/index.ts b/src/index.ts index 1e2bc45..f541541 100644 --- a/src/index.ts +++ b/src/index.ts @@ -10,7 +10,6 @@ import { requiredPermissions } from './datasources/userserver/permission'; import { CargoBike } from './model/CargoBike'; import { BikeEvent } from './model/BikeEvent'; import { BikeModel } from './model/BikeModel'; -import { ChainSwap } from './model/ChainSwap'; import { ContactInformation } from './model/ContactInformation'; import { Equipment } from './model/Equipment'; import { LendingStation } from './model/LendingStation'; @@ -22,6 +21,9 @@ import { Engagement } from './model/Engagement'; import { Workshop } from './model/Workshop'; import { LendingStationAPI } from './datasources/db/lendingstationAPI'; import lendingstationResolvers from './resolvers/lendingstationResolvers'; +import { ParticipantAPI } from './datasources/db/participantAPI'; +import participantResolvers from './resolvers/participantResolvers'; +import { ContactPerson } from './model/ContactPerson'; require('dotenv').config(); @@ -59,7 +61,6 @@ createConnection({ CargoBike, BikeEvent, BikeModel, - ChainSwap, ContactInformation, Equipment, LendingStation, @@ -68,7 +69,8 @@ createConnection({ Participant, Provider, Engagement, - Workshop + Workshop, + ContactPerson ], synchronize: true, logging: false @@ -81,12 +83,14 @@ const userAPI = new UserServerAPI(process.env.RPC_HOST); const server = new ApolloServer({ resolvers: [ bikeresolver, - lendingstationResolvers + lendingstationResolvers, + participantResolvers ], typeDefs, dataSources: () => ({ cargoBikeAPI: new CargoBikeAPI(), lendingStationAPI: new LendingStationAPI(), + participantAPI: new ParticipantAPI(), userAPI }), context: (req: any) => { diff --git a/src/model/BikeEvent.ts b/src/model/BikeEvent.ts index 5b271db..481e17d 100644 --- a/src/model/BikeEvent.ts +++ b/src/model/BikeEvent.ts @@ -1,5 +1,5 @@ /* eslint no-unused-vars: "off" */ -import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn } from 'typeorm'; +import { Entity, Column, PrimaryGeneratedColumn, ManyToOne, JoinColumn, TreeLevelColumn } from 'typeorm'; import { CargoBike } from './CargoBike'; export enum BikeEventType { @@ -7,14 +7,15 @@ export enum BikeEventType { INBETRIEBNAHME = 'INBETRIEBNAHME', AUSFALL = 'AUSFALL', WARTUNG = 'WARTUNG', + KETTENWECHSEL = 'KETTENWECHSEL', ANDERE = 'ANDERE' } @Entity() export class BikeEvent { - public setValues ({ id, note, date, documents, cargoBike, eventType }: { id: number, note: string, date: Date, documents: string[], cargoBike: CargoBike, eventType: BikeEventType}): void { + public setValues ({ id, remark, date, documents, cargoBike, eventType }: { id: number, remark: string, date: Date, documents: string[], cargoBike: CargoBike, eventType: BikeEventType}): void { this.id = id; - this.note = note; + this.remark = remark; this.date = date; this.documents = documents; this.cargoBike = cargoBike; @@ -27,13 +28,28 @@ export class BikeEvent { @Column({ nullable: true }) - note: string; + name: string; + + @Column({ + nullable: true + }) + remark: string; @Column({ type: 'date' }) date: Date; + @Column({ + nullable: true + }) + mechanic: string; + + @Column({ + nullable: true + }) + kexNoOldAXAChain: string; + @Column('simple-array', { nullable: true }) diff --git a/src/model/CargoBike.ts b/src/model/CargoBike.ts index e012c9d..baeddc1 100644 --- a/src/model/CargoBike.ts +++ b/src/model/CargoBike.ts @@ -1,7 +1,6 @@ /* eslint no-unused-vars: "off" */ import { Entity, Column, PrimaryGeneratedColumn, OneToMany, ManyToOne, JoinColumn } from 'typeorm'; import { Bike } from './BikeFeatures'; -import { ChainSwap } from './ChainSwap'; import { Provider } from './Provider'; import { Participant } from './Participant'; import { InsuranceData } from './InsuranceData'; @@ -81,12 +80,7 @@ export class CargoBike extends Bike { type: 'simple-array', nullable: true }) - otherEquipment: string[]; - - @OneToMany(type => ChainSwap, chainSwap => chainSwap.cargoBike, { - nullable: true - }) - chainSwaps: ChainSwap[] + miscellaneousEquipment: string[]; // Security information @Column(type => Security) diff --git a/src/model/ChainSwap.ts b/src/model/ChainSwap.ts deleted file mode 100644 index dbab23b..0000000 --- a/src/model/ChainSwap.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from 'typeorm'; -import { CargoBike } from './CargoBike'; - -@Entity() -export class ChainSwap { - @PrimaryGeneratedColumn() - id: number; - - @Column() - mechanic: string; - - @Column({ - type: 'date' - }) - time: Date; - - @Column() - kexNoOldAXAChain: string; - - @ManyToOne(type => CargoBike, cargoBike => cargoBike.chainSwaps) - cargoBike: CargoBike; -} diff --git a/src/model/ContactInformation.ts b/src/model/ContactInformation.ts index 766beb6..d3578fb 100644 --- a/src/model/ContactInformation.ts +++ b/src/model/ContactInformation.ts @@ -1,5 +1,4 @@ -import { PrimaryGeneratedColumn, Column, ManyToOne, Entity } from 'typeorm'; -import { Provider } from './Provider'; +import { PrimaryGeneratedColumn, Column, Entity } from 'typeorm'; @Entity() export class ContactInformation { @@ -50,7 +49,4 @@ export class ContactInformation { @Column() note: string; - - @ManyToOne(type => Provider, provider => provider.contactInformation) - provider: Provider; } diff --git a/src/model/ContactPerson.ts b/src/model/ContactPerson.ts new file mode 100644 index 0000000..4e2107b --- /dev/null +++ b/src/model/ContactPerson.ts @@ -0,0 +1,28 @@ +import { Column, Entity, ManyToMany, ManyToOne, PrimaryGeneratedColumn } from 'typeorm'; +import { ContactInformation } from './ContactInformation'; +import { LendingStation } from './LendingStation'; +import { Provider } from './Provider'; + +@Entity() +export class ContactPerson { + @PrimaryGeneratedColumn() + id: number; + + @ManyToOne(type => ContactInformation) + contactInformation: ContactInformation; + + @ManyToMany(type => LendingStation, lendingStation => lendingStation.contactPersons, { + nullable: true + }) + lendingStation: LendingStation; + + @ManyToMany(type => Provider, provider => provider.contactPersons, { + nullable: true + }) + provider: Provider[]; + + @Column({ + type: 'boolean' + }) + intern: boolean; +} diff --git a/src/model/Engagement.ts b/src/model/Engagement.ts index fbfb29b..236e913 100644 --- a/src/model/Engagement.ts +++ b/src/model/Engagement.ts @@ -23,4 +23,19 @@ export class Engagement { nullable: true }) to: Date; + + @Column() + roleCoordinator: boolean; + + @Column() + roleEmployeADFC: boolean; + + @Column() + roleMentor: boolean; + + @Column() + roleAmbulance: boolean; + + @Column() + roleBringer: boolean; } diff --git a/src/model/LendingStation.ts b/src/model/LendingStation.ts index 21af80d..9186739 100644 --- a/src/model/LendingStation.ts +++ b/src/model/LendingStation.ts @@ -1,9 +1,9 @@ import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable, OneToMany, ManyToOne } from 'typeorm'; -import { ContactInformation } from './ContactInformation'; import { LoanPeriod } from './LoanPeriod'; import { CargoBike } from './CargoBike'; import { Organization } from './Organization'; import { Address } from './Provider'; +import { ContactPerson } from './ContactPerson'; @Entity() export class LendingStation { @@ -13,9 +13,9 @@ export class LendingStation { @Column() name: string; - @ManyToMany(type => ContactInformation) + @ManyToMany(type => ContactPerson) @JoinTable() - contactInformation: ContactInformation[]; + contactPersons: ContactPerson[]; @Column(type => Address) address: Address; diff --git a/src/model/Organization.ts b/src/model/Organization.ts index 24f018e..d62d5d5 100644 --- a/src/model/Organization.ts +++ b/src/model/Organization.ts @@ -1,6 +1,6 @@ import { PrimaryGeneratedColumn, OneToOne, OneToMany, Column, Entity } from 'typeorm'; import { LendingStation } from './LendingStation'; -import { Provider } from './Provider'; +import { Address, Provider } from './Provider'; @Entity() export class Organization { @@ -25,4 +25,7 @@ export class Organization { nullable: true }) registerNo: string; + + @Column(type => Address) + address: Address; } diff --git a/src/model/Participant.ts b/src/model/Participant.ts index a3245c8..b0b4aca 100644 --- a/src/model/Participant.ts +++ b/src/model/Participant.ts @@ -15,7 +15,8 @@ export class Participant { start: Date; @Column({ - type: 'date' + type: 'date', + nullable: true }) end: Date; @@ -49,22 +50,7 @@ export class Participant { workshops: Workshop[]; @Column() - roleCoreTeam: boolean; - - @Column() - roleCoordinator: boolean; - - @Column() - roleEmployeADFC: boolean; - - @Column() - roleMentor: boolean; - - @Column() - roleAmbulance: boolean; - - @Column() - roleBringer: boolean; + memberCoreTeam: boolean; @Column({ type: 'date' diff --git a/src/model/Provider.ts b/src/model/Provider.ts index 963dbb4..61053a8 100644 --- a/src/model/Provider.ts +++ b/src/model/Provider.ts @@ -1,7 +1,8 @@ /* eslint no-unused-vars: "off" */ -import { PrimaryGeneratedColumn, Column, OneToMany, Entity, OneToOne } from 'typeorm'; +import { PrimaryGeneratedColumn, Column, OneToMany, Entity, OneToOne, ChildEntity } from 'typeorm'; import { ContactInformation } from './ContactInformation'; +import { ContactPerson } from './ContactPerson'; import { LendingStation } from './LendingStation'; import { Organization } from './Organization'; @@ -14,6 +15,11 @@ export class Address { @Column() zip: string; + + @Column({ + nullable: true + }) + city: string; } @Entity() @@ -21,19 +27,15 @@ export class Provider { @PrimaryGeneratedColumn() id: number; - @Column() - name: string; - @Column({ nullable: false }) formularName: String; - @Column(type => Address) - address: Address; - - @OneToMany(type => ContactInformation, contactInformation => contactInformation.provider) - contactInformation: ContactInformation[]; + @OneToMany(type => ContactPerson, contactPerson => contactPerson.provider, { + nullable: true + }) + contactPersons: ContactPerson[]; @Column() isPrivatePerson: boolean; diff --git a/src/model/Workshop.ts b/src/model/Workshop.ts index d4b6655..5c7d81e 100644 --- a/src/model/Workshop.ts +++ b/src/model/Workshop.ts @@ -7,7 +7,13 @@ export class Workshop { id: number; @Column() - name: string; + type: string; + + @Column() + title: string; + + @Column() + description: string; @Column({ type: 'date' diff --git a/src/resolvers/participantResolvers.ts b/src/resolvers/participantResolvers.ts new file mode 100644 index 0000000..083cf9d --- /dev/null +++ b/src/resolvers/participantResolvers.ts @@ -0,0 +1,19 @@ +import { GraphQLError } from 'graphql'; +import { Permission } from '../datasources/userserver/permission'; + +export default { + Query: { + participantById: (_: any, { id }: { id: any }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.ReadBike)) { + return dataSources.participantAPI.getParticipantById(id); + } else { + return new GraphQLError('Insufficient Permissions'); + } + } + }, + Participant: { + engagement (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) { + return dataSources.participantAPI.engagementByParticipantId(parent.id); + } + } +}; diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index 1323f8b..5562dd5 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -31,7 +31,7 @@ type CargoBike { bikeEvents: [BikeEvent] equipment: [Equipment] "Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2" - otherEquipment: [String] + miscellaneousEquipment: [String] chainSwaps: [ChainSwap] "Sticker State" stickerBikeNameState: StickerBikeNameState @@ -69,7 +69,7 @@ input CargoBikeCreateInput { """ dimensionsAndLoad: DimensionsAndLoadCreateInput! "Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2" - otherEquipment: [String] + miscellaneousEquipment: [String] "Sticker State" stickerBikeNameState: StickerBikeNameState @@ -103,7 +103,7 @@ input CargoBikeUpdateInput { """ dimensionsAndLoad: DimensionsAndLoadUpdateInput "Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2" - otherEquipment: [String] + miscellaneousEquipment: [String] lendingStationId: ID "Sticker State" stickerBikeNameState: StickerBikeNameState @@ -223,6 +223,13 @@ type Participant { """ distributedActiveBikeParte: Boolean! reserve: String + engagement: Engagement +} + +type Engagement { + id: ID! + participant: Participant + cargobike: CargoBike } type Taxes { @@ -449,7 +456,7 @@ type Provider { id: ID! name: String! formularName: String - address: Address + providerContactPerson: [ContactInformation] isPrivatePerson: Boolean! @@ -498,8 +505,28 @@ input ContactInformationUpdateInput { note: String } +type contactPerson { + id: ID! + intern: Boolean! + contactInformation: ContactInformation! +} + +input contactPersonCreateInput { + intern: Boolean! + contactInformationCreate: ContactInformationCreateInput + contactInformationExisting: ContactInformationUpdateInput +} + +input contactPersonUpdateInput { + id: ID! + intern: Boolean + contactInformationCreate: ContactInformationCreateInput + contactInformationExisting: ContactInformationUpdateInput +} + type Organisation { id: ID! + address: Address "(dt. Ausleihstation)" lendingStations: [LendingStation] "registration number of association" From 1830107f2b3998eea9c4406a4d1cef747ae79fd0 Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Mon, 21 Sep 2020 17:34:25 +0200 Subject: [PATCH 3/4] engagement and participant resolvers --- src/datasources/db/cargobikeAPI.ts | 16 ++- src/datasources/db/participantAPI.ts | 148 ++++++++++++++++++++++++-- src/model/ContactInformation.ts | 4 +- src/model/Engagement.ts | 8 +- src/model/Participant.ts | 18 +++- src/resolvers/cargobikeResolver.ts | 2 +- src/resolvers/participantResolvers.ts | 41 +++++++ src/schema/type-defs.ts | 71 ++++++++++-- 8 files changed, 281 insertions(+), 27 deletions(-) diff --git a/src/datasources/db/cargobikeAPI.ts b/src/datasources/db/cargobikeAPI.ts index bab71f0..13bb44c 100644 --- a/src/datasources/db/cargobikeAPI.ts +++ b/src/datasources/db/cargobikeAPI.ts @@ -4,6 +4,7 @@ import { CargoBike } from '../../model/CargoBike'; import { GraphQLError } from 'graphql'; import { BikeEvent } from '../../model/BikeEvent'; import { Equipment } from '../../model/Equipment'; +import { Engagement } from '../../model/Engagement'; /** * extended datasource to feed resolvers with data about cargoBikes @@ -29,7 +30,7 @@ export class CargoBikeAPI extends DataSource { * Finds cargo bike by id, retuns null if id was not found * @param param0 id of bike */ - async findCargoBikeById ({ id }:{id: any}) { + async findCargoBikeById (id: number) { return (await this.connection.manager.getRepository(CargoBike).findByIds([id], { relations: ['lendingStation'] }))[0]; /* .createQueryBuilder() .select('cargoBike') @@ -38,6 +39,15 @@ export class CargoBikeAPI extends DataSource { .getOne() || new GraphQLError('ID not found'); */ } + async findCargoBikeByEngagementId (id: number) { + return (await this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .leftJoinAndSelect('engagement.cargoBike', 'cargoBike') + .where('engagement."cargoBikeId" = "cargoBike".id') + .andWhere('engagement.id = :id', { id: id }) + .getOne())?.cargoBike; + } + /** * Updates CargoBike and return updated cargoBike * @param param0 cargoBike to be updated @@ -64,7 +74,7 @@ export class CargoBikeAPI extends DataSource { .of(cargoBike.id) .set(lendingStationId); } - return await this.findCargoBikeById({ id: bike.id }); + return await this.findCargoBikeById(bike.id); } else { return new GraphQLError('ID not in database'); } @@ -91,7 +101,7 @@ export class CargoBikeAPI extends DataSource { async createBikeEvent ({ bikeEvent }: { bikeEvent: any }) { const event = new BikeEvent(); event.setValues(bikeEvent); - event.cargoBike = await this.findCargoBikeById({ id: bikeEvent.cargoBikeId }) as unknown as CargoBike; + event.cargoBike = await this.findCargoBikeById(bikeEvent.cargoBikeId) as unknown as CargoBike; if (event.cargoBike instanceof GraphQLError) { return event.cargoBike; } diff --git a/src/datasources/db/participantAPI.ts b/src/datasources/db/participantAPI.ts index 65a8ae4..9521a1a 100644 --- a/src/datasources/db/participantAPI.ts +++ b/src/datasources/db/participantAPI.ts @@ -1,5 +1,10 @@ import { DataSource } from 'apollo-datasource'; +import { GraphQLBoolean, GraphQLError } from 'graphql'; import { Connection, getConnection } from 'typeorm'; +import { CargoBike } from '../../model/CargoBike'; +import { ContactInformation } from '../../model/ContactInformation'; +import { Engagement } from '../../model/Engagement'; +import { Participant } from '../../model/Participant'; export class ParticipantAPI extends DataSource { connection : Connection @@ -9,14 +14,145 @@ export class ParticipantAPI extends DataSource { } async getParticipantById (id: number) { - return { - id: 2 - }; + return await this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .select() + .where('participant.id = :id', { id: id }) + .getOne(); } + async getParticipants (offset: number, limit: number) { + return await this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .select() + .offset(offset) + .limit(limit) + .getMany(); + } + + async participantByEngagementId (id: number) { + return (await this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .leftJoinAndSelect('engagement.participant', 'participant') + .where('engagement.id = :id', { id: id }) + .andWhere('engagement."participantId" = participant.id') + .getOne()).participant; + } async engagementByParticipantId (id: number) { - return { - id: 3 - }; + return await this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .select() + .where('engagement."participantId" = :id', { id: id }) + .getOne(); + } + + async engagementById (id: number) { + return await this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .select() + .where('engagement.id = :id', { id: id }) + .getOne(); + } + + async contactInformationById (id: number) { + return await this.connection.getRepository(ContactInformation) + .createQueryBuilder('contactInformation') + .select() + .where('contactInformation.id = :id', { id: id }) + .getOne(); + } + + async contactInformationByParticipantId (id: number) { + const ret = (await this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .leftJoinAndSelect('participant.contactInformation', 'contactInformation') + .where('participant."contactInformationId" = "contactInformation".id') + .andWhere('participant.id = :id', { id: id }) + .printSql() + .getOne()); + return (ret) ? ret.contactInformation : null; + } + + /** + * creates participant and creates realtion to given contactInformation + * @param participant to be created + */ + async createParticipant (participant: any) { + let count = this.connection.getRepository(ContactInformation) + .createQueryBuilder('contactInformation') + .select() + .where('contactInformation.id = :id', { id: participant.contactInformationId }) + .getCount(); + if ((await count) !== 1) { + return new GraphQLError('contactInformationId not found.'); + } + count = this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .select() + .where('participant."contactInformationId" = :id', { + id: participant.contactInformationId + }) + .getCount(); + if ((await count) !== 0) { + return new GraphQLError('contactInformationId already used by other participant.'); + } + const inserts = await this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .insert() + .into(Participant) + .values([participant]) + .returning('*') + .execute(); + await this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .relation(Participant, 'contactInformation') + .of(inserts.identifiers[0].id) + .set(participant.contactInformationId); + return this.getParticipantById((await inserts).identifiers[0].id); + } + + async createContactInformation (contactInformation: any) { + const inserts = await this.connection.getRepository(ContactInformation) + .createQueryBuilder('contactInformation') + .insert() + .into(ContactInformation) + .values([contactInformation]) + .returning('*') + .execute(); + return this.contactInformationById(inserts.identifiers[0].id); + } + + async createEngagement (engagement: any) { + const countB = this.connection.getRepository(CargoBike) + .createQueryBuilder('cargoBike') + .select() + .where('cargoBike.id = :id', { id: engagement.cargoBikeId }) + .getCount(); + const countP = this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .select() + .where('participant.id = :id', { id: engagement.participantId }) + .getCount(); + if ((await countB) !== 1) { return new GraphQLError('BikeId not found'); } + if ((await countP) !== 1) { return new GraphQLError('ParticipantId not found'); } + // TODO check whether someone is already engaged with the bike + const inserts = await this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .insert() + .values([engagement]) + .returning('*') + .execute(); + this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .relation(Engagement, 'cargoBike') + .of(inserts.identifiers[0].id) + .set(engagement.cargoBikeId); + this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .relation(Engagement, 'participant') + .of(inserts.identifiers[0].id) + .set(engagement.participantId); + console.log(inserts); + return this.engagementById(inserts.identifiers[0].id); } } diff --git a/src/model/ContactInformation.ts b/src/model/ContactInformation.ts index d3578fb..3595bdb 100644 --- a/src/model/ContactInformation.ts +++ b/src/model/ContactInformation.ts @@ -47,6 +47,8 @@ export class ContactInformation { }) emailIntern: string; - @Column() + @Column({ + nullable: true + }) note: string; } diff --git a/src/model/Engagement.ts b/src/model/Engagement.ts index 236e913..6a9e0e1 100644 --- a/src/model/Engagement.ts +++ b/src/model/Engagement.ts @@ -1,4 +1,4 @@ -import { Entity, PrimaryGeneratedColumn, ManyToOne, Column } from 'typeorm'; +import { Entity, PrimaryGeneratedColumn, ManyToOne, Column, JoinColumn } from 'typeorm'; import { Participant } from './Participant'; import { CargoBike } from './CargoBike'; @@ -7,7 +7,11 @@ export class Engagement { @PrimaryGeneratedColumn() id: number; - @ManyToOne(type => Participant, participant => participant.engagement) + @ManyToOne(type => Participant, participant => participant.engagement, { + }) + @JoinColumn({ + name: 'participantId' + }) participant: Participant; @ManyToOne(type => CargoBike, cargoBike => cargoBike.engagement) diff --git a/src/model/Participant.ts b/src/model/Participant.ts index b0b4aca..9da9c57 100644 --- a/src/model/Participant.ts +++ b/src/model/Participant.ts @@ -20,14 +20,20 @@ export class Participant { }) end: Date; - @OneToOne(type => ContactInformation) + @OneToOne(type => ContactInformation, { + nullable: true + }) @JoinColumn() contactInformation: ContactInformation; - @Column() + @Column({ + nullable: true + }) usernameflotte: string; - @Column() + @Column({ + nullable: true + }) usernameSlack: string; @Column() @@ -53,12 +59,14 @@ export class Participant { memberCoreTeam: boolean; @Column({ - type: 'date' + type: 'date', + nullable: true }) workshopMentor: Date; @Column({ - type: 'date' + type: 'date', + nullable: true }) workshopAmbulance: Date; diff --git a/src/resolvers/cargobikeResolver.ts b/src/resolvers/cargobikeResolver.ts index 4ece04a..6383be4 100644 --- a/src/resolvers/cargobikeResolver.ts +++ b/src/resolvers/cargobikeResolver.ts @@ -5,7 +5,7 @@ export default { Query: { cargoBikeById: (_: any, { id }:{id: any}, { dataSources, req }:{dataSources: any, req: any }) => { if (req.permissions.includes(Permission.ReadBike)) { - return dataSources.cargoBikeAPI.findCargoBikeById({ id }); + return dataSources.cargoBikeAPI.findCargoBikeById(id); } else { return new GraphQLError('Insufficient Permissions'); } diff --git a/src/resolvers/participantResolvers.ts b/src/resolvers/participantResolvers.ts index 083cf9d..3172997 100644 --- a/src/resolvers/participantResolvers.ts +++ b/src/resolvers/participantResolvers.ts @@ -9,11 +9,52 @@ export default { } else { return new GraphQLError('Insufficient Permissions'); } + }, + participants: (_: any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.ReadBike)) { + return dataSources.participantAPI.getParticipants(offset, limit); + } else { + return new GraphQLError('Insufficient Permissions'); + } } }, Participant: { engagement (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) { return dataSources.participantAPI.engagementByParticipantId(parent.id); + }, + contactInformation (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) { + return (dataSources.participantAPI.contactInformationByParticipantId(parent.id)); + } + }, + Engagement: { + cargoBike (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) { + return dataSources.cargoBikeAPI.findCargoBikeByEngagementId(parent.id); + }, + participant (parent: any, _: any, { dataSources, req }: { dataSources: any, req: any }) { + return dataSources.participantAPI.participantByEngagementId(parent.id); + } + }, + Mutation: { + createParticipant: (_: any, { participant }: { participant: any }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.participantAPI.createParticipant(participant); + } else { + return new GraphQLError('Insufficient Permissions'); + } + }, + createContactInformation: (_: any, { contactInformation }: { contactInformation: any }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.participantAPI.createContactInformation(contactInformation); + } else { + return new GraphQLError('Insufficient Permissions'); + } + }, + createEngagement: (_: any, { engagement }: { engagement: any }, { dataSources, req }: { dataSources: any, req: any }) => { + if (req.permissions.includes(Permission.WriteBike)) { + return dataSources.participantAPI.createEngagement(engagement); + } else { + return new GraphQLError('Insufficient Permissions'); + } } } }; diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index 5562dd5..a2374f0 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -193,16 +193,16 @@ type BikeModel { technicalEquipment: TechnicalEquipment! } -type Participant { +type Participant { id: ID! start: Date! - end: Date! - mentor: ContactInformation! + end: Date + contactInformation: ContactInformation! usernamefLotte: String usernameSlack: String memberADFC: Boolean! locationZIPs: [String] - roleCoreTeam: Boolean! + memberCoreTeam: Boolean! roleCoordinator: Boolean! roleEmployeADFC: Boolean! """ @@ -223,13 +223,58 @@ type Participant { """ distributedActiveBikeParte: Boolean! reserve: String - engagement: Engagement + engagement: [Engagement] +} + +input ParticipantCreateInput { + start: Date! + end: Date + "must create contactinformation first, if you want to use new" + contactInformationId: ID! + usernamefLotte: String + usernameSlack: String + memberADFC: Boolean! + locationZIPs: [String] + memberCoreTeam: Boolean! + + "Date of workshop to become Mentor dt. Pate" + workshopMentor: Date + "Date of last Erste Hilfe Kurs?" + workshopAmbulance: Date + + reserve: String } + type Engagement { id: ID! + from: Date! + to: Date participant: Participant - cargobike: CargoBike + cargoBike: CargoBike + roleCoordinator: Boolean! + roleEmployeADFC: Boolean! + """ + Wahr, wenn die Person Pate ist. + """ + roleMentor: Boolean! + roleAmbulance: Boolean! + roleBringer: Boolean! +} + +input EngagementCreateInput { + from: Date! + to: Date + participantId: ID! + cargoBikeId: ID! + roleCoordinator: Boolean! + roleEmployeADFC: Boolean! + """ + Wahr, wenn die Person Pate ist. + """ + roleMentor: Boolean! + roleAmbulance: Boolean! + roleBringer: Boolean! } type Taxes { @@ -479,8 +524,8 @@ type ContactInformation { } input ContactInformationCreateInput { - name: String - firstName: String + name: String! + firstName: String! retiredAt: Date phoneExtern: String phone2Extern: String @@ -654,8 +699,10 @@ type Query { "equipment by id, will return null if id not found" equipmentById(id: ID!): Equipment providers: [Provider]! + "particcipant by id" participantById(id:ID!): Participant - participants: [ Participant]! + "p" + participants(offset: Int!, limit: Int!): [ Participant]! lendingStationById(id:ID!): LendingStation lendingStations: [LendingStation]! contactInformation: [ContactInformation]! @@ -678,6 +725,12 @@ type Mutation { updateLendingStation(lendingstation: LendingStationUpdateInput!): LendingStation! "creates new BikeEvent" createBikeEvent(bikeEvent: BikeEventCreateInput): BikeEvent! + "create participant" + createParticipant(participant: ParticipantCreateInput!): Participant! + "create new contactInfo" + createContactInformation(contactInformation: ContactInformationCreateInput!): ContactInformation! + "create Engagement" + createEngagement(engagement: EngagementCreateInput): Engagement! } `; From 35144d6e734f2244934c0405d2f42266299ae696 Mon Sep 17 00:00:00 2001 From: leonnicolas Date: Mon, 21 Sep 2020 19:04:58 +0200 Subject: [PATCH 4/4] added cargobike equipment resolvers --- src/datasources/db/cargobikeAPI.ts | 24 +++++++++++++++----- src/datasources/db/lendingstationAPI.ts | 1 - src/datasources/db/participantAPI.ts | 29 ++++++++++++++++++++++--- src/resolvers/cargobikeResolver.ts | 16 ++++++++++++++ src/schema/type-defs.ts | 4 ++-- 5 files changed, 63 insertions(+), 11 deletions(-) diff --git a/src/datasources/db/cargobikeAPI.ts b/src/datasources/db/cargobikeAPI.ts index 13bb44c..6b3ed2d 100644 --- a/src/datasources/db/cargobikeAPI.ts +++ b/src/datasources/db/cargobikeAPI.ts @@ -128,6 +128,7 @@ export class CargoBikeAPI extends DataSource { .getOne(); } + // think this can go async findEquipmentJoinBikeById (id: number) { return await this.connection.getRepository(Equipment) .createQueryBuilder('equipment') @@ -136,6 +137,14 @@ export class CargoBikeAPI extends DataSource { .getOne(); } + async equipmentByCargoBikeId (offset: number, limit: number, id: number) { + return await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .select() + .where('equipment."cargoBikeId" = :id', { id: id }) + .getMany(); + } + async createEquipment ({ equipment }: { equipment: any }) { const inserts = await this.connection.getRepository(Equipment) .createQueryBuilder('equipment') @@ -150,29 +159,34 @@ export class CargoBikeAPI extends DataSource { .relation(Equipment, 'cargoBike') .of(equipment.id) .set(equipment.cargoBikeId); - return this.findEquipmentJoinBikeById(inserts.identifiers[0].id); + // return this.findEquipmentJoinBikeById(inserts.identifiers[0].id); } return this.findEquipmentById(inserts.identifiers[0].id); } + async cargoBikeByEquipmentId (id: number) { + return (await this.connection.getRepository(Equipment) + .createQueryBuilder('equipment') + .leftJoinAndSelect('equipment.cargoBike', 'cargoBike') + .where('equipment.id = :id', { id: id }) + .getOne())?.cargoBike; + } + /** * Will update Equipment, crashes when id not in db or cargoBikeId not db. * 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 }) { - console.log(equipment); const cargoBikeId = equipment.cargoBikeId; delete equipment.cargoBikeId; - console.log(equipment); - const inserts = await this.connection.getRepository(Equipment) + await this.connection.getRepository(Equipment) .createQueryBuilder('equipment') .update() .set({ ...equipment }) .where('id = :id', { id: equipment.id }) .returning('*') .execute(); - console.log(inserts.raw[0]); if (cargoBikeId || cargoBikeId === null) { await this.connection.getRepository(Equipment) .createQueryBuilder() diff --git a/src/datasources/db/lendingstationAPI.ts b/src/datasources/db/lendingstationAPI.ts index 7658041..dc63848 100644 --- a/src/datasources/db/lendingstationAPI.ts +++ b/src/datasources/db/lendingstationAPI.ts @@ -34,7 +34,6 @@ export class LendingStationAPI extends DataSource { * @param param0 new lendingStation */ async createLendingStation ({ lendingStation }:{ lendingStation: any }) { - console.log(lendingStation); const inserts = await this.connection.manager .createQueryBuilder() .insert() diff --git a/src/datasources/db/participantAPI.ts b/src/datasources/db/participantAPI.ts index 9521a1a..5c4a320 100644 --- a/src/datasources/db/participantAPI.ts +++ b/src/datasources/db/participantAPI.ts @@ -1,5 +1,5 @@ import { DataSource } from 'apollo-datasource'; -import { GraphQLBoolean, GraphQLError } from 'graphql'; +import { GraphQLError } from 'graphql'; import { Connection, getConnection } from 'typeorm'; import { CargoBike } from '../../model/CargoBike'; import { ContactInformation } from '../../model/ContactInformation'; @@ -38,6 +38,16 @@ export class ParticipantAPI extends DataSource { .andWhere('engagement."participantId" = participant.id') .getOne()).participant; } + + async participantByCargoBikeId (id:number) { + return await this.connection.getRepository(Participant) + .createQueryBuilder('participant') + .leftJoinAndSelect('participant.cargoBike', 'cargoBike') + .where('"cargoBike".id = :id', { id: id }) + .andWhere('"cargoBike"."participantId" = participant.id') + .getOne(); + } + async engagementByParticipantId (id: number) { return await this.connection.getRepository(Engagement) .createQueryBuilder('engagement') @@ -46,6 +56,20 @@ export class ParticipantAPI extends DataSource { .getOne(); } + async engagementByCargoBikeId (offset: number, limit: number, id: number) { + return await this.connection.getRepository(Engagement) + .createQueryBuilder('engagement') + .select() + .where('engagement."cargoBikeId" = :id', { + id: id + }) + .offset(offset) + .limit(limit) + .orderBy('engagement.from', 'DESC') + .addOrderBy('engagement.to', 'DESC', 'NULLS FIRST') + .getMany(); + } + async engagementById (id: number) { return await this.connection.getRepository(Engagement) .createQueryBuilder('engagement') @@ -108,7 +132,7 @@ export class ParticipantAPI extends DataSource { .relation(Participant, 'contactInformation') .of(inserts.identifiers[0].id) .set(participant.contactInformationId); - return this.getParticipantById((await inserts).identifiers[0].id); + return this.getParticipantById(inserts.identifiers[0].id); } async createContactInformation (contactInformation: any) { @@ -152,7 +176,6 @@ export class ParticipantAPI extends DataSource { .relation(Engagement, 'participant') .of(inserts.identifiers[0].id) .set(engagement.participantId); - console.log(inserts); return this.engagementById(inserts.identifiers[0].id); } } diff --git a/src/resolvers/cargobikeResolver.ts b/src/resolvers/cargobikeResolver.ts index 6383be4..590753c 100644 --- a/src/resolvers/cargobikeResolver.ts +++ b/src/resolvers/cargobikeResolver.ts @@ -39,6 +39,22 @@ export default { } } }, + CargoBike: { + engagement (parent: any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) { + return dataSources.participantAPI.engagementByCargoBikeId(offset, limit, parent.id); + }, + coordinator (parent: any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) { + dataSources.participantAPI.participantByCargoBikeId(parent.id); + }, + equipment (parent: any, { offset, limit }: { offset: number, limit: number }, { dataSources, req }: { dataSources: any, req: any }) { + return dataSources.cargoBikeAPI.equipmentByCargoBikeId(offset, limit, parent.id); + } + }, + Equipment: { + cargoBike (parent: any, __: any, { dataSources, req }: { dataSources: any, req: any }) { + return dataSources.cargoBikeAPI.cargoBikeByEquipmentId(parent.id); + } + }, Mutation: { createCargoBike: (_: any, { cargoBike }: { cargoBike: any }, { dataSources, req }:{dataSources: any, req: any }) => { if (req.permissions.includes(Permission.WriteBike)) { diff --git a/src/schema/type-defs.ts b/src/schema/type-defs.ts index a2374f0..fdd6a1d 100644 --- a/src/schema/type-defs.ts +++ b/src/schema/type-defs.ts @@ -29,10 +29,9 @@ type CargoBike { """ dimensionsAndLoad: DimensionsAndLoad! bikeEvents: [BikeEvent] - equipment: [Equipment] + equipment(offset: Int!, limit: Int!): [Equipment] "Refers to equipment that is not unique. See kommentierte info tabelle -> Fragen -> Frage 2" miscellaneousEquipment: [String] - chainSwaps: [ChainSwap] "Sticker State" stickerBikeNameState: StickerBikeNameState note: String @@ -41,6 +40,7 @@ type CargoBike { insuranceData: InsuranceData! lendingStation: LendingStation taxes: Taxes + engagement(offset: Int!, limit: Int!): [Engagement] "null if not locked by other user" lockedBy: ID lockedUntil: Date