Compare commits

...

39 Commits

Author SHA1 Message Date
becc277123 Merge branch 'feature/65-donor_controllers' of git.odit.services:lfk/backend into feature/65-donor_controllers 2021-01-02 18:19:51 +01:00
52cdd41ec8 Fixed not null constraint
ref #65
2021-01-02 18:19:45 +01:00
53548ba7a6 Fixed not null constraint
ref #56
2021-01-02 18:19:40 +01:00
1dc438beb2 Mitigated circular dependency (to be fixed)
ref #65
2021-01-02 18:12:18 +01:00
c9ba69792f Extended todo w/ issue link
ref #65
2021-01-02 17:07:17 +01:00
ab67e5f4aa Added basic runner updateing
ref #65
2021-01-02 16:55:27 +01:00
557608e318 Added everything for basic donor creation
ref #65
2021-01-02 16:51:33 +01:00
a83fedc9b8 Added first donor-specific errors
ref #65
2021-01-02 16:47:06 +01:00
61a17b198f Implemented basic donor deletion
ref #65
2021-01-02 16:45:01 +01:00
3df1db4ad8 Added the base logic for donor getters
ref #65
2021-01-02 16:42:55 +01:00
e46cfa0d77 Added donor response class
ref #65
2021-01-02 16:40:38 +01:00
4126d31a5e Added copy of runnerController with some stuff reanames for donors
ref #65
2021-01-02 16:38:07 +01:00
9d9549cdd4 Added new donor permission target
ref #65
2021-01-02 16:37:17 +01:00
eb40de6eb4 Removed legacy license txt file
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-31 18:05:21 +01:00
6efd09db73 new license file version [CI SKIP] 2020-12-31 17:02:56 +00:00
3f09e3d387 Merge pull request 'Automatic and manual license collection 📖' (#62) from feature/59-license_collection into dev
All checks were successful
continuous-integration/drone/push Build is passing
Reviewed-on: #62
closes #59
2020-12-31 17:02:08 +00:00
05868e0e00 Bumped license lib version
All checks were successful
continuous-integration/drone/pr Build is passing
ref #59
2020-12-31 18:00:46 +01:00
580a73f9a5 Switched to automatic license attribution generation via oss-attribution-generator
All checks were successful
continuous-integration/drone/pr Build is passing
#59
2020-12-31 15:14:51 +01:00
ab7110d49f Merge branch 'dev' into feature/59-license_collection
All checks were successful
continuous-integration/drone/pr Build is passing
# Conflicts:
#	.drone.yml
2020-12-30 21:26:07 +01:00
875781335c Removed the testing pipeline and updated the dev license pipeline
ref #59
2020-12-30 21:24:51 +01:00
625340cf8a Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection
All checks were successful
continuous-integration/drone/push Build is passing
2020-12-30 21:23:37 +01:00
8d9dbc3957 Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection 2020-12-30 21:23:33 +01:00
07d813082b Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection 2020-12-30 21:23:04 +01:00
a684f60252 Added secondary dependency for piupeline
ref #59
2020-12-30 21:22:59 +01:00
931cae3c98 new license file version [CI SKIP] 2020-12-30 20:22:35 +00:00
dfd82a6293 Merge branch 'feature/59-license_collection' of git.odit.services:lfk/backend into feature/59-license_collection
All checks were successful
continuous-integration/drone/push Build is passing
# Conflicts:
#	.drone.yml
2020-12-30 21:21:50 +01:00
82d4b11de3 Adjusted ci dependencies
ref #59
2020-12-30 21:21:40 +01:00
75473937cf Adjusted ci dependencies
ref #59
2020-12-30 21:21:08 +01:00
a68bbab8ab Canged drone branch
All checks were successful
continuous-integration/drone/push Build is passing
ref #59
2020-12-30 21:18:40 +01:00
5cfd2c9a52 Revert "Added license exporter (to json)"
All checks were successful
continuous-integration/drone/push Build is passing
This reverts commit 84a0bd2cd9.
2020-12-30 21:17:27 +01:00
6c7b31d76c Revert "Moved package script related files to their own folder"
This reverts commit 395b0101a8.
2020-12-30 21:17:23 +01:00
2924ac2900 Revert "Added automatic license export on dev push/merge"
This reverts commit 18e3ef9a79.
2020-12-30 21:17:18 +01:00
a501625dd6 Revert "Added --full option for the license exporter to export the license path and text as well"
This reverts commit 62c7f26540.
2020-12-30 21:17:13 +01:00
cc64ce4498 Revert "Added test pipeline for automatic license export"
This reverts commit c9378e6cae.
2020-12-30 21:17:09 +01:00
c9378e6cae Added test pipeline for automatic license export
All checks were successful
continuous-integration/drone/push Build is passing
ref #59
2020-12-30 21:13:32 +01:00
62c7f26540 Added --full option for the license exporter to export the license path and text as well
ref #59
2020-12-30 21:05:16 +01:00
18e3ef9a79 Added automatic license export on dev push/merge
ref #59
2020-12-30 20:40:28 +01:00
395b0101a8 Moved package script related files to their own folder
ref #59
2020-12-30 20:22:18 +01:00
84a0bd2cd9 Added license exporter (to json)
ref #59
2020-12-30 20:18:28 +01:00
21 changed files with 6963 additions and 43 deletions

View File

@@ -37,11 +37,23 @@ steps:
tags:
- dev
registry: registry.odit.services
when:
branch:
- dev
event:
- push
- name: run full license export
depends_on: ["clone"]
image: node:alpine
commands:
- yarn
- yarn licenses:export
- name: push new licenses file to repo
depends_on: ["run full license export"]
image: appleboy/drone-git-push
settings:
branch: dev
commit: true
commit_message: new license file version [CI SKIP]
author_email: bot@odit.services
remote: git@git.odit.services:lfk/backend.git
ssh_key:
from_secret: GITLAB_SSHKEY
trigger:
branch:

3
.gitignore vendored
View File

@@ -133,4 +133,5 @@ build
*.sqlite
*.sqlite-jurnal
/docs
lib
lib
/oss-attribution

1296
licenses.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -48,6 +48,7 @@
"validator": "^13.5.2"
},
"devDependencies": {
"@odit/license-exporter": "^0.0.6",
"@types/cors": "^2.8.8",
"@types/csvtojson": "^1.1.5",
"@types/express": "^4.17.9",
@@ -74,7 +75,8 @@
"test:watch": "jest --watchAll",
"test:ci": "start-server-and-test dev http://localhost:4010/api/docs/openapi.json test",
"seed": "ts-node ./node_modules/typeorm/cli.js schema:sync && ts-node ./node_modules/typeorm-seeding/dist/cli.js seed",
"openapi:export": "ts-node src/openapi_export.ts"
"openapi:export": "node scripts/openapi_export.js",
"licenses:export": "license-exporter --md"
},
"nodemonConfig": {
"ignore": [

View File

@@ -4,9 +4,9 @@ import fs from "fs";
import "reflect-metadata";
import { createExpressServer, getMetadataArgsStorage } from "routing-controllers";
import { routingControllersToSpec } from 'routing-controllers-openapi';
import { config } from './config';
import authchecker from "./middlewares/authchecker";
import { ErrorHandler } from './middlewares/ErrorHandler';
import { config } from '../src/config';
import authchecker from "../src/middlewares/authchecker";
import { ErrorHandler } from '../src/middlewares/ErrorHandler';
const CONTROLLERS_FILE_EXTENSION = process.env.NODE_ENV === 'production' ? 'js' : 'ts';
createExpressServer({

View File

@@ -0,0 +1,105 @@
import { Authorized, Body, Delete, Get, JsonController, OnUndefined, Param, Post, Put, QueryParam } from 'routing-controllers';
import { OpenAPI, ResponseSchema } from 'routing-controllers-openapi';
import { getConnectionManager, Repository } from 'typeorm';
import { DonorIdsNotMatchingError, DonorNotFoundError } from '../errors/DonorErrors';
import { CreateDonor } from '../models/actions/CreateDonor';
import { UpdateDonor } from '../models/actions/UpdateDonor';
import { Donor } from '../models/entities/Donor';
import { ResponseDonor } from '../models/responses/ResponseDonor';
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
@JsonController('/donors')
@OpenAPI({ security: [{ "AuthToken": [] }, { "RefreshTokenCookie": [] }] })
export class DonorController {
private donorRepository: Repository<Donor>;
/**
* Gets the repository of this controller's model/entity.
*/
constructor() {
this.donorRepository = getConnectionManager().get().getRepository(Donor);
}
@Get()
@Authorized("DONOR:GET")
@ResponseSchema(ResponseDonor, { isArray: true })
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
async getAll() {
let responseDonors: ResponseDonor[] = new Array<ResponseDonor>();
const donors = await this.donorRepository.find();
donors.forEach(donor => {
responseDonors.push(new ResponseDonor(donor));
});
return responseDonors;
}
@Get('/:id')
@Authorized("DONOR:GET")
@ResponseSchema(ResponseDonor)
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@OnUndefined(DonorNotFoundError)
@OpenAPI({ description: 'Lists all information about the runner whose id got provided.' })
async getOne(@Param('id') id: number) {
let donor = await this.donorRepository.findOne({ id: id })
if (!donor) { throw new DonorNotFoundError(); }
return new ResponseDonor(donor);
}
@Post()
@Authorized("DONOR:CREATE")
@ResponseSchema(ResponseDonor)
@OpenAPI({ description: 'Create a new runner. <br> Please remeber to provide the runner\'s group\'s id.' })
async post(@Body({ validate: true }) createRunner: CreateDonor) {
let donor;
try {
donor = await createRunner.toDonor();
} catch (error) {
throw error;
}
donor = await this.donorRepository.save(donor)
return new ResponseDonor(await this.donorRepository.findOne(donor));
}
@Put('/:id')
@Authorized("DONOR:UPDATE")
@ResponseSchema(ResponseDonor)
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
@ResponseSchema(DonorIdsNotMatchingError, { statusCode: 406 })
@OpenAPI({ description: "Update the runner whose id you provided. <br> Please remember that ids can't be changed." })
async put(@Param('id') id: number, @Body({ validate: true }) donor: UpdateDonor) {
let oldDonor = await this.donorRepository.findOne({ id: id });
if (!oldDonor) {
throw new DonorNotFoundError();
}
if (oldDonor.id != donor.id) {
throw new DonorIdsNotMatchingError();
}
await this.donorRepository.save(await donor.updateDonor(oldDonor));
return new ResponseDonor(await this.donorRepository.findOne({ id: id }));
}
@Delete('/:id')
@Authorized("DONOR:DELETE")
@ResponseSchema(ResponseDonor)
@ResponseSchema(ResponseEmpty, { statusCode: 204 })
@OnUndefined(204)
@OpenAPI({ description: 'Delete the runner whose id you provided. <br> If no runner with this id exists it will just return 204(no content).' })
async remove(@Param("id") id: number, @QueryParam("force") force: boolean) {
let donor = await this.donorRepository.findOne({ id: id });
if (!donor) { return null; }
const responseDonor = await this.donorRepository.findOne(donor);
if (!donor) {
throw new DonorNotFoundError();
}
//TODO: DELETE DONATIONS AND WARN FOR FORCE (https://git.odit.services/lfk/backend/issues/66)
await this.donorRepository.delete(donor);
return new ResponseDonor(responseDonor);
}
}

25
src/errors/DonorErrors.ts Normal file
View File

@@ -0,0 +1,25 @@
import { IsString } from 'class-validator';
import { NotAcceptableError, NotFoundError } from 'routing-controllers';
/**
* Error to throw when a donor couldn't be found.
*/
export class DonorNotFoundError extends NotFoundError {
@IsString()
name = "DonorNotFoundError"
@IsString()
message = "Donor not found!"
}
/**
* Error to throw when two donors' ids don't match.
* Usually occurs when a user tries to change a donor's id.
*/
export class DonorIdsNotMatchingError extends NotAcceptableError {
@IsString()
name = "DonorIdsNotMatchingError"
@IsString()
message = "The ids don't match! \n And if you wanted to change a donor's id: This isn't allowed!"
}

View File

@@ -0,0 +1,33 @@
import { IsBoolean, IsOptional } from 'class-validator';
import { Donor } from '../entities/Donor';
import { CreateParticipant } from './CreateParticipant';
/**
* This classed is used to create a new Donor entity from a json body (post request).
*/
export class CreateDonor extends CreateParticipant {
/**
* Does this donor need a receipt?
*/
@IsBoolean()
@IsOptional()
receiptNeeded?: boolean = false;
/**
* Creates a new Donor entity from this.
*/
public async toDonor(): Promise<Donor> {
let newDonor: Donor = new Donor();
newDonor.firstname = this.firstname;
newDonor.middlename = this.middlename;
newDonor.lastname = this.lastname;
newDonor.phone = this.phone;
newDonor.email = this.email;
newDonor.receiptNeeded = this.receiptNeeded;
newDonor.address = await this.getAddress();
return newDonor;
}
}

View File

@@ -41,7 +41,7 @@ export class CreateRunnerOrganisation extends CreateRunnerGroup {
newRunnerOrganisation.name = this.name;
newRunnerOrganisation.contact = await this.getContact();
newRunnerOrganisation.address = await this.getAddress();
// newRunnerOrganisation.address = await this.getAddress();
return newRunnerOrganisation;
}

View File

@@ -0,0 +1,39 @@
import { IsBoolean, IsInt, IsOptional } from 'class-validator';
import { Donor } from '../entities/Donor';
import { CreateParticipant } from './CreateParticipant';
/**
* This class is used to update a Donor entity (via put request).
*/
export class UpdateDonor extends CreateParticipant {
/**
* The updated donor's id.
* This shouldn't have changed but it is here in case anyone ever wants to enable id changes (whyever they would want to).
*/
@IsInt()
id: number;
/**
* Does the updated donor need a receipt?
*/
@IsBoolean()
@IsOptional()
receiptNeeded?: boolean;
/**
* Updates a provided Donor entity based on this.
*/
public async updateDonor(donor: Donor): Promise<Donor> {
donor.firstname = this.firstname;
donor.middlename = this.middlename;
donor.lastname = this.lastname;
donor.phone = this.phone;
donor.email = this.email;
donor.receiptNeeded = this.receiptNeeded;
donor.address = await this.getAddress();
return donor;
}
}

View File

@@ -45,7 +45,7 @@ export class UpdateRunnerOrganisation extends CreateRunnerGroup {
organisation.name = this.name;
organisation.contact = await this.getContact();
organisation.address = await this.getAddress();
// organisation.address = await this.getAddress();
return organisation;
}

View File

@@ -8,7 +8,6 @@ import {
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { config } from '../../config';
import { Participant } from "./Participant";
import { RunnerOrganisation } from "./RunnerOrganisation";
/**
* Defines the Address entity.
@@ -82,9 +81,9 @@ export class Address {
@OneToMany(() => Participant, participant => participant.address, { nullable: true })
participants: Participant[];
/**
* Used to link the address to runner groups.
*/
@OneToMany(() => RunnerOrganisation, group => group.address, { nullable: true })
groups: RunnerOrganisation[];
// /**
// * Used to link the address to runner groups.
// */
// @OneToMany(() => RunnerOrganisation, group => group.address, { nullable: true })
// groups: RunnerOrganisation[];
}

View File

@@ -3,7 +3,7 @@ import {
IsNotEmpty
} from "class-validator";
import { Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
import { Participant } from "./Participant";
import { Donor } from './Donor';
/**
* Defines the Donation entity.
@@ -24,8 +24,8 @@ export abstract class Donation {
* The donations's donor.
*/
@IsNotEmpty()
@ManyToOne(() => Participant, donor => donor.donations)
donor: Participant;
@ManyToOne(() => Donor, donor => donor.donations)
donor: Donor;
/**
* The donation's amount in cents (or whatever your currency's smallest unit is.).

View File

@@ -1,5 +1,6 @@
import { IsBoolean } from "class-validator";
import { ChildEntity, Column } from "typeorm";
import { ChildEntity, Column, OneToMany } from "typeorm";
import { Donation } from './Donation';
import { Participant } from "./Participant";
/**
@@ -14,4 +15,11 @@ export class Donor extends Participant {
@Column()
@IsBoolean()
receiptNeeded: boolean = false;
/**
* Used to link the participant as the donor of a donation.
* Attention: Only runner's can be associated as a distanceDonations distance source.
*/
@OneToMany(() => Donation, donation => donation.donor, { nullable: true })
donations: Donation[];
}

View File

@@ -7,10 +7,9 @@ import {
IsString
} from "class-validator";
import { Column, Entity, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
import { config } from '../../config';
import { Address } from "./Address";
import { Donation } from "./Donation";
/**
* Defines the Participant entity.
@@ -74,11 +73,4 @@ export abstract class Participant {
@IsOptional()
@IsEmail()
email?: string;
/**
* Used to link the participant as the donor of a donation.
* Attention: Only runner's can be associated as a distanceDonations distance source.
*/
@OneToMany(() => Donation, donation => donation.donor, { nullable: true })
donations: Donation[];
}

View File

@@ -18,7 +18,7 @@ export class Runner extends Participant {
* Can be a runner team or organisation.
*/
@IsNotEmpty()
@ManyToOne(() => RunnerGroup, group => group.runners, { nullable: false })
@ManyToOne(() => RunnerGroup, group => group.runners)
group: RunnerGroup;
/**

View File

@@ -1,6 +1,5 @@
import { IsInt, IsOptional } from "class-validator";
import { ChildEntity, ManyToOne, OneToMany } from "typeorm";
import { Address } from "./Address";
import { IsInt } from "class-validator";
import { ChildEntity, OneToMany } from "typeorm";
import { Runner } from './Runner';
import { RunnerGroup } from "./RunnerGroup";
import { RunnerTeam } from "./RunnerTeam";
@@ -12,12 +11,12 @@ import { RunnerTeam } from "./RunnerTeam";
@ChildEntity()
export class RunnerOrganisation extends RunnerGroup {
/**
* The organisations's address.
*/
@IsOptional()
@ManyToOne(() => Address, address => address.groups, { nullable: true })
address?: Address;
// /**
// * The organisations's address.
// */
// @IsOptional()
// @ManyToOne(() => Address, address => address.groups, { nullable: true })
// address?: Address;
/**
* The organisation's teams.

View File

@@ -9,5 +9,6 @@ export enum PermissionTarget {
USER = 'USER',
USERGROUP = 'USERGROUP',
PERMISSION = 'PERMISSION',
STATSCLIENT = 'STATSCLIENT'
STATSCLIENT = 'STATSCLIENT',
DONOR = 'DONOR'
}

View File

@@ -0,0 +1,26 @@
import {
IsBoolean
} from "class-validator";
import { Donor } from '../entities/Donor';
import { ResponseParticipant } from './ResponseParticipant';
/**
* Defines the donor response.
*/
export class ResponseDonor extends ResponseParticipant {
/**
* Does this donor need a receipt?
*/
@IsBoolean()
receiptNeeded: boolean;
/**
* Creates a ResponseRunner object from a runner.
* @param runner The user the response shall be build for.
*/
public constructor(donor: Donor) {
super(donor);
this.receiptNeeded = donor.receiptNeeded;
}
}

View File

@@ -32,7 +32,7 @@ export class ResponseRunnerOrganisation extends ResponseRunnerGroup {
*/
public constructor(org: RunnerOrganisation) {
super(org);
this.address = org.address;
// this.address = org.address;
this.teams = org.teams;
}
}

5382
tmp.json Normal file

File diff suppressed because it is too large Load Diff