Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

25 bac query endpoint #31

Merged
merged 10 commits into from
Aug 1, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ CREATE TABLE "DrinkAction" (
"milliliter" INTEGER NOT NULL,
"drinkId" TEXT NOT NULL,
"eventId" TEXT NOT NULL,
"hasEffect" BOOLEAN NOT NULL DEFAULT true,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

CONSTRAINT "DrinkAction_pkey" PRIMARY KEY ("id")
);
Expand Down
8 changes: 5 additions & 3 deletions apps/backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,15 @@ model Event {
}

model DrinkAction {
id String @id @default(uuid())
id String @id @default(uuid())
price Int
milliliter Int
drinkId String
drink Drink @relation(fields: [drinkId], references: [id])
drink Drink @relation(fields: [drinkId], references: [id])
eventId String
event Event @relation(fields: [eventId], references: [id])
event Event @relation(fields: [eventId], references: [id])
// userId String
// user User @relation(fields: [userId], references: [authSchId])
hasEffect Boolean @default(true)
VarMattew marked this conversation as resolved.
Show resolved Hide resolved
createdAt DateTime @default(now())
Tschonti marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ import { OmitType } from '@nestjs/swagger';

import { DrinkAction } from '../entities/drink-action.entity';

export class CreateDrinkActionDto extends OmitType(DrinkAction, ['id']) {}
export class CreateDrinkActionDto extends OmitType(DrinkAction, ['id', 'hasEffect']) {}
12 changes: 12 additions & 0 deletions apps/backend/src/drink-action/entities/drink-action.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,16 @@ export class DrinkAction {
@IsNumber()
@Min(0)
milliliter: number;

/**
* Shows if the alcohol still has effect on the user.
* @example false
*/
hasEffect: boolean;

/**
* The date and time when the alcohol was consumed
* @example 2024-07-27T15:31:11.763Z
*/
createdAt: Date;
}
13 changes: 13 additions & 0 deletions apps/backend/src/users/dto/user-bac.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { IsNotEmpty, Min } from 'class-validator';
import { IsFloat } from 'src/util/is-float.validator';

export class UserBac {
/**
* Blood Alcohol Content.
* @example 0.06
*/
@IsFloat()
@IsNotEmpty()
@Min(0)
alcoholContent: number;
}
4 changes: 2 additions & 2 deletions apps/backend/src/users/entities/user.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ export class User {

/**
* Gender
* @example Male/Female
* @example Male
*/
@IsOptional()
gender?: Gender;

/**
* Weight
* @example 75.2 (kg)
* @example 75.2
*/
@IsOptional()
@Min(0)
Expand Down
16 changes: 13 additions & 3 deletions apps/backend/src/users/users.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Patch, Post } from '@nestjs/common';
import { ApiBody, ApiOperation, ApiTags } from '@nestjs/swagger';
import { CurrentUser } from '@kir-dev/passport-authsch';
import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Patch, Post, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { User } from '@prisma/client';

import { UserBac } from './dto/user-bac.dto';
import { UserGenderWeight } from './dto/user-gender-weight.dto';
import { UserWithFavoriteDrinks } from './dto/user-with-favorite-drinks.dto';
import { UserWithoutWeight } from './dto/user-without-weight.dto';
Expand All @@ -23,6 +26,14 @@ export class UsersController {
return await this.usersService.findAll();
}

@Get('/bac')
@UseGuards(AuthGuard('jwt'))
@ApiBearerAuth()
@ApiOperation({ summary: 'Get BAC (Blood Alcohol Content)' })
async calculateBloodAlcoholContent(@CurrentUser() user: User): Promise<UserBac> {
return await this.usersService.calculateBloodAlcoholContent(user);
}

@Delete(':id')
@ApiOperation({ summary: 'Delete user by ID' })
async remove(@Param('id', ParseUUIDPipe) id: string): Promise<User> {
Expand All @@ -31,7 +42,6 @@ export class UsersController {

@Patch(':id/')
@ApiOperation({ summary: 'Edit Gender and Weight' })
@ApiBody({ type: UserGenderWeight })
async update(@Param('id', ParseUUIDPipe) id: string, @Body() userGenderWeight: UserGenderWeight) {
await this.usersService.update(id, userGenderWeight);
return { message: `User was updated successfully: ${userGenderWeight.gender}, ${userGenderWeight.weight} kg` };
Expand Down
40 changes: 40 additions & 0 deletions apps/backend/src/users/users.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { BadRequestException, Injectable, NotFoundException } from '@nestjs/comm
import { User } from '@prisma/client';
import { PrismaService } from 'nestjs-prisma';

import { UserBac } from './dto/user-bac.dto';
import { UserGenderWeight } from './dto/user-gender-weight.dto';
import { UserWithFavoriteDrinks } from './dto/user-with-favorite-drinks.dto';
import { UserWithoutWeight } from './dto/user-without-weight.dto';
Expand Down Expand Up @@ -37,6 +38,45 @@ export class UsersService {
return await this.prisma.user.findMany({ omit: { weight: true } });
}

async calculateBloodAlcoholContent(user: User): Promise<UserBac> {
if (!user.weight) {
throw new NotFoundException('User has no weight or gender set');
}

if (!user.gender) {
throw new NotFoundException('User has no weight or gender set');
}

const currentTime = new Date();
const userWeightInGrams = user.weight * 1000;
const genderFactor = user.gender === 'Male' ? 0.68 : 0.55;
Tschonti marked this conversation as resolved.
Show resolved Hide resolved

const drinkActions = await this.prisma.drinkAction.findMany({
where: { hasEffect: true },
include: { drink: { select: { alcoholContent: true } } },
});

let totalBac = 0;

for (const drinkAction of drinkActions) {
const dose = drinkAction.milliliter * (drinkAction.drink.alcoholContent / 100) * 0.789;
const timeDifferenceMs = currentTime.getTime() - drinkAction.createdAt.getTime();
const eliminated = (timeDifferenceMs / (1000 * 60 * 60)) * 0.016;

const bac = Math.max(0, (dose / (userWeightInGrams * genderFactor)) * 100 - eliminated);
if (bac === 0) {
await this.prisma.drinkAction.update({
where: { id: drinkAction.id },
data: { hasEffect: false },
});
} else {
totalBac += bac;
}
}

return { alcoholContent: Math.round(totalBac * 10000) / 10000 };
}

async remove(authSchId: string): Promise<User> {
try {
return await this.prisma.user.delete({ where: { authSchId } });
Expand Down