Skip to content
This repository has been archived by the owner on Feb 26, 2022. It is now read-only.

Commit

Permalink
Merge pull request #33 from LudovicGendre/feature/store/image-in-post…
Browse files Browse the repository at this point in the history
…gres

feat: save img into Postgres
  • Loading branch information
Ludovic authored Jan 20, 2022
2 parents 1d7d2e9 + b16061c commit 64286e6
Show file tree
Hide file tree
Showing 12 changed files with 119 additions and 72 deletions.
28 changes: 14 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"@nestjs/passport": "^8.0.1",
"@nestjs/platform-express": "^8.2.4",
"@nestjs/swagger": "^5.1.5",
"@prisma/client": "^3.8.0",
"@prisma/client": "^3.8.1",
"@types/faker": "^5.5.9",
"class-transformer": "^0.5.1",
"class-validator": "^0.13.2",
Expand Down Expand Up @@ -83,7 +83,7 @@
"husky": "^7.0.4",
"jest": "^27.2.5",
"prettier": "^2.3.2",
"prisma": "^3.8.0",
"prisma": "^3.8.1",
"source-map-support": "^0.5.20",
"supertest": "^6.1.3",
"ts-jest": "^27.0.3",
Expand Down
10 changes: 9 additions & 1 deletion prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,15 @@ model User {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
firstName String
lastName String
avatar String?
username String @unique
birthDate DateTime? @db.Timestamptz(6)
email String @unique
sex Int @default(0)
latitude Float?
longitude Float?
avatarId String? @db.Uuid
cityId String @db.Uuid
File File? @relation(fields: [avatarId], references: [id])
city City @relation(fields: [cityId], references: [id])
animals Animal[]
}
Expand All @@ -55,3 +56,10 @@ model Animal {
user User @relation(fields: [userId], references: [id])
breeds Breed[]
}

model File {
id String @id @default(dbgenerated("gen_random_uuid()")) @db.Uuid
fileName String
data Bytes
User User[]
}
2 changes: 1 addition & 1 deletion prisma/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const prisma = new PrismaClient();

export const seedUsers = async (): Promise<void> => {
const cities = await prisma.city.findMany();
const avatars = await prisma.city.findMany();
const promises: Promise<User>[] = [];

for (let index = 0; index < 10; index++) {
Expand All @@ -19,7 +20,6 @@ export const seedUsers = async (): Promise<void> => {
sex: 1,
latitude: 44.837789 + generateRandomFloatInRange(-0.5, 0.5),
longitude: -0.57918 + generateRandomFloatInRange(-0.5, 0.5),
avatar: '',
};
promises.push(prisma.user.create({ data: items }));
}
Expand Down
4 changes: 2 additions & 2 deletions src/animal/animal.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Delete,
} from '@nestjs/common';
import { Animal } from '@prisma/client';
import { CreateAnimalDto, Id, AnimalDto, FilterDto } from 'src/dtos';
import { CreateAnimalDto, FilterDto } from 'src/dtos';

import { AnimalService } from './animal.service';

Expand Down Expand Up @@ -52,7 +52,7 @@ export class AnimalController {
): Promise<Animal> {
return await this.animalService.update({
where: { id: id },
data: animal,
data: { ...animal, user: { connect: animal.user.connect } },
});
}

Expand Down
2 changes: 1 addition & 1 deletion src/animal/breed.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import {
Delete,
} from '@nestjs/common';
import { Breed } from '@prisma/client';
import { CreateBreedDto, Id, BreedDto, FilterDto } from 'src/dtos';
import { CreateBreedDto, FilterDto } from 'src/dtos';

import { BreedService } from './breed.service';

Expand Down
4 changes: 2 additions & 2 deletions src/dtos/animals/animal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@ export class CreateAnimalDto {
}

export class AnimalDto extends CreateAnimalDto {
@ApiProperty()
@ApiProperty({ type: () => BreedDto })
public breeds?: RelationsInput<BreedDto>;

@ApiProperty()
@ApiProperty({ type: () => UserDto })
public user: RelationInput<UserDto>;

@ApiProperty()
Expand Down
Empty file removed src/dtos/image/.gitkeep
Empty file.
32 changes: 32 additions & 0 deletions src/dtos/image/file.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';

import { IsNotEmpty, IsString, IsUUID } from 'class-validator';
import { UserDto } from '..';
import { RelationInput } from '../utils';

export class CreateFileDto {
@ApiProperty()
@IsString()
@IsNotEmpty()
public fileName!: string;

@ApiProperty()
@IsNotEmpty()
public data!: any;

@ApiProperty({ type: () => UserDto })
@IsNotEmpty()
@Type(() => UserDto)
public user!: RelationInput<UserDto>;
}

export class FileDto extends CreateFileDto {
@ApiProperty({ type: () => UserDto })
public user!: RelationInput<UserDto>;

@ApiProperty()
@IsNotEmpty()
@IsUUID(4)
public id!: string;
}
11 changes: 5 additions & 6 deletions src/dtos/users/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
} from 'class-validator';
import { CityDto } from '.';
import { AnimalDto } from '..';
import { FileDto } from '../image/file';
import { Id, RelationInput, RelationsInput } from '../utils';

