Merge pull request #34 from fLotte-meets-HWR-DB/dev

Dev
main
leonnicolas 4 years ago committed by GitHub
commit 111a5d8f6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -1,5 +1,4 @@
FROM node:14.14.0-alpine3.10 AS builder
RUN npm --version
WORKDIR /
COPY ./src /src

@ -56,6 +56,7 @@ import { ActionLog } from './model/ActionLog';
import actionLogResolvers from './resolvers/actionLogResolvers';
import { ActionLogAPI } from './datasources/db/actionLogAPI';
import bodyParser from 'body-parser';
import { CopyConfig } from './model/CopyConfig';
const cors = require('cors');
require('dotenv').config();
@ -83,7 +84,8 @@ export function getConnectionOptions (): ConnectionOptions {
Workshop,
Person,
WorkshopType,
ActionLog
ActionLog,
CopyConfig
],
synchronize: true,
logging: false
@ -127,8 +129,12 @@ export async function getApp (connOptions: ConnectionOptions) {
}
}
let cargoBikeAPI: CargoBikeAPI;
try {
await createConnection(connOptions);
// init copy config
cargoBikeAPI = new CargoBikeAPI();
await cargoBikeAPI.populateCopyConfig();
} catch (err) {
console.error(err);
}
@ -145,7 +151,7 @@ export async function getApp (connOptions: ConnectionOptions) {
],
typeDefs,
dataSources: () => ({
cargoBikeAPI: new CargoBikeAPI(),
cargoBikeAPI: cargoBikeAPI,
lendingStationAPI: new LendingStationAPI(),
participantAPI: new ParticipantAPI(),
contactInformationAPI: new ContactInformationAPI(),

@ -18,6 +18,7 @@ This file is part of fLotte-API-Server.
*/
import { DataSource } from 'apollo-datasource';
import { ApolloError } from 'apollo-server-express';
import { Connection, EntityManager, getConnection } from 'typeorm';
import { CargoBike } from '../../model/CargoBike';
import { BikeEvent } from '../../model/BikeEvent';
@ -31,6 +32,7 @@ import { BikeEventType } from '../../model/BikeEventType';
import { Actions } from '../../model/ActionLog';
import { ResourceLockedError } from '../../errors/ResourceLockedError';
import { NotFoundError } from '../../errors/NotFoundError';
import { CopyConfig } from '../../model/CopyConfig';
/**
* extended datasource to feed resolvers with data about cargoBikes
@ -42,6 +44,55 @@ export class CargoBikeAPI extends DataSource {
this.connection = getConnection();
}
private async addCopyConfig (key: string, value: boolean) {
return await this.connection.getRepository(CopyConfig)
.createQueryBuilder('cc')
.insert()
.values([{ key, value }])
.execute();
}
/**
* populate CopyConfig with default values
*/
async populateCopyConfig () {
if (await this.connection.getRepository(CopyConfig)
.createQueryBuilder('cc')
.select()
.getCount() === 0) {
const config: CopyConfig[] = [
{ key: 'id', value: false },
{ key: 'group', value: true },
{ key: 'name', value: true },
{ key: 'state', value: true },
{ key: 'equipmentIds', value: false },
{ key: 'equipmentTypeIds', value: false },
{ key: 'security', value: false },
{ key: 'stickerBikeNameState', value: true },
{ key: 'note', value: true },
{ key: 'providerId', value: false },
{ key: 'bikeEvents', value: false },
{ key: 'insuranceData', value: true },
{ key: 'timeFrames', value: false },
{ key: 'engagement', value: false },
{ key: 'taxes', value: true },
{ key: 'description', value: true },
{ key: 'modelName', value: true },
{ key: 'numberOfWheels', value: true },
{ key: 'forCargo', value: true },
{ key: 'forChildren', value: true },
{ key: 'numberOfChildren', value: true },
{ key: 'technicalEquipment', value: true },
{ key: 'dimensionsAndLoad', value: true }
];
await this.connection.getRepository(CopyConfig)
.createQueryBuilder('cc')
.insert()
.values(config)
.execute();
}
}
async getCargoBikes (offset?: number, limit?: number) {
return await DBUtils.getAllEntity(this.connection, CargoBike, 'cb', offset, limit);
}
@ -50,12 +101,14 @@ export class CargoBikeAPI extends DataSource {
* Finds cargo bike by id, returns null if id was not found
* @param id
*/
async findCargoBikeById (id: number) {
async findCargoBikeById (id: number) : Promise<CargoBike> {
return await this.connection.getRepository(CargoBike)
.createQueryBuilder('cb')
.select()
.where('id = :id', { id })
.getOne();
.getOne().catch(() => {
throw new NotFoundError('CargoBike', 'id', id);
});
}
async findCargoBikeByEngagementId (id: number) {
@ -498,4 +551,38 @@ export class CargoBikeAPI extends DataSource {
.of(id)
.loadMany();
}
async copyCargoBikeById (id: number) {
// load keys
const keys = await this.connection.getRepository(CopyConfig)
.createQueryBuilder('cc')
.select()
.getMany();
const cargoBike: any = await this.findCargoBikeById(id);
keys.forEach(value => {
if (value.value === false && value.key !== 'id') {
delete cargoBike[value.key];
}
});
return cargoBike;
}
async editCopyConfig (key: string, value: boolean) : Promise<boolean> {
return await this.connection.getRepository(CopyConfig)
.createQueryBuilder('cc')
.update()
.set({ value: value })
.where('key = :key', { key: key })
.returning('*')
.execute().then((v) => {
if (v.affected !== 1) {
throw new NotFoundError('CopyConfig', 'key', key);
} else {
return true;
}
},
(e) => {
throw new ApolloError(e);
});
}
}

@ -61,7 +61,8 @@ export enum Permission {
DeleteWorkshopType = 'WORKSHOP_TYPE_DELETE',
DeleteEventType = 'EVENT_TYPE_DELETE',
DeleteEquipmentType = 'EQUIPMENT_TYPE_DELETE',
DeleteEngagementType = 'ENGAGEMENT_TYPE_DELETE'
DeleteEngagementType = 'ENGAGEMENT_TYPE_DELETE',
EditCopyConfig = 'EDIT_COPY_CONFIG'
}
// Permissions where the creation will be requested on startup
@ -237,5 +238,9 @@ export const requiredPermissions = [
{
name: Permission.DeleteEngagementType,
description: 'Allows to delete engagement types'
},
{
name: Permission.EditCopyConfig,
description: 'Allow to edit the copy config for cargo bikes'
}
];

@ -0,0 +1,34 @@
/*
Copyright (C) 2020 Leon Löchner
This file is part of fLotte-API-Server.
fLotte-API-Server is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
fLotte-API-Server is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with fLotte-API-Server. If not, see <https://www.gnu.org/licenses/>.
*/
/* eslint no-unused-vars: "off" */
import { Column, Entity, PrimaryColumn } from 'typeorm';
@Entity()
export class CopyConfig {
@PrimaryColumn()
key: string;
@Column({
type: 'boolean',
default: true
})
value: boolean;
}

@ -44,7 +44,7 @@ export class Participant implements Lockable {
@Column({
nullable: true
})
usernameflotte: string;
usernamefLotte: string;
@Column({
nullable: true

@ -51,7 +51,7 @@ export default {
throw new PermissionError();
}
},
bikeEventTypeByd: (_:any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
bikeEventTypeById: (_:any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.ReadBikeEvent)) {
return dataSources.cargoBikeAPI.bikeEventTypeById(id);
} else {
@ -92,6 +92,13 @@ export default {
} else {
throw new PermissionError();
}
},
copyCargoBikeById: (_:any, { id }: {id:number}, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.ReadBike)) {
return dataSources.cargoBikeAPI.copyCargoBikeById(id);
} else {
throw new PermissionError();
}
}
},
CargoBike: {
@ -395,6 +402,13 @@ export default {
} else {
throw new PermissionError();
}
},
editCopyConfig: (_: any, { key, value }: { key: string, value: boolean }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.EditCopyConfig)) {
return dataSources.cargoBikeAPI.editCopyConfig(key, value);
} else {
throw new PermissionError();
}
}
}
};

