Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_
SECRET_KEY=

HOST=::0.0.0.0
PORT=4000
PORT=4000

MAPS_CO_GEOCODE_API_KEY=
4 changes: 3 additions & 1 deletion .env.local
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ DATABASE_URL="postgresql://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_
SECRET_KEY=batata

HOST=::0.0.0.0
PORT=4000
PORT=4000

MAPS_CO_GEOCODE_API_KEY=
48 changes: 48 additions & 0 deletions package-lock.json

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

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-express": "^10.0.0",
"@nestjs/platform-fastify": "^10.3.8",
"@nestjs/schedule": "^4.0.2",
"@nestjs/swagger": "^7.3.1",
"@prisma/client": "^5.13.0",
"bcrypt": "^5.1.1",
Expand Down
8 changes: 8 additions & 0 deletions prisma/migrations/20240511043849_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-- AlterTable
ALTER TABLE "shelters"
ADD COLUMN "city" TEXT,
ADD COLUMN "street" TEXT,
ADD COLUMN "street_number" TEXT,
ADD COLUMN "neighbourhood" TEXT,
ADD COLUMN "state_district" TEXT,
ADD COLUMN "zip_code" TEXT;
6 changes: 6 additions & 0 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ model Shelter {
latitude Float?
longitude Float?
verified Boolean @default(value: false)
city String?
street String?
streetNumber String? @map("street_number")
neighbourhood String?
stateDistrict String? @map("state_district")
zipCode String? @map("zip_code")
createdAt String @map("created_at") @db.VarChar(32)
updatedAt String? @map("updated_at") @db.VarChar(32)

Expand Down
106 changes: 106 additions & 0 deletions src/shelter/populateShelterCity.cron.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { Injectable, Logger } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';

import { PrismaService } from 'src/prisma/prisma.service';

@Injectable()
export class PopulateShelterCity {
private readonly logger = new Logger(PopulateShelterCity.name);
private readonly geocodeApiKey = process.env.MAPS_CO_GEOCODE_API_KEY;
constructor(private readonly prismaService: PrismaService) {}

@Cron(CronExpression.EVERY_MINUTE)
async populateShelterCity() {
const runId = Date.now();
this.logger.log(`Running Populate Shelter City CRON (${runId})`);

const shelter = await this.prismaService.shelter.findFirst({
where: {
city: null,
latitude: { not: null },
longitude: { not: null },
},
select: {
id: true,
latitude: true,
longitude: true,
},
});

if (!shelter) {
this.logger.log(`${runId} > No pending shelters found. Skipping...`);
return;
}
this.logger.log(
`${runId} > Processing data for shelter with ID '${shelter.id}'`,
);

const { latitude, longitude } = shelter;
if (!latitude || !longitude) {
this.logger.log(`${runId} > Inconsistent lat/long data. Skipping...`);
return;
}

let geocodeData:
| {
city?: string;
postCode?: string;
}
| undefined = undefined;

try {
geocodeData = await this.reverseGeocode({ latitude, longitude });
if (!geocodeData.city) {
this.logger.log(
`${runId} > Missing city from geocode data. Skipping...`,
);
return;
}
} catch (error) {
this.logger.error(error);
this.logger.log(`${runId} > Error fetching geodata. Skipping...`);
geocodeData = undefined;
}
if (!geocodeData) return;

await this.prismaService.shelter.update({
where: { id: shelter.id },
data: geocodeData,
});
this.logger.log(`${runId} > Successfully updated geocode data.`);
}

private async reverseGeocode({
latitude,
longitude,
}: {
latitude: number;
longitude: number;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Crie a interface e a passe como parametro.

Por exemplo:

props: IReverseGeoCodeProps

ao inves de passar uma interface hardcoded.

Daí faça isso em todas interface do seu PR por gentileza.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feito

}): Promise<{
city?: string;
street?: string;
streetNumber?: string;
neighbourhood?: string;
stateDistrict?: string;
zipCode?: string;
}> {
const reverseGeocodeURI = `https://geocode.maps.co/reverse?lat=${latitude}&lon=${longitude}&api_key=${this.geocodeApiKey}`;

const response = await fetch(reverseGeocodeURI, {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Não seria uma opção utilizar o modulo http do nestjs?

method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
const data = await response.json();

return {
city: data?.address.city,
street: data?.address.road,
streetNumber: data?.address.house_number,
neighbourhood: data?.address.suburb,
stateDistrict: data?.address.state_district,
zipCode: data?.address.postcode,
};
}
}
6 changes: 4 additions & 2 deletions src/shelter/shelter.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Module } from '@nestjs/common';
import { ScheduleModule } from '@nestjs/schedule';

import { PopulateShelterCity } from './populateShelterCity.cron';
import { ShelterService } from './shelter.service';
import { ShelterController } from './shelter.controller';
import { PrismaModule } from '../prisma/prisma.module';

@Module({
imports: [PrismaModule],
providers: [ShelterService],
imports: [PrismaModule, ScheduleModule.forRoot()],
providers: [ShelterService, PopulateShelterCity],
controllers: [ShelterController],
})
export class ShelterModule {}
6 changes: 6 additions & 0 deletions src/shelter/shelter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,12 @@ export class ShelterService {
verified: true,
latitude: true,
longitude: true,
city: true,
street: true,
streetNumber: true,
neighbourhood: true,
stateDistrict: true,
zipCode: true,
createdAt: true,
updatedAt: true,
shelterSupplies: {
Expand Down
5 changes: 5 additions & 0 deletions src/shelter/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ const ShelterSchema = z.object({
name: z.string().transform(capitalize),
pix: z.string().nullable().optional(),
address: z.string().transform(capitalize),
city: z.string().transform(capitalize).optional(),
street: z.string().transform(capitalize).optional(),
streetNumber: z.string().nullable().optional(),
neighbourhood: z.string().transform(capitalize).optional(),
postCode: z.string().nullable().optional(),
petFriendly: z.boolean().nullable().optional(),
shelteredPeople: z.number().nullable().optional(),
latitude: z.number().nullable().optional(),
Expand Down