Skip to content

Commit d95d816

Browse files
committed
feat: gh actions, category supploes and fix shelter service methods
1 parent 067fa6b commit d95d816

19 files changed

+301
-14
lines changed

.env.example

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
TZ=America/Sao_Paulo
2+
3+
DB_HOST=
4+
DB_PORT=
5+
DB_USER=
6+
DB_PASSWORD=
7+
DB_DATABASE_NAME=
8+
DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_DATABASE_NAME}?schema=public&sslmode=require"
9+
SECRET_KEY=
10+
11+
HOST=::0.0.0.0
12+
PORT=4000

.github/workflows/deploy.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: Deploy Backend
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
jobs:
10+
build:
11+
runs-on: self-hosted
12+
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Create .env file
17+
run: |
18+
touch .env
19+
echo TZ=${{ secrets.TZ }} >> .env
20+
echo DB_HOST=${{ secrets.DB_HOST }} >> .env
21+
echo DB_PORT=${{ secrets.DB_PORT }} >> .env
22+
echo DB_USER=${{ secrets.DB_USER }} >> .env
23+
echo DB_PASSWORD=${{ secrets.DB_PASSWORD }} >> .env
24+
echo DB_DATABASE_NAME=${{ secrets.DB_DATABASE_NAME }} >> .env
25+
echo DATABASE_URL=postgresql://${{ secrets.DB_USER }}:${{ secrets.DB_PASSWORD }}@${{ secrets.DB_HOST }}:${{ secrets.DB_PORT }}/${{ secrets.DB_DATABASE_NAME }}?schema=public >> .env
26+
echo SECRET_KEY=${{ secrets.SECRET_KEY }} >> .env
27+
echo HOST=${{ secrets.HOST }} >> .env
28+
echo PORT=${{ secrets.PORT }} >> .env
29+
echo SERVER_USER_PASSWORD=${{ secrets.SERVER_USER_PASSWORD }} >> .env
30+
cat .env
31+
32+
- name: Remove old docker image
33+
run: echo ${{ secrets.SERVER_USER_PASSWORD }} | sudo -S docker compose down --rmi all
34+
35+
- name: Create new docker image
36+
run: echo ${{ secrets.SERVER_USER_PASSWORD }} | sudo -S docker compose up -d --force-recreate

Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
FROM node:18.18 as node
2+
3+
WORKDIR /usr/app
4+
5+
COPY package.json package-lock.json ./
6+
7+
RUN npm install
8+
COPY . .

docker-compose.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
services:
2+
sos-rs-api:
3+
container_name: sos-rs-api
4+
build:
5+
context: .
6+
dockerfile: Dockerfile
7+
restart: always
8+
tty: true
9+
ports:
10+
- '4000:4000'
11+
command: >
12+
sh -c "npx prisma generate &&
13+
npx prisma migrate deploy &&
14+
npm run build && npm run start:prod"
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/*
2+
Warnings:
3+
4+
- A unique constraint covering the columns `[name]` on the table `shelters` will be added. If there are existing duplicate values, this will fail.
5+
- Added the required column `name` to the `shelters` table without a default value. This is not possible if the table is not empty.
6+
7+
*/
8+
-- AlterTable
9+
ALTER TABLE "shelters" ADD COLUMN "name" TEXT NOT NULL;
10+
11+
-- CreateIndex
12+
CREATE UNIQUE INDEX "shelters_name_key" ON "shelters"("name");