@ -25,7 +25,7 @@ export default {
Query: {
participantById: (_: any, { id }: { id: any }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.ReadParticipant)) {
return dataSources.participantAPI.getParticipantById(id);
return dataSources.participantAPI.participantById(id);
} else {
throw new PermissionError();
}
@ -119,6 +119,10 @@ export default {
isLockedByMe: (parent: any, __: any, { req }: { req: any }) => isLockedByMe(parent, { req }),
isLocked: (parent: any, __: any, { req }: { req: any }) => isLocked(parent, { req })
},
EngagementType: {
isLockedByMe: (parent: any, __: any, { req }: { req: any }) => isLockedByMe(parent, { req }),
isLocked: (parent: any, __: any, { req }: { req: any }) => isLocked(parent, { req })
},
Mutation: {
createParticipant: (_: any, { participant }: { participant: any }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteParticipant)) {
@ -136,7 +140,7 @@ export default {
},
unlockParticipant: (_: any, { id }: { id: number }, { dataSources, req }: { dataSources: any, req: any }) => {
if (req.permissions.includes(Permission.WriteParticipant)) {
return dataSources.participantAPI.unlockeParticipant(id, req.userId);
return dataSources.participantAPI.unlockParticipant(id, req.userId);
} else {
throw new PermissionError();
}

@ -35,6 +35,7 @@ export default gql`
The kind of currency depends on the database.
"""
scalar Money
scalar Link
"The CargoBike type is central to the graph. You could call it the root."
type CargoBike {
@ -667,7 +668,7 @@ export default gql`
"""
Path to documents
"""
documents: [String!]!
documents: [Link!]!
remark: String
isLocked: Boolean!
isLockedByMe: Boolean!
@ -686,7 +687,7 @@ export default gql`
"""
Path to documents
"""
documents: [String]
documents: [Link]
remark: String
}
@ -701,7 +702,7 @@ export default gql`
"""
Path to documents
"""
documents: [String]
documents: [Link]
remark: String
keepLock: Boolean
}
@ -1011,6 +1012,8 @@ export default gql`
type Query {
"Will (eventually) return all properties of cargo bike"
cargoBikeById(id:ID!): CargoBike
"copies cargoBike, the id of the copy needs to be delted by the front end. This function will not create a new entry in the data base"
copyCargoBikeById(id: ID!): CargoBike
"Returns cargoBikes ordered by name ascending. If offset or limit is not provided, both values are ignored."
cargoBikes(offset: Int, limit: Int): [CargoBike!]!
engagementById(id: ID!): Engagement
@ -1057,7 +1060,7 @@ export default gql`
persons(offset: Int, limit: Int): [Person!]
"If offset or limit is not provided, both values are ignored"
bikeEventTypes(offset: Int, limit: Int): [BikeEventType!]
bikeEventTypeByd(id: ID!): BikeEventType
bikeEventTypeById(id: ID!): BikeEventType
"If offset or limit is not provided, both values are ignored"
bikeEvents(offset: Int, limit: Int): [BikeEvent!]!
bikeEventById(id:ID!): BikeEvent
@ -1083,6 +1086,8 @@ export default gql`
updateCargoBike(cargoBike: CargoBikeUpdateInput!): CargoBike!
"true on success"
deleteCargoBike(id: ID!): Boolean!
"edit or add key value pair to copy config for cargo bikes"
editCopyConfig(key: String!, value: Boolean!): Boolean!
"""
EQUIPMENT
creates new peace of unique Equipment

Loading…
Cancel
Save