Skip to content

Commit

Permalink
brought ./places response inline with expectations
Browse files Browse the repository at this point in the history
  • Loading branch information
AdenForshaw committed Nov 9, 2024
1 parent 16f9ed8 commit d4bcf40
Show file tree
Hide file tree
Showing 12 changed files with 599 additions and 122 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "overture-maps-api",
"version": "0.0.8",
"version": "0.0.9",
"description": "",
"author": "",
"private": true,
Expand Down
29 changes: 16 additions & 13 deletions src/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
import { PlacesModule } from './places/places.module';
import { PlacesService } from './places/places.service';
// src/app.module.ts
import { Module, NestMiddleware, MiddlewareConsumer, Logger, RequestMethod } from '@nestjs/common';
import { Module, NestMiddleware, MiddlewareConsumer, Logger, RequestMethod } from '@nestjs/common';
import { PlacesController } from './places/places.controller';
import { BigQueryService } from './bigquery/bigquery.service';
import { GcsService } from './gcs/gcs.service';
import { ConfigModule } from '@nestjs/config';
import {Request, Response} from 'express'
import { Request, Response } from 'express'
import { AuthAPIMiddleware } from './middleware/auth-api.middleware';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
imports: [ConfigModule.forRoot()],
controllers: [AppController,PlacesController],
providers: [BigQueryService, GcsService,AppService],
imports: [
PlacesModule, ConfigModule.forRoot()],
controllers: [AppController],
providers: [ BigQueryService, GcsService, AppService],
})
export class AppModule {
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('*');
configure(consumer: MiddlewareConsumer) {
consumer
.apply(LoggerMiddleware)
.forRoutes('*');

consumer.apply(AuthAPIMiddleware)
.forRoutes('*');
.forRoutes('*');

}
}

class LoggerMiddleware implements NestMiddleware {
use(req:Request, res:Response, next: Function) {
use(req: Request, res: Response, next: Function) {

Logger.debug(`Request ${req.method} ${req.originalUrl}`)
next();
}
}
}
15 changes: 15 additions & 0 deletions src/decorators/authed-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const AuthedUser = createParamDecorator(
(data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();
return request.res.locals['user']; // Get the user from locals
},
);

//interface for user object
export interface User {
accountId: string;
userId: string;
isDemoAccount?: boolean;
}
22 changes: 22 additions & 0 deletions src/decorators/validate-lat-lng-user.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { Injectable, BadRequestException, ForbiddenException } from '@nestjs/common';

// Method decorator
export function ValidateLatLngUser(): MethodDecorator {
return function (target, propertyKey, descriptor: PropertyDescriptor) {
const originalMethod = descriptor.value;

descriptor.value = async function (...args: any[]) {
const request = args[0]; // Assuming the first argument is the request object
const lat = request?.lat;
const lng = request?.lng;
const user = args[1]

if (lat && lng && user.isDemoAccount) {
throw new ForbiddenException('Demo accounts cannot access this feature');
}

// Call the original method if validation passes
return await originalMethod.apply(this, args);
};
};
}
16 changes: 9 additions & 7 deletions src/middleware/auth-api.middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import {
} from '@nestjs/common';

import { Request, Response } from 'express';
import { User } from '../decorators/authed-user.decorator';
//import CacheService from '../cache/CacheService';
import TheAuthAPI from 'theauthapi';

const DEMO_API_KEY = process.env.DEMO_API_KEY || 'DEMO-API-KEY';


@Injectable()
export class AuthAPIMiddleware implements NestMiddleware {

Expand Down Expand Up @@ -59,8 +61,9 @@ export class AuthAPIMiddleware implements NestMiddleware {

const apiKey = await this.theAuthAPI.apiKeys.authenticateKey(apiKeyString);
if (apiKey) {
const userObj = {
metadata: apiKey.customMetaData,
const metaData = apiKey.customMetaData as any;
const userObj:User = {
isDemoAccount: metaData.isDemoAccount || false,
accountId: apiKey.customAccountId,
userId: apiKey.customUserId,
};
Expand All @@ -77,13 +80,12 @@ export class AuthAPIMiddleware implements NestMiddleware {

//if demo key, set user to demo user
if (apiKeyString === DEMO_API_KEY) {
req['user'] = req.res.locals['user'] = {
metadata: {
isDemoAccount:true
},
const demoUser:User = {
isDemoAccount:true,
accountId: 'demo-account-id',
userId: 'demo-user-id',
userId: 'demo-user-id'
};
req['user'] = req.res.locals['user'] = demoUser;
next();
return;
}
Expand Down
49 changes: 23 additions & 26 deletions src/places/dto/place-response.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,13 +92,13 @@ export class PropertiesDto {
addresses?: AddressDto[];

@ApiProperty({ description: 'Theme associated with the place.', example: 'Restaurant' })
theme: string;
theme?: string;

@ApiProperty({ description: 'Type of feature or place.', example: 'Commercial' })
type: string;
type?: string;

@ApiProperty({ description: 'Version number of the place data.', example: 1 })
version: number;
@ApiProperty({ description: 'Version number of the place data.', example: "1" })
version: string;

@ApiProperty({
description: 'Source information for the place data.',
Expand All @@ -111,6 +111,10 @@ export class PropertiesDto {
type: () => PlaceNamesDto,
})
names: PlaceNamesDto;

constructor(data={}) {
Object.assign(this, data);
}
}

export class PlaceResponseDto {
Expand All @@ -134,29 +138,22 @@ export class PlaceResponseDto {

constructor(place: Place) {
this.id = place.id;
Object.assign(this, place);
this.geometry = place.geometry;
//if(!this.properties) this.properties = new PropertiesDto();
//Object.assign(this.properties, place);
}
}

export const toPlaceDto = (place: Place):PlaceResponseDto => {

const excludeFieldsFromProperties = ['properties','geometry','distance_m','bbox'];
const properties = {...place};
excludeFieldsFromProperties.forEach(field => delete properties[field]);

const rPlace = new PlaceResponseDto(place)
rPlace.properties = properties;
rPlace.geometry = place.geometry;

return rPlace;
}

export const toPlacesGeoJSONResponseDto = (places: Place[]) => {
const toplevel =
{
"type":"FeatureCollection",
"features":[
]
}
places.forEach(place => {
toplevel.features.push({
"type":"Feature",
"geometry":place.geometry,
"properties":{
confidence: place.confidence,
...place.names,
...place.brand,
...place.categories
}
})
})
return toplevel;
}
6 changes: 4 additions & 2 deletions src/places/interfaces/place.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export interface Place {
brand?: Brand;
addresses: Address[];
distance_m?: number;
theme?: string;
type?: string;
}

export interface Geometry {
Expand All @@ -39,7 +41,7 @@ export interface Place {

export interface Names {
primary: string;
common?: string;
common?: Record<string, string>;
rules?: any; // No clear type provided, so keeping it as `any`
}

Expand All @@ -55,7 +57,7 @@ export interface Place {

export interface BrandNames {
primary: string;
common?: string;
common?: Record<string, string>;
rules?: any; // No clear type provided, so keeping it as `any`
}

Expand Down
Loading

0 comments on commit d4bcf40

Please sign in to comment.