prisma/schema.prisma

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ enum SupplyStatus {
5151

5252
model SupplyCategory {
5353
id String @id @default(uuid())
54-
name String
54+
name String @unique
5555
createdAt String @map("created_at") @db.VarChar(32)
5656
updatedAt String? @map("updated_at") @db.VarChar(32)
5757
@@ -77,6 +77,7 @@ model Supply {
7777

7878
model Shelter {
7979
id String @id @default(uuid())
80+
name String @unique
8081
pix String @unique
8182
address String
8283
petFriendly Boolean? @map("pet_friendly")

src/app.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ServerResponseInterceptor } from './interceptors';
88
import { LoggingMiddleware } from './middlewares/logging.middleware';
99
import { UsersModule } from './users/users.module';
1010
import { SessionsModule } from './sessions/sessions.module';
11+
import { SupplyCategoriesModule } from './supply-categories/supply-categories.module';
1112

1213
@Module({
1314
imports: [
@@ -16,6 +17,7 @@ import { SessionsModule } from './sessions/sessions.module';
1617
SessionsModule,
1718
ShelterModule,
1819
SupplyModule,
20+
SupplyCategoriesModule,
1921
],
2022
controllers: [],
2123
providers: [

src/shelter/shelter.controller.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,15 @@ import {
77
Param,
88
Post,
99
Put,
10+
UseGuards,
1011
} from '@nestjs/common';
1112
import { ApiTags } from '@nestjs/swagger';
1213

1314
import { ShelterService } from './shelter.service';
1415
import { ServerResponse } from '../utils';
1516
import { SearchQuery } from '../decorators';
1617
import { SeachQueryProps } from '@/decorators/search-query/types';
18+
import { StaffGuard } from '@/guards/staff.guard';
1719

1820
@ApiTags('Abrigos')
1921
@Controller('shelters')
@@ -25,7 +27,7 @@ export class ShelterController {
2527
@Get('')
2628
async index(@SearchQuery() searchQueryParams: SeachQueryProps) {
2729
try {
28-
const data = await this.shelterService.getAll(searchQueryParams);
30+
const data = await this.shelterService.index(searchQueryParams);
2931
return new ServerResponse(200, 'Successfully get shelters', data);
3032
} catch (err: any) {
3133
this.logger.error(`Failed to get shelters: ${err}`);
@@ -34,12 +36,13 @@ export class ShelterController {
3436
}
3537

3638
@Post('')
39+
@UseGuards(StaffGuard)
3740
async store(@Body() body) {
3841
try {
3942
const data = await this.shelterService.store(body);
4043
return new ServerResponse(200, 'Successfully created shelter', data);
4144
} catch (err: any) {
42-
this.logger.error(`Failed to get all users: ${err}`);
45+
this.logger.error(`Failed to create shelter: ${err}`);
4346
throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400);
4447
}
4548
}
@@ -56,12 +59,13 @@ export class ShelterController {
5659
}
5760

5861
@Put(':id/admin')
62+
@UseGuards(StaffGuard)
5963
async fullUpdate(@Param('id') id: string, @Body() body) {
6064
try {
6165
const data = await this.shelterService.fullUpdate(id, body);
6266
return new ServerResponse(200, 'Successfully updated shelter', data);
6367
} catch (err: any) {
64-
this.logger.error(`Failed update shelter: ${err}`);
68+
this.logger.error(`Failed to update shelter: ${err}`);
6569
throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400);
6670
}
6771
}

src/shelter/shelter.service.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class ShelterService {
3333
},
3434
data: {
3535
...payload,
36-
createdAt: new Date().toISOString(),
36+
updatedAt: new Date().toISOString(),
3737
},
3838
});
3939
}
@@ -46,18 +46,19 @@ export class ShelterService {
4646
},
4747
data: {
4848
...payload,
49-
createdAt: new Date().toISOString(),
49+
updatedAt: new Date().toISOString(),
5050
},
5151
});
5252
}
5353

54-
async getAll(props: SeachQueryProps) {
54+
async index(props: SeachQueryProps) {
5555
const { handleSearch } = props;
5656
return await handleSearch<Prisma.ShelterSelect<DefaultArgs>>(
5757
this.prismaService.shelter,
5858
{
5959
select: {
6060
id: true,
61+
name: true,
6162
pix: true,
6263
address: true,
6364
capacity: true,

src/shelter/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import z from 'zod';
22

33
const ShelterSchema = z.object({
44
id: z.string(),
5+
name: z.string(),
56
pix: z.string(),
67
address: z.string(),
78
petFriendly: z.boolean().nullable().optional(),
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { SupplyCategoriesController } from './supply-categories.controller';
3+
4+
describe('SupplyCategoriesController', () => {
5+
let controller: SupplyCategoriesController;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
controllers: [SupplyCategoriesController],
10+
}).compile();
11+
12+
controller = module.get<SupplyCategoriesController>(SupplyCategoriesController);
13+
});
14+
15+
it('should be defined', () => {
16+
expect(controller).toBeDefined();
17+
});
18+
});
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import {
2+
Body,
3+
Controller,
4+
Get,
5+
HttpException,
6+
Logger,
7+
Param,
8+
Post,
9+
Put,
10+
UseGuards,
11+
} from '@nestjs/common';
12+
import { ApiTags } from '@nestjs/swagger';
13+
14+
import { SupplyCategoriesService } from './supply-categories.service';
15+
import { ServerResponse } from '../utils';
16+
import { StaffGuard } from '@/guards/staff.guard';
17+
18+
@ApiTags('Categoria de Suprimentos')
19+
@Controller('supply-categories')
20+
export class SupplyCategoriesController {
21+
private logger = new Logger(SupplyCategoriesController.name);
22+
23+
constructor(
24+
private readonly supplyCategoryServices: SupplyCategoriesService,
25+
) {}
26+
27+
@Get('')
28+
async index() {
29+
try {
30+
const data = await this.supplyCategoryServices.index();
31+
return new ServerResponse(
32+
200,
33+
'Successfully get supply categories',
34+
data,
35+
);
36+
} catch (err: any) {
37+
this.logger.error(`Failed to get supply categories: ${err}`);
38+
throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400);
39+
}
40+
}
41+
42+
@Post('')
43+
@UseGuards(StaffGuard)
44+
async store(@Body() body) {
45+
try {
46+
const data = await this.supplyCategoryServices.store(body);
47+
return new ServerResponse(
48+
200,
49+
'Successfully created supply category',
50+
data,
51+
);
52+
} catch (err: any) {
53+
this.logger.error(`Failed to create supply category: ${err}`);
54+
throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400);
55+
}
56+
}
57+
58+
@Put(':id')
59+
@UseGuards(StaffGuard)
60+
async update(@Param('id') id: string, @Body() body) {
61+
try {
62+
const data = await this.supplyCategoryServices.update(id, body);
63+
return new ServerResponse(
64+
200,
65+
'Successfully updated supply category',
66+
data,
67+
);
68+
} catch (err: any) {
69+
this.logger.error(`Failed to update supply category: ${err}`);
70+
throw new HttpException(err?.code ?? err?.name ?? `${err}`, 400);
71+
}
72+
}
73+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Module } from '@nestjs/common';
2+
3+
import { SupplyCategoriesService } from './supply-categories.service';
4+
import { SupplyCategoriesController } from './supply-categories.controller';
5+
import { PrismaModule } from '../prisma/prisma.module';
6+
7+
@Module({
8+
imports: [PrismaModule],
9+
providers: [SupplyCategoriesService],
10+
controllers: [SupplyCategoriesController],
11+
})
12+
export class SupplyCategoriesModule {}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { SupplyCategoriesService } from './supply-categories.service';
3+
4+
describe('SupplyCategoriesService', () => {
5+
let service: SupplyCategoriesService;
6+
7+
beforeEach(async () => {
8+
const module: TestingModule = await Test.createTestingModule({
9+
providers: [SupplyCategoriesService],
10+
}).compile();
11+
12+
service = module.get<SupplyCategoriesService>(SupplyCategoriesService);
13+
});
14+
15+
it('should be defined', () => {
16+
expect(service).toBeDefined();
17+
});
18+
});
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { Injectable } from '@nestjs/common';
2+
3+
import { PrismaService } from '../prisma/prisma.service';
4+
import { z } from 'zod';
5+
import {
6+
CreateSupplyCategorySchema,
7+
UpdateSupplyCategorySchema,
8+
} from './types';
9+
10+
@Injectable()
11+
export class SupplyCategoriesService {
12+
constructor(private readonly prismaService: PrismaService) {}
13+
14+
async store(body: z.infer<typeof CreateSupplyCategorySchema>) {
15+
const payload = CreateSupplyCategorySchema.parse(body);
16+
await this.prismaService.supplyCategory.create({
17+
data: {
18+
...payload,
19+
createdAt: new Date().toISOString(),
20+
},
21+
});
22+
}
23+
24+
async update(id: string, body: z.infer<typeof UpdateSupplyCategorySchema>) {
25+
const payload = UpdateSupplyCategorySchema.parse(body);
26+
await this.prismaService.supplyCategory.update({
27+
where: {
28+
id,
29+
},
30+
data: {
31+
...payload,
32+
updatedAt: new Date().toISOString(),
33+
},
34+
});
35+
}
36+
37+
async index() {
38+
return await this.prismaService.supplyCategory.findMany({});
39+
}
40+
}

0 commit comments

Comments
 (0)