Skip to content

Commit

Permalink
feat: refactor pin controller
Browse files Browse the repository at this point in the history
  • Loading branch information
frederic-maury committed Jan 10, 2025
1 parent 0b775dc commit 306f5df
Show file tree
Hide file tree
Showing 2 changed files with 66 additions and 37 deletions.
80 changes: 53 additions & 27 deletions backend/src/controllers/pin.controller.ts
Original file line number Diff line number Diff line change
@@ -1,47 +1,73 @@
import { Request, Response } from 'express';
import { getPinSvg, getPinSvgFromCache, writePinSvgToCache } from '../services/pin/pin.service';
import { getPinSvg, getPinSvgFromCache, Occupation, PropertyType, writePinSvgToCache } from '../services/pin/pin.service';

function validateParams(
query: Request['query'],
res: Response,
): {
occupation: Occupation,
propertyType: PropertyType,
owned: boolean,
icon: boolean,
} | undefined {
const { occupation, propertyType, owned, icon } = query;
if (!occupation || !propertyType) {
res.status(400).json({ error: 'Occupation, propertyType parameters are required' });
return;
}
if (typeof occupation !== 'string' || typeof propertyType !== 'string') {
res.status(400).json({ error: 'Occupation, propertyType parameters must be strings' });
return;
}
const occupationEnum: Occupation[] = ['red', 'green', 'yellow'];
const propertyTypeEnum: PropertyType[] = ['singleFamily', 'multiFamily', 'duplex', 'condominium', 'mixedUse', 'quadplex', 'commercial', 'sfrPortfolio', 'mfrPortfolio', 'loan', 'stack'];
if (!occupationEnum.includes(occupation as Occupation) || !propertyTypeEnum.includes(propertyType as PropertyType)) {
res.status(400).json({ error: 'Invalid occupation or propertyType' });
return;
}
return {
occupation: occupation as Occupation,
propertyType: propertyType as PropertyType,
owned: !owned && owned !== '' ? false : true,
icon: !icon && icon !== '' ? false : true,
};
}

export async function generatePinSvg(
req: Request,
res: Response,
) {
const { occupation, propertyType, owned, icon } = req.query;
if (!occupation || !propertyType) {
return res.status(400).json({ error: 'Occupation, propertyType parameters are required' });
} else if (typeof occupation !== 'string' || typeof propertyType !== 'string') {
return res.status(400).json({ error: 'Occupation, propertyType parameters must be strings' });
} else if (!['red', 'green', 'yellow'].includes(occupation) || !['singleFamily', 'multiFamily', 'duplex', 'condominium', 'mixedUse', 'quadplex', 'commercial', 'sfrPortfolio', 'mfrPortfolio', 'loan', 'stack'].includes(propertyType)) {
return res.status(400).json({ error: 'Invalid occupation or propertyType' });
const params = validateParams(req.query, res);
if (!params) {
return;
}
const { occupation, propertyType, owned, icon } = params;

res.setHeader('Content-Type', 'image/svg+xml');
res.setHeader('Content-Security-Policy', "default-src 'self'");
res.setHeader('X-Content-Type-Options', 'nosniff');
res.setHeader('Cache-Control', 'public, max-age=604800, immutable');
res.setTimeout(5000, () => {
res.status(504).json({ error: 'Request timed out' });
});
res.setHeader('Content-Type', 'image/svg+xml')
.setHeader('Content-Security-Policy', "default-src 'self'")
.setHeader('X-Content-Type-Options', 'nosniff')
.setHeader('Cache-Control', 'public, max-age=604800, immutable')
.setTimeout(5000, () => {
res.status(504).json({ error: 'Request timed out' });
});

try {
const ownedValue = !owned && owned !== '' ? false : true;
const iconValue = !icon && icon !== '' ? false : true;

const existingSvg = await getPinSvgFromCache(occupation, propertyType, ownedValue, iconValue);
const existingSvg = await getPinSvgFromCache(occupation, propertyType, owned, icon);
if (existingSvg) {
return res.send(existingSvg);
}

const svg = await getPinSvg(
occupation as string,
propertyType as string,
ownedValue,
iconValue,
occupation,
propertyType,
owned,
icon,
);
await writePinSvgToCache(
occupation as string,
propertyType as string,
ownedValue,
iconValue,
occupation,
propertyType,
owned,
icon,
svg,
);

Expand Down
23 changes: 13 additions & 10 deletions backend/src/services/pin/pin.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { access, mkdir, readFile, writeFile } from "fs/promises";
import path from "path";

function getOccupationColor(occupation: string) {
export type Occupation = 'red' | 'green' | 'yellow';
export type PropertyType = 'singleFamily' | 'multiFamily' | 'duplex' | 'condominium' | 'mixedUse' | 'quadplex' | 'commercial' | 'sfrPortfolio' | 'mfrPortfolio' | 'loan' | 'stack';

function getOccupationColor(occupation: Occupation) {
switch (occupation) {
case 'red':
return '#f44336';
Expand All @@ -14,7 +17,7 @@ function getOccupationColor(occupation: string) {
}
}

function getPropertyTypeColor(propertyType: string) {
function getPropertyTypeColor(propertyType: PropertyType) {
switch (propertyType) {
case 'singleFamily':
return '#1e88e5';
Expand Down Expand Up @@ -44,8 +47,8 @@ function getPropertyTypeColor(propertyType: string) {
}

export function getPinCacheKey(
occupation: string,
propertyType: string,
occupation: Occupation,
propertyType: PropertyType,
owned?: boolean,
icon?: boolean,
) {
Expand All @@ -60,8 +63,8 @@ export function getPinCacheKey(
}

export async function getPinSvg(
occupation: string,
propertyType: string,
occupation: Occupation,
propertyType: PropertyType,
owned: boolean,
icon: boolean,
) {
Expand Down Expand Up @@ -97,8 +100,8 @@ export async function getPinSvg(
}

export async function writePinSvgToCache(
occupation: string,
propertyType: string,
occupation: Occupation,
propertyType: PropertyType,
owned: boolean,
icon: boolean,
svg: string,
Expand All @@ -114,8 +117,8 @@ export async function writePinSvgToCache(
}

export async function getPinSvgFromCache(
occupation: string,
propertyType: string,
occupation: Occupation,
propertyType: PropertyType,
owned: boolean,
icon: boolean,
) {
Expand Down

0 comments on commit 306f5df

Please sign in to comment.