export class CreateUserDto {
Expand All @@ -29,11 +30,6 @@ export class CreateUserDto {
@IsNotEmpty()
public username: string;

@ApiProperty()
@IsOptional()
@IsString()
public avatar?: string | null;

@ApiProperty()
@IsISO8601()
@IsOptional()
Expand Down Expand Up @@ -66,12 +62,15 @@ export class CreateUserDto {
}

export class UserDto extends CreateUserDto {
@ApiProperty()
@ApiProperty({ type: () => CityDto })
public city: RelationInput<CityDto>;

@ApiProperty({ type: () => AnimalDto })
public animals: RelationsInput<UserDto>;

@ApiProperty({ type: () => FileDto })
public avatar?: RelationInput<FileDto>;

@ApiProperty()
@IsNotEmpty()
@IsUUID(4)
Expand Down
74 changes: 32 additions & 42 deletions src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,21 @@ import {
Put,
Query,
UploadedFile,
UseGuards,
Request,
UseInterceptors,
Req,
Res,
StreamableFile,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import { User } from '@prisma/client';
import { query } from 'express';
import { diskStorage } from 'multer';
import path = require('path');
import { v4 as uuidv4 } from 'uuid';
import { Response } from 'express';
import { CreateUserDto, FilterDto } from 'src/dtos';
import { AuthGuard } from 'src/guards/auth.guard';

import { UserService } from './user.service';

import { createParamDecorator } from '@nestjs/common';
import { LoggedUser } from 'src/decorators/logged-user.decorator';
import { Readable } from 'stream';

export const AuthUser = createParamDecorator((data, req) => {
return req.user;
Expand All @@ -43,17 +41,6 @@ export class UserController {
});
}

// Ludo: Pas nécessaire (duplication), nous avons déjà l'ensemble des users en relation dans /cities/:id

// @Get('/city/:id')
// async listCity(@Param('id') id: string): Promise<User[]> {
// return await this.userService.getCity({
// cityWhereUniqueInput: {
// id,
// },
// });
// }

// @UseGuards(AuthGuard)
@Get('/proximity')
async getUsersInRadius(
Expand All @@ -72,31 +59,34 @@ export class UserController {
return await this.userService.get({ id: id });
}

@Post('upload')
@UseInterceptors(
FileInterceptor('file', {
storage: diskStorage({
destination: './uploads',
filename: (req, file, cb) => {
const filename: string =
path.parse(file.originalname).name.replace(/\s/g, '') + uuidv4();
const extension: string = path.parse(file.originalname).ext;

cb(null, `${filename}${extension}`);
},
}),
}),
)
async uploadFile(
@Post('/avatar')
@UseInterceptors(FileInterceptor('file'))
async addAvatar(
@Req() request: any,
@UploadedFile() file: Express.Multer.File,
@LoggedUser() user: any,
): Promise<User> {
const auth = await this.userService.get(user);
) {
return this.userService.addAvatar(
'34d2d1f0-3028-4b89-98ff-6f8df08e9f9d',
file.buffer,
file.originalname,
);
}

return await this.userService.update({
where: { id: auth.id },
data: { avatar: file.filename },
@Get('/avatar/:id')
async getDatabaseFileById(
@Res({ passthrough: true }) response: Response,
@Param('id') id: string,
) {
const file = await this.userService.getFileById(id);

const stream = Readable.from(file.data);

response.set({
'Content-Disposition': `inline; filename="${file.fileName}"`,
'Content-Type': 'image',
});

return new StreamableFile(stream);
}

@Post('/')
Expand All @@ -112,11 +102,11 @@ export class UserController {
@Put('/:id')
async update(
@Param('id') id: string,
@Body() city: CreateUserDto,
@Body() body: CreateUserDto,
): Promise<User> {
return await this.userService.update({
where: { id: id },
data: city,
data: body,
});
}
}
20 changes: 19 additions & 1 deletion src/user/user.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma.service';
import { User, Prisma } from '@prisma/client';
import { User, Prisma, File } from '@prisma/client';
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
Expand Down Expand Up @@ -83,6 +83,24 @@ export class UserService {

return usersInProximity;
}

// save avatar in db
async addAvatar(userId: string, imageBuffer: Buffer, filename: string) {
const avatar = await this.prisma.file.create({
data: {
fileName: filename,
data: imageBuffer,
User: { connect: { id: userId } },
},
});
return avatar;
}
// get avatar from db
async getFileById(fileId: string): Promise<File | null> {
return await this.prisma.file.findUnique({
where: { id: fileId },
});
}
}

//This function takes in latitude and longitude of two location and returns the distance between them as the crow flies (in km)
Expand Down

0 comments on commit 64286e6

Please sign in to comment.