Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
7ac98229d1
|
|||
|
dd5b538783
|
|||
|
8e6d67428c
|
|||
|
7ffb7523aa
|
|||
|
f4bf309821
|
|||
|
02b1cb9904
|
|||
|
7697acff82
|
|||
|
bacfc437f9
|
|||
|
9875b4f392
|
|||
|
ce9b765b81
|
|||
|
2ab6e985e3
|
|||
|
d06f6a4407
|
|||
|
a50d72f2f5
|
|||
|
4723d9738e
|
|||
|
1a478bd784
|
|||
|
284cb0f8b3
|
|||
|
6e63c57936
|
|||
|
30b61db2c1
|
|||
|
8237d5f210
|
|||
|
03e0a29096
|
|||
|
a6afba93e2
|
|||
|
a41758cd9c
|
|||
|
d6755ed134
|
|||
|
599c75fc00
|
68
CHANGELOG.md
68
CHANGELOG.md
@@ -2,9 +2,77 @@
|
|||||||
|
|
||||||
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
All notable changes to this project will be documented in this file. Dates are displayed in UTC.
|
||||||
|
|
||||||
|
#### [1.4.1](https://git.odit.services/lfk/backend/compare/1.4.0...1.4.1)
|
||||||
|
|
||||||
|
- refactor(auth): Increased token timeouts to 24hrs/7days [`dd5b538`](https://git.odit.services/lfk/backend/commit/dd5b538783f9c806f0c883cd391754fb5c842ec8)
|
||||||
|
|
||||||
|
#### [1.4.0](https://git.odit.services/lfk/backend/compare/1.3.12...1.4.0)
|
||||||
|
|
||||||
|
> 28 April 2025
|
||||||
|
|
||||||
|
- feat(donations): Implement response type to indicate possible missing donor [`f4bf309`](https://git.odit.services/lfk/backend/commit/f4bf309821c140f2bc0ae8b6d96c7458fcc80978)
|
||||||
|
- wip [`9875b4f`](https://git.odit.services/lfk/backend/commit/9875b4f3926e04b502e7af64c17f54fd3c1d8e3e)
|
||||||
|
- refactor(donations): Make anon prepaid [`02b1cb9`](https://git.odit.services/lfk/backend/commit/02b1cb9904cc593faeac025ae302a8684f650f5e)
|
||||||
|
- chore(release): 1.4.0 [`8e6d674`](https://git.odit.services/lfk/backend/commit/8e6d67428c85b6ee504a379ff13a3a951f7b9543)
|
||||||
|
- fix(donations): Move donor over to the types that need it [`7697acf`](https://git.odit.services/lfk/backend/commit/7697acff82b23d0c05dbbd17fee6e70eb1b7061c)
|
||||||
|
|
||||||
|
#### [1.3.12](https://git.odit.services/lfk/backend/compare/1.3.11...1.3.12)
|
||||||
|
|
||||||
|
> 28 April 2025
|
||||||
|
|
||||||
|
- chore(release): 1.3.12 [`bacfc43`](https://git.odit.services/lfk/backend/commit/bacfc437f97cac6a20c32b79ae2d6391466f78a6)
|
||||||
|
- refactor: make Donation.donor optional [`2ab6e98`](https://git.odit.services/lfk/backend/commit/2ab6e985e356f0f3d8637d81630d191cc11b8806)
|
||||||
|
- refactor(config): improve consola error logs [`ce9b765`](https://git.odit.services/lfk/backend/commit/ce9b765b81b014623e79ce64d8d835f1f86cecf3)
|
||||||
|
|
||||||
|
#### [1.3.11](https://git.odit.services/lfk/backend/compare/1.3.10...1.3.11)
|
||||||
|
|
||||||
|
> 17 April 2025
|
||||||
|
|
||||||
|
- feat(RunnerController): add selfservice_links parameter to getRunners method [`a50d72f`](https://git.odit.services/lfk/backend/commit/a50d72f2f5281b8c28ca64a0970161a35a7af95a)
|
||||||
|
- chore(release): 1.3.11 [`d06f6a4`](https://git.odit.services/lfk/backend/commit/d06f6a44072971d1853411b255f9b49eb423b3a2)
|
||||||
|
|
||||||
|
#### [1.3.10](https://git.odit.services/lfk/backend/compare/1.3.9...1.3.10)
|
||||||
|
|
||||||
|
> 11 April 2025
|
||||||
|
|
||||||
|
- chore(release): 1.3.10 [`4723d97`](https://git.odit.services/lfk/backend/commit/4723d9738eacd63fb41f23c628fbe4181bd126de)
|
||||||
|
- feat(RunnerController.getAll): debug created_via query param filter [`1a478bd`](https://git.odit.services/lfk/backend/commit/1a478bd784e01b9d5a1c6635d1004a9535c9a0e9)
|
||||||
|
|
||||||
|
#### [1.3.9](https://git.odit.services/lfk/backend/compare/1.3.8...1.3.9)
|
||||||
|
|
||||||
|
> 9 April 2025
|
||||||
|
|
||||||
|
- feat(RunnerController.getAll): add created_via query param filter [`6e63c57`](https://git.odit.services/lfk/backend/commit/6e63c57936f06a29da5f1a94b1141d51b75df5f0)
|
||||||
|
- chore(release): 1.3.9 [`284cb0f`](https://git.odit.services/lfk/backend/commit/284cb0f8b3955d0d65c2b36d2ec427a39752ffe7)
|
||||||
|
|
||||||
|
#### [1.3.8](https://git.odit.services/lfk/backend/compare/1.3.7...1.3.8)
|
||||||
|
|
||||||
|
> 9 April 2025
|
||||||
|
|
||||||
|
- feat(RunnerCardController): putByCode [`8237d5f`](https://git.odit.services/lfk/backend/commit/8237d5f21067c0872a7eff7c8d1506edf44ec10c)
|
||||||
|
- chore(release): 1.3.8 [`30b61db`](https://git.odit.services/lfk/backend/commit/30b61db2c160c019bac381f26cefdc6524ea465e)
|
||||||
|
|
||||||
|
#### [1.3.7](https://git.odit.services/lfk/backend/compare/1.3.6...1.3.7)
|
||||||
|
|
||||||
|
> 8 April 2025
|
||||||
|
|
||||||
|
- feat(stats): Publish runners by kiosk stat [`a6afba9`](https://git.odit.services/lfk/backend/commit/a6afba93e243ca419c282a16cad023d06d864e0e)
|
||||||
|
- chore(release): 1.3.7 [`03e0a29`](https://git.odit.services/lfk/backend/commit/03e0a290965648579956ac1f8e8542c97a667ed8)
|
||||||
|
|
||||||
|
#### [1.3.6](https://git.odit.services/lfk/backend/compare/1.3.5...1.3.6)
|
||||||
|
|
||||||
|
> 8 April 2025
|
||||||
|
|
||||||
|
- chore(release): 1.3.6 [`a41758c`](https://git.odit.services/lfk/backend/commit/a41758cd9c83105c3a4b407744bafe2f0f6fb48a)
|
||||||
|
- feat(runners): Allow created via being set via api [`d6755ed`](https://git.odit.services/lfk/backend/commit/d6755ed134071df635bc9d5821ceb2396c0f1d22)
|
||||||
|
- fix(participant): Switch to correct type [`599c75f`](https://git.odit.services/lfk/backend/commit/599c75fc00217eaec3cc87c0de50d059bdde685f)
|
||||||
|
|
||||||
#### [1.3.5](https://git.odit.services/lfk/backend/compare/1.3.4...1.3.5)
|
#### [1.3.5](https://git.odit.services/lfk/backend/compare/1.3.4...1.3.5)
|
||||||
|
|
||||||
|
> 8 April 2025
|
||||||
|
|
||||||
- feat(runners): Generate selfservice urls on runner if requested or create/update/get single [`5415cd3`](https://git.odit.services/lfk/backend/commit/5415cd38a727e76632a01a4d2634a1777df5542c)
|
- feat(runners): Generate selfservice urls on runner if requested or create/update/get single [`5415cd3`](https://git.odit.services/lfk/backend/commit/5415cd38a727e76632a01a4d2634a1777df5542c)
|
||||||
|
- chore(release): 1.3.5 [`bb213f0`](https://git.odit.services/lfk/backend/commit/bb213f001eff2157abf8741128f624f9cc991afe)
|
||||||
|
|
||||||
#### [1.3.4](https://git.odit.services/lfk/backend/compare/1.3.3...1.3.4)
|
#### [1.3.4](https://git.odit.services/lfk/backend/compare/1.3.3...1.3.4)
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@odit/lfk-backend",
|
"name": "@odit/lfk-backend",
|
||||||
"version": "1.3.5",
|
"version": "1.4.1",
|
||||||
"main": "src/app.ts",
|
"main": "src/app.ts",
|
||||||
"repository": "https://git.odit.services/lfk/backend",
|
"repository": "https://git.odit.services/lfk/backend",
|
||||||
"author": {
|
"author": {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import consola from 'consola';
|
||||||
import { config as configDotenv } from 'dotenv';
|
import { config as configDotenv } from 'dotenv';
|
||||||
import { CountryCode } from 'libphonenumber-js';
|
import { CountryCode } from 'libphonenumber-js';
|
||||||
import ValidatorJS from 'validator';
|
import ValidatorJS from 'validator';
|
||||||
@@ -20,12 +21,15 @@ export const config = {
|
|||||||
}
|
}
|
||||||
let errors = 0
|
let errors = 0
|
||||||
if (typeof config.internal_port !== "number") {
|
if (typeof config.internal_port !== "number") {
|
||||||
|
consola.error("Error: APP_PORT is not a number")
|
||||||
errors++
|
errors++
|
||||||
}
|
}
|
||||||
if (typeof config.development !== "boolean") {
|
if (typeof config.development !== "boolean") {
|
||||||
|
consola.error("Error: NODE_ENV is not a boolean")
|
||||||
errors++
|
errors++
|
||||||
}
|
}
|
||||||
if (config.mailer_url == "" || config.mailer_key == "") {
|
if (config.mailer_url == "" || config.mailer_key == "") {
|
||||||
|
consola.error("Error: invalid mailer config")
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
function getPhoneCodeLocale(): CountryCode {
|
function getPhoneCodeLocale(): CountryCode {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { Repository, getConnectionManager } from 'typeorm';
|
|||||||
import { DonationIdsNotMatchingError, DonationNotFoundError } from '../errors/DonationErrors';
|
import { DonationIdsNotMatchingError, DonationNotFoundError } from '../errors/DonationErrors';
|
||||||
import { DonorNotFoundError } from '../errors/DonorErrors';
|
import { DonorNotFoundError } from '../errors/DonorErrors';
|
||||||
import { RunnerNotFoundError } from '../errors/RunnerErrors';
|
import { RunnerNotFoundError } from '../errors/RunnerErrors';
|
||||||
|
import { CreateAnonymousDonation } from '../models/actions/create/CreateAnonymousDonation';
|
||||||
import { CreateDistanceDonation } from '../models/actions/create/CreateDistanceDonation';
|
import { CreateDistanceDonation } from '../models/actions/create/CreateDistanceDonation';
|
||||||
import { CreateFixedDonation } from '../models/actions/create/CreateFixedDonation';
|
import { CreateFixedDonation } from '../models/actions/create/CreateFixedDonation';
|
||||||
import { UpdateDistanceDonation } from '../models/actions/update/UpdateDistanceDonation';
|
import { UpdateDistanceDonation } from '../models/actions/update/UpdateDistanceDonation';
|
||||||
@@ -11,6 +12,7 @@ import { UpdateFixedDonation } from '../models/actions/update/UpdateFixedDonatio
|
|||||||
import { DistanceDonation } from '../models/entities/DistanceDonation';
|
import { DistanceDonation } from '../models/entities/DistanceDonation';
|
||||||
import { Donation } from '../models/entities/Donation';
|
import { Donation } from '../models/entities/Donation';
|
||||||
import { FixedDonation } from '../models/entities/FixedDonation';
|
import { FixedDonation } from '../models/entities/FixedDonation';
|
||||||
|
import { ResponseAnonymousDonation } from '../models/responses/ResponseAnonymousDonation';
|
||||||
import { ResponseDistanceDonation } from '../models/responses/ResponseDistanceDonation';
|
import { ResponseDistanceDonation } from '../models/responses/ResponseDistanceDonation';
|
||||||
import { ResponseDonation } from '../models/responses/ResponseDonation';
|
import { ResponseDonation } from '../models/responses/ResponseDonation';
|
||||||
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
|
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
|
||||||
@@ -35,6 +37,7 @@ export class DonationController {
|
|||||||
@Authorized("DONATION:GET")
|
@Authorized("DONATION:GET")
|
||||||
@ResponseSchema(ResponseDonation, { isArray: true })
|
@ResponseSchema(ResponseDonation, { isArray: true })
|
||||||
@ResponseSchema(ResponseDistanceDonation, { isArray: true })
|
@ResponseSchema(ResponseDistanceDonation, { isArray: true })
|
||||||
|
@ResponseSchema(ResponseAnonymousDonation, { isArray: true })
|
||||||
@OpenAPI({ description: 'Lists all donations (fixed or distance based) from all donors. <br> This includes the donations\'s runner\'s distance ran(if distance donation).' })
|
@OpenAPI({ description: 'Lists all donations (fixed or distance based) from all donors. <br> This includes the donations\'s runner\'s distance ran(if distance donation).' })
|
||||||
async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
|
async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100) {
|
||||||
let responseDonations: ResponseDonation[] = new Array<ResponseDonation>();
|
let responseDonations: ResponseDonation[] = new Array<ResponseDonation>();
|
||||||
@@ -56,6 +59,7 @@ export class DonationController {
|
|||||||
@Authorized("DONATION:GET")
|
@Authorized("DONATION:GET")
|
||||||
@ResponseSchema(ResponseDonation)
|
@ResponseSchema(ResponseDonation)
|
||||||
@ResponseSchema(ResponseDistanceDonation)
|
@ResponseSchema(ResponseDistanceDonation)
|
||||||
|
@ResponseSchema(ResponseAnonymousDonation)
|
||||||
@ResponseSchema(DonationNotFoundError, { statusCode: 404 })
|
@ResponseSchema(DonationNotFoundError, { statusCode: 404 })
|
||||||
@OnUndefined(DonationNotFoundError)
|
@OnUndefined(DonationNotFoundError)
|
||||||
@OpenAPI({ description: 'Lists all information about the donation whose id got provided. This includes the donation\'s runner\'s distance ran (if distance donation).' })
|
@OpenAPI({ description: 'Lists all information about the donation whose id got provided. This includes the donation\'s runner\'s distance ran (if distance donation).' })
|
||||||
@@ -76,6 +80,17 @@ export class DonationController {
|
|||||||
return (await this.donationRepository.findOne({ id: donation.id }, { relations: ['donor'] })).toResponse();
|
return (await this.donationRepository.findOne({ id: donation.id }, { relations: ['donor'] })).toResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Post('/anonymous')
|
||||||
|
@Authorized("DONATION:CREATE")
|
||||||
|
@ResponseSchema(ResponseDonation)
|
||||||
|
@ResponseSchema(DonorNotFoundError, { statusCode: 404 })
|
||||||
|
@OpenAPI({ description: 'Create a anonymous donation' })
|
||||||
|
async postAnonymous(@Body({ validate: true }) createDonation: CreateAnonymousDonation) {
|
||||||
|
let donation = await createDonation.toEntity();
|
||||||
|
donation = await this.fixedDonationRepository.save(donation);
|
||||||
|
return (await this.donationRepository.findOne({ id: donation.id })).toResponse();
|
||||||
|
}
|
||||||
|
|
||||||
@Post('/distance')
|
@Post('/distance')
|
||||||
@Authorized("DONATION:CREATE")
|
@Authorized("DONATION:CREATE")
|
||||||
@ResponseSchema(ResponseDistanceDonation)
|
@ResponseSchema(ResponseDistanceDonation)
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { RunnerCardHasScansError, RunnerCardIdsNotMatchingError, RunnerCardNotFo
|
|||||||
import { RunnerNotFoundError } from '../errors/RunnerErrors';
|
import { RunnerNotFoundError } from '../errors/RunnerErrors';
|
||||||
import { CreateRunnerCard } from '../models/actions/create/CreateRunnerCard';
|
import { CreateRunnerCard } from '../models/actions/create/CreateRunnerCard';
|
||||||
import { UpdateRunnerCard } from '../models/actions/update/UpdateRunnerCard';
|
import { UpdateRunnerCard } from '../models/actions/update/UpdateRunnerCard';
|
||||||
|
import { UpdateRunnerCardByCode } from '../models/actions/update/UpdateRunnerCardByCode';
|
||||||
import { RunnerCard } from '../models/entities/RunnerCard';
|
import { RunnerCard } from '../models/entities/RunnerCard';
|
||||||
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
|
import { ResponseEmpty } from '../models/responses/ResponseEmpty';
|
||||||
import { ResponseRunnerCard } from '../models/responses/ResponseRunnerCard';
|
import { ResponseRunnerCard } from '../models/responses/ResponseRunnerCard';
|
||||||
@@ -112,6 +113,28 @@ export class RunnerCardController {
|
|||||||
return (await this.cardRepository.findOne({ id: id }, { relations: ['runner', 'runner.group', 'runner.group.parentGroup'] })).toResponse();
|
return (await this.cardRepository.findOne({ id: id }, { relations: ['runner', 'runner.group', 'runner.group.parentGroup'] })).toResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Put('/:code')
|
||||||
|
@Authorized("CARD:UPDATE")
|
||||||
|
@ResponseSchema(ResponseRunnerCard)
|
||||||
|
@ResponseSchema(RunnerCardNotFoundError, { statusCode: 404 })
|
||||||
|
@ResponseSchema(RunnerNotFoundError, { statusCode: 404 })
|
||||||
|
@ResponseSchema(RunnerCardIdsNotMatchingError, { statusCode: 406 })
|
||||||
|
@OpenAPI({ description: "Update the card whose code you provided." })
|
||||||
|
async putByCode(@Param('code') code: string, @Body({ validate: true }) card: UpdateRunnerCardByCode) {
|
||||||
|
let oldCard = await this.cardRepository.findOne({ code: code });
|
||||||
|
|
||||||
|
if (!oldCard) {
|
||||||
|
throw new RunnerCardNotFoundError();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (oldCard.code != card.code) {
|
||||||
|
throw new RunnerCardIdsNotMatchingError();
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.cardRepository.save(await card.update(oldCard));
|
||||||
|
return (await this.cardRepository.findOne({ code: code }, { relations: ['runner', 'runner.group', 'runner.group.parentGroup'] })).toResponse();
|
||||||
|
}
|
||||||
|
|
||||||
@Delete('/:id')
|
@Delete('/:id')
|
||||||
@Authorized("CARD:DELETE")
|
@Authorized("CARD:DELETE")
|
||||||
@ResponseSchema(ResponseRunnerCard)
|
@ResponseSchema(ResponseRunnerCard)
|
||||||
|
|||||||
@@ -30,10 +30,11 @@ export class RunnerController {
|
|||||||
@Authorized("RUNNER:GET")
|
@Authorized("RUNNER:GET")
|
||||||
@ResponseSchema(ResponseRunner, { isArray: true })
|
@ResponseSchema(ResponseRunner, { isArray: true })
|
||||||
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
|
@OpenAPI({ description: 'Lists all runners from all teams/orgs. <br> This includes the runner\'s group and distance ran.' })
|
||||||
async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100, @QueryParam("selfservice_links", { required: false }) selfservice_links: boolean = false) {
|
async getAll(@QueryParam("page", { required: false }) page: number, @QueryParam("page_size", { required: false }) page_size: number = 100, @QueryParam("created_via", { required: false }) created_via: string = "all", @QueryParam("selfservice_links", { required: false }) selfservice_links: boolean = false) {
|
||||||
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
|
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
|
||||||
let runners: Array<Runner>;
|
let runners: Array<Runner>;
|
||||||
|
|
||||||
|
console.log("call to RunnerController.getAll() with page: " + page + " and page_size: " + page_size + " and created_via: " + created_via + " and selfservice_links: " + selfservice_links);
|
||||||
if (page != undefined) {
|
if (page != undefined) {
|
||||||
runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track'], skip: page * page_size, take: page_size });
|
runners = await this.runnerRepository.find({ relations: ['scans', 'group', 'group.parentGroup', 'scans.track'], skip: page * page_size, take: page_size });
|
||||||
} else {
|
} else {
|
||||||
@@ -41,7 +42,13 @@ export class RunnerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
runners.forEach(runner => {
|
runners.forEach(runner => {
|
||||||
responseRunners.push(new ResponseRunner(runner, selfservice_links));
|
if (created_via === "all") {
|
||||||
|
responseRunners.push(new ResponseRunner(runner, selfservice_links));
|
||||||
|
} else {
|
||||||
|
if (runner.created_via === created_via) {
|
||||||
|
responseRunners.push(new ResponseRunner(runner, selfservice_links));
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return responseRunners;
|
return responseRunners;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ export class RunnerOrganizationController {
|
|||||||
@ResponseSchema(ResponseRunner, { isArray: true })
|
@ResponseSchema(ResponseRunner, { isArray: true })
|
||||||
@ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
|
@ResponseSchema(RunnerOrganizationNotFoundError, { statusCode: 404 })
|
||||||
@OpenAPI({ description: 'Lists all runners from this org and it\'s teams (if you don\'t provide the ?onlyDirect=true param). <br> This includes the runner\'s group and distance ran.' })
|
@OpenAPI({ description: 'Lists all runners from this org and it\'s teams (if you don\'t provide the ?onlyDirect=true param). <br> This includes the runner\'s group and distance ran.' })
|
||||||
async getRunners(@Param('id') id: number, @QueryParam('onlyDirect') onlyDirect: boolean) {
|
async getRunners(@Param('id') id: number, @QueryParam('onlyDirect') onlyDirect: boolean, @QueryParam("selfservice_links", { required: false }) selfservice_links: boolean = false) {
|
||||||
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
|
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
|
||||||
let runners: Runner[];
|
let runners: Runner[];
|
||||||
if (!onlyDirect) { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.group', 'teams.runners.group.parentGroup', 'teams.runners.scans', 'teams.runners.scans.track'] })).allRunners; }
|
if (!onlyDirect) { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track', 'teams', 'teams.runners', 'teams.runners.group', 'teams.runners.group.parentGroup', 'teams.runners.scans', 'teams.runners.scans.track'] })).allRunners; }
|
||||||
else { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners; }
|
else { runners = (await this.runnerOrganizationRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners; }
|
||||||
runners.forEach(runner => {
|
runners.forEach(runner => {
|
||||||
responseRunners.push(new ResponseRunner(runner));
|
responseRunners.push(new ResponseRunner(runner, selfservice_links));
|
||||||
});
|
});
|
||||||
return responseRunners;
|
return responseRunners;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,11 +60,11 @@ export class RunnerTeamController {
|
|||||||
@ResponseSchema(ResponseRunner, { isArray: true })
|
@ResponseSchema(ResponseRunner, { isArray: true })
|
||||||
@ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 })
|
@ResponseSchema(RunnerTeamNotFoundError, { statusCode: 404 })
|
||||||
@OpenAPI({ description: 'Lists all runners from this team. <br> This includes the runner\'s group and distance ran.' })
|
@OpenAPI({ description: 'Lists all runners from this team. <br> This includes the runner\'s group and distance ran.' })
|
||||||
async getRunners(@Param('id') id: number) {
|
async getRunners(@Param('id') id: number, @QueryParam("selfservice_links", { required: false }) selfservice_links: boolean = false) {
|
||||||
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
|
let responseRunners: ResponseRunner[] = new Array<ResponseRunner>();
|
||||||
const runners = (await this.runnerTeamRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners;
|
const runners = (await this.runnerTeamRepository.findOne({ id: id }, { relations: ['runners', 'runners.group', 'runners.group.parentGroup', 'runners.scans', 'runners.scans.track'] })).runners;
|
||||||
runners.forEach(runner => {
|
runners.forEach(runner => {
|
||||||
responseRunners.push(new ResponseRunner(runner));
|
responseRunners.push(new ResponseRunner(runner, selfservice_links));
|
||||||
});
|
});
|
||||||
return responseRunners;
|
return responseRunners;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ export class StatsController {
|
|||||||
async get() {
|
async get() {
|
||||||
const connection = getConnection();
|
const connection = getConnection();
|
||||||
const runnersViaSelfservice = await connection.getRepository(Runner).count({ where: { created_via: "selfservice" } });
|
const runnersViaSelfservice = await connection.getRepository(Runner).count({ where: { created_via: "selfservice" } });
|
||||||
|
const runnersViaKiosk = await connection.getRepository(Runner).count({ where: { created_via: "kiosk" } });
|
||||||
const runners = await connection.getRepository(Runner).count();
|
const runners = await connection.getRepository(Runner).count();
|
||||||
const teams = await connection.getRepository(RunnerTeam).count();
|
const teams = await connection.getRepository(RunnerTeam).count();
|
||||||
const orgs = await connection.getRepository(RunnerOrganization).count();
|
const orgs = await connection.getRepository(RunnerOrganization).count();
|
||||||
@@ -42,7 +43,7 @@ export class StatsController {
|
|||||||
let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] });
|
let donations = await connection.getRepository(Donation).find({ relations: ['runner', 'runner.scans', 'runner.scans.track'] });
|
||||||
const donors = await connection.getRepository(Donor).count();
|
const donors = await connection.getRepository(Donor).count();
|
||||||
|
|
||||||
return new ResponseStats(runnersViaSelfservice, runners, teams, orgs, users, scans, donations, distace, donors)
|
return new ResponseStats(runnersViaSelfservice, runners, teams, orgs, users, scans, donations, distace, donors, runnersViaKiosk)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Get("/runners/distance")
|
@Get("/runners/distance")
|
||||||
|
|||||||
29
src/models/actions/create/CreateAnonymousDonation.ts
Normal file
29
src/models/actions/create/CreateAnonymousDonation.ts
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
import { IsInt, IsPositive } from 'class-validator';
|
||||||
|
import { FixedDonation } from '../../entities/FixedDonation';
|
||||||
|
import { CreateDonation } from './CreateDonation';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to create a new FixedDonation entity from a json body (post request).
|
||||||
|
*/
|
||||||
|
export class CreateAnonymousDonation extends CreateDonation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's amount.
|
||||||
|
* The unit is your currency's smallest unit (default: euro cent).
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
@IsPositive()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new FixedDonation entity from this.
|
||||||
|
*/
|
||||||
|
public async toEntity(): Promise<FixedDonation> {
|
||||||
|
let newDonation = new FixedDonation;
|
||||||
|
|
||||||
|
newDonation.amount = this.amount;
|
||||||
|
newDonation.paidAmount = this.amount;
|
||||||
|
|
||||||
|
return newDonation;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -61,11 +61,11 @@ export class CreateAuth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Create the access token
|
//Create the access token
|
||||||
const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 5 * 60
|
const timestamp_accesstoken_expiry = Math.floor(Date.now() / 1000) + 24 * 60 * 60
|
||||||
newAuth.access_token = JwtCreator.createAccess(found_user, timestamp_accesstoken_expiry);
|
newAuth.access_token = JwtCreator.createAccess(found_user, timestamp_accesstoken_expiry);
|
||||||
newAuth.access_token_expires_at = timestamp_accesstoken_expiry
|
newAuth.access_token_expires_at = timestamp_accesstoken_expiry
|
||||||
//Create the refresh token
|
//Create the refresh token
|
||||||
const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 10 * 36000
|
const timestamp_refresh_expiry = Math.floor(Date.now() / 1000) + 7 * 24 * 60 * 60
|
||||||
newAuth.refresh_token = JwtCreator.createRefresh(found_user, timestamp_refresh_expiry);
|
newAuth.refresh_token = JwtCreator.createRefresh(found_user, timestamp_refresh_expiry);
|
||||||
newAuth.refresh_token_expires_at = timestamp_refresh_expiry
|
newAuth.refresh_token_expires_at = timestamp_refresh_expiry
|
||||||
return newAuth;
|
return newAuth;
|
||||||
|
|||||||
@@ -10,6 +10,20 @@ import { CreateDonation } from './CreateDonation';
|
|||||||
*/
|
*/
|
||||||
export class CreateDistanceDonation extends CreateDonation {
|
export class CreateDistanceDonation extends CreateDonation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's associated donor's id.
|
||||||
|
* This is important to link donations to donors.
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
@IsPositive()
|
||||||
|
donor: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's paid amount in the smalles unit of your currency (default: euro cent).
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
paidAmount?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The donation's associated runner's id.
|
* The donation's associated runner's id.
|
||||||
* This is important to link the runner's distance ran to the donation.
|
* This is important to link the runner's distance ran to the donation.
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { IsInt, IsOptional, IsPositive } from 'class-validator';
|
import { Exclude } from 'class-transformer';
|
||||||
import { getConnection } from 'typeorm';
|
import { getConnection } from 'typeorm';
|
||||||
import { DonorNotFoundError } from '../../../errors/DonorErrors';
|
|
||||||
import { Donation } from '../../entities/Donation';
|
import { Donation } from '../../entities/Donation';
|
||||||
import { Donor } from '../../entities/Donor';
|
import { Donor } from '../../entities/Donor';
|
||||||
|
|
||||||
@@ -8,19 +7,10 @@ import { Donor } from '../../entities/Donor';
|
|||||||
* This class is used to create a new Donation entity from a json body (post request).
|
* This class is used to create a new Donation entity from a json body (post request).
|
||||||
*/
|
*/
|
||||||
export abstract class CreateDonation {
|
export abstract class CreateDonation {
|
||||||
/**
|
@Exclude()
|
||||||
* The donation's associated donor's id.
|
|
||||||
* This is important to link donations to donors.
|
|
||||||
*/
|
|
||||||
@IsInt()
|
|
||||||
@IsPositive()
|
|
||||||
donor: number;
|
donor: number;
|
||||||
|
|
||||||
/**
|
@Exclude()
|
||||||
* The donation's paid amount in the smalles unit of your currency (default: euro cent).
|
|
||||||
*/
|
|
||||||
@IsInt()
|
|
||||||
@IsOptional()
|
|
||||||
paidAmount?: number;
|
paidAmount?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,9 +23,6 @@ export abstract class CreateDonation {
|
|||||||
*/
|
*/
|
||||||
public async getDonor(): Promise<Donor> {
|
public async getDonor(): Promise<Donor> {
|
||||||
const donor = await getConnection().getRepository(Donor).findOne({ id: this.donor });
|
const donor = await getConnection().getRepository(Donor).findOne({ id: this.donor });
|
||||||
if (!donor) {
|
|
||||||
throw new DonorNotFoundError();
|
|
||||||
}
|
|
||||||
return donor;
|
return donor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,21 @@ import { CreateDonation } from './CreateDonation';
|
|||||||
* This class is used to create a new FixedDonation entity from a json body (post request).
|
* This class is used to create a new FixedDonation entity from a json body (post request).
|
||||||
*/
|
*/
|
||||||
export class CreateFixedDonation extends CreateDonation {
|
export class CreateFixedDonation extends CreateDonation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's associated donor's id.
|
||||||
|
* This is important to link donations to donors.
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
@IsPositive()
|
||||||
|
donor: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's paid amount in the smalles unit of your currency (default: euro cent).
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
paidAmount?: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The donation's amount.
|
* The donation's amount.
|
||||||
* The unit is your currency's smallest unit (default: euro cent).
|
* The unit is your currency's smallest unit (default: euro cent).
|
||||||
|
|||||||
@@ -50,4 +50,11 @@ export abstract class CreateParticipant {
|
|||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsObject()
|
@IsObject()
|
||||||
address?: Address;
|
address?: Address;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* how the participant got into the system
|
||||||
|
*/
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
created_via?: string;
|
||||||
}
|
}
|
||||||
@@ -32,6 +32,9 @@ export class CreateRunner extends CreateParticipant {
|
|||||||
newRunner.email = this.email;
|
newRunner.email = this.email;
|
||||||
newRunner.group = await this.getGroup();
|
newRunner.group = await this.getGroup();
|
||||||
newRunner.address = this.address;
|
newRunner.address = this.address;
|
||||||
|
if (this.created_via) {
|
||||||
|
newRunner.created_via = this.created_via;
|
||||||
|
}
|
||||||
Address.validate(newRunner.address);
|
Address.validate(newRunner.address);
|
||||||
|
|
||||||
return newRunner;
|
return newRunner;
|
||||||
|
|||||||
50
src/models/actions/update/UpdateRunnerCardByCode.ts
Normal file
50
src/models/actions/update/UpdateRunnerCardByCode.ts
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
import { IsBoolean, IsInt, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
|
import { getConnection } from 'typeorm';
|
||||||
|
import { RunnerNotFoundError } from '../../../errors/RunnerErrors';
|
||||||
|
import { Runner } from '../../entities/Runner';
|
||||||
|
import { RunnerCard } from '../../entities/RunnerCard';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to update a RunnerCard entity (via put request).
|
||||||
|
*/
|
||||||
|
export class UpdateRunnerCardByCode {
|
||||||
|
/**
|
||||||
|
* The card's code.
|
||||||
|
*/
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
code?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The runner's id.
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
@IsOptional()
|
||||||
|
runner?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is the updated card enabled (for fraud reasons)?
|
||||||
|
* Default: true
|
||||||
|
*/
|
||||||
|
@IsBoolean()
|
||||||
|
enabled: boolean = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new RunnerCard entity from this.
|
||||||
|
*/
|
||||||
|
public async update(card: RunnerCard): Promise<RunnerCard> {
|
||||||
|
card.enabled = this.enabled;
|
||||||
|
card.runner = await this.getRunner();
|
||||||
|
|
||||||
|
return card;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getRunner(): Promise<Runner> {
|
||||||
|
if (!this.runner) { return null; }
|
||||||
|
const runner = await getConnection().getRepository(Runner).findOne({ id: this.runner });
|
||||||
|
if (!runner) {
|
||||||
|
throw new RunnerNotFoundError();
|
||||||
|
}
|
||||||
|
return runner;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
IsInt,
|
IsInt
|
||||||
IsNotEmpty
|
|
||||||
} from "class-validator";
|
} from "class-validator";
|
||||||
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
|
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn, TableInheritance } from "typeorm";
|
||||||
import { ResponseDonation } from '../responses/ResponseDonation';
|
import { ResponseDonation } from '../responses/ResponseDonation';
|
||||||
@@ -24,7 +23,6 @@ export abstract class Donation {
|
|||||||
/**
|
/**
|
||||||
* The donations's donor.
|
* The donations's donor.
|
||||||
*/
|
*/
|
||||||
@IsNotEmpty()
|
|
||||||
@ManyToOne(() => Donor, donor => donor.donations)
|
@ManyToOne(() => Donor, donor => donor.donations)
|
||||||
donor: Donor;
|
donor: Donor;
|
||||||
|
|
||||||
|
|||||||
@@ -80,7 +80,7 @@ export abstract class Participant {
|
|||||||
*/
|
*/
|
||||||
@Column({ nullable: true, default: "backend" })
|
@Column({ nullable: true, default: "backend" })
|
||||||
@IsOptional()
|
@IsOptional()
|
||||||
@IsEmail()
|
@IsString()
|
||||||
created_via?: string;
|
created_via?: string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -84,6 +84,6 @@ export class Runner extends Participant {
|
|||||||
* Turns this entity into it's response class.
|
* Turns this entity into it's response class.
|
||||||
*/
|
*/
|
||||||
public toResponse(): ResponseRunner {
|
public toResponse(): ResponseRunner {
|
||||||
return new ResponseRunner(this);
|
return new ResponseRunner(this, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
58
src/models/responses/ResponseAnonymousDonation.ts
Normal file
58
src/models/responses/ResponseAnonymousDonation.ts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
import { IsInt, IsPositive } from "class-validator";
|
||||||
|
import { Donation } from '../entities/Donation';
|
||||||
|
import { DonationStatus } from '../enums/DonationStatus';
|
||||||
|
import { ResponseObjectType } from '../enums/ResponseObjectType';
|
||||||
|
import { IResponse } from './IResponse';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Defines the donation response.
|
||||||
|
*/
|
||||||
|
export class ResponseAnonymousDonation implements IResponse {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The responseType.
|
||||||
|
* This contains the type of class/entity this response contains.
|
||||||
|
*/
|
||||||
|
responseType: ResponseObjectType = ResponseObjectType.DONATION;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's payment status.
|
||||||
|
* Provides you with a quick indicator of it's payment status.
|
||||||
|
*/
|
||||||
|
status: DonationStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's id.
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
@IsPositive()
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's amount in the smalles unit of your currency (default: euro cent).
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The donation's paid amount in the smalles unit of your currency (default: euro cent).
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
paidAmount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a ResponseDonation object from a scan.
|
||||||
|
* @param donation The donation the response shall be build for.
|
||||||
|
*/
|
||||||
|
public constructor(donation: Donation) {
|
||||||
|
this.id = donation.id;
|
||||||
|
this.amount = donation.amount;
|
||||||
|
this.paidAmount = donation.paidAmount || 0;
|
||||||
|
if (this.paidAmount < this.amount) {
|
||||||
|
this.status = DonationStatus.OPEN;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.status = DonationStatus.PAID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -22,6 +22,12 @@ export class ResponseStats implements IResponse {
|
|||||||
@IsInt()
|
@IsInt()
|
||||||
runnersViaSelfservice: number;
|
runnersViaSelfservice: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of runners registered via kiosk.
|
||||||
|
*/
|
||||||
|
@IsInt()
|
||||||
|
runnersViaKiosk: number;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The amount of runners registered in the system.
|
* The amount of runners registered in the system.
|
||||||
*/
|
*/
|
||||||
@@ -98,7 +104,7 @@ export class ResponseStats implements IResponse {
|
|||||||
* @param scans number of scans - no relations have to be resolved.
|
* @param scans number of scans - no relations have to be resolved.
|
||||||
* @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track
|
* @param donations Array containing all donations - the following relations have to be resolved: runner, runner.scans, runner.scans.track
|
||||||
*/
|
*/
|
||||||
public constructor(runnersViaSelfservice: number, runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number, donors: number) {
|
public constructor(runnersViaSelfservice: number, runners: number, teams: number, orgs: number, users: number, scans: number, donations: Donation[], distance: number, donors: number, runnersViaKiosk: number) {
|
||||||
this.runnersViaSelfservice = runnersViaSelfservice;
|
this.runnersViaSelfservice = runnersViaSelfservice;
|
||||||
this.total_runners = runners;
|
this.total_runners = runners;
|
||||||
this.total_teams = teams;
|
this.total_teams = teams;
|
||||||
@@ -111,5 +117,6 @@ export class ResponseStats implements IResponse {
|
|||||||
this.average_donation = this.total_donation / this.total_donations
|
this.average_donation = this.total_donation / this.total_donations
|
||||||
this.total_donors = donors;
|
this.total_donors = donors;
|
||||||
this.average_distance = this.total_distance / this.total_runners;
|
this.average_distance = this.total_distance / this.total_runners;
|
||||||
|
this.runnersViaKiosk = runnersViaKiosk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user