Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: added geolocation APIs in CREDEBL. #796

Merged
merged 9 commits into from
Jun 24, 2024
15 changes: 8 additions & 7 deletions apps/api-gateway/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import * as redisStore from 'cache-manager-redis-store';
import { WebhookModule } from './webhook/webhook.module';
import { UtilitiesModule } from './utilities/utilities.module';
import { NotificationModule } from './notification/notification.module';
import { GeoLocationModule } from './geo-location/geo-location.module';

@Module({
imports: [
Expand Down Expand Up @@ -53,15 +54,18 @@ import { NotificationModule } from './notification/notification.module';
UtilitiesModule,
WebhookModule,
NotificationModule,
CacheModule.register({ store: redisStore, host: process.env.REDIS_HOST, port: process.env.REDIS_PORT })
CacheModule.register({ store: redisStore, host: process.env.REDIS_HOST, port: process.env.REDIS_PORT }),
GeoLocationModule
],
controllers: [AppController],
providers: [AppService]
})
export class AppModule {
configure(userContext: MiddlewareConsumer): void {
userContext.apply(AuthzMiddleware)
.exclude({ path: 'authz', method: RequestMethod.ALL },
userContext
.apply(AuthzMiddleware)
.exclude(
{ path: 'authz', method: RequestMethod.ALL },
'authz/:splat*',
'admin/subscriptions',
'registry/organizations/',
Expand Down Expand Up @@ -90,9 +94,6 @@ export class AppModule {
'issue-credentials/national-id',
'labels/:id'
)
.forRoutes(
AgentController,
RevocationController
);
.forRoutes(AgentController, RevocationController);
}
}
64 changes: 64 additions & 0 deletions apps/api-gateway/src/geo-location/geo-location.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Controller, Get, HttpStatus, Logger, Param, Res } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { GeoLocationService } from './geo-location.service';
import { ApiResponseDto } from '../dtos/apiResponse.dto';
import IResponseType from '@credebl/common/interfaces/response.interface';
import { ResponseMessages } from '@credebl/common/response-messages';
import { Response } from 'express';
@Controller('/')
@ApiTags('geolocation')
export class GeoLocationController {
constructor(
private readonly geolocationService: GeoLocationService,
private readonly logger: Logger
) {}

/**
* @returns get all countries
*/
@Get('countries')
@ApiOperation({ summary: 'Get all countries', description: 'Get all countries' })
ganeshawle25 marked this conversation as resolved.
Show resolved Hide resolved
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto })
async getAllCountries(@Res() res: Response): Promise<Response> {
const countriesDetails = await this.geolocationService.getAllCountries();
const finalResponse: IResponseType = {
statusCode: HttpStatus.OK,
message: ResponseMessages.user.success.countriesVerificationCode,
data: countriesDetails
};
return res.status(HttpStatus.OK).json(finalResponse);
}

/**
* @returns get all states by countryId
*/

@Get('countries/:countryId/states')
@ApiOperation({summary: 'Get all states by using countryId ', description: 'Get all states by using countryId '
})
@ApiResponse({status: HttpStatus.OK, description: 'Success', type: ApiResponseDto})
async getStatesByCountryId(@Param('countryId') countryId: string, @Res() res: Response): Promise<Response> {
ganeshawle25 marked this conversation as resolved.
Show resolved Hide resolved
const statesDetails = await this.geolocationService.getStatesByCountryId(countryId);
const finalResponse: IResponseType = {
statusCode: HttpStatus.OK,
message: ResponseMessages.user.success.stateVerificationCode,
data: statesDetails
};
return res.status(HttpStatus.OK).json(finalResponse);
}
/**
* @returns get all cities by countryId and stateId
*/
@Get('countries/:countryId/states/:stateId/cities')
@ApiOperation({summary: 'Get all cities by using countryId and stateId', description: 'Get all cities by using countryId and stateId'})
@ApiResponse({ status: HttpStatus.OK, description: 'Success', type: ApiResponseDto })
async getCitiesByStateAndCountry(@Param('countryId') countryId: string, @Param('stateId') stateId: string, @Res() res: Response): Promise<Response> {
const citiesDetails = await this.geolocationService.getCitiesByStateAndCountry(countryId, stateId);
const finalResponse: IResponseType = {
statusCode: HttpStatus.OK,
message: ResponseMessages.user.success.cityVerificationCode,
data: citiesDetails
};
return res.status(HttpStatus.OK).json(finalResponse);
}
}
26 changes: 26 additions & 0 deletions apps/api-gateway/src/geo-location/geo-location.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Logger, Module } from '@nestjs/common';
import { GeoLocationController } from './geo-location.controller';
import { GeoLocationService } from './geo-location.service';
import { HttpModule } from '@nestjs/axios';
import { ConfigModule } from '@nestjs/config';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { getNatsOptions } from '@credebl/common/nats.config';
import { CommonModule } from '@credebl/common';

@Module({
imports: [
HttpModule,
ConfigModule.forRoot(),
ClientsModule.register([
{
name: 'NATS_CLIENT',
transport: Transport.NATS,
options: getNatsOptions(process.env.API_GATEWAY_NKEY_SEED)
ganeshawle25 marked this conversation as resolved.
Show resolved Hide resolved
},
CommonModule
])
],
controllers: [GeoLocationController],
providers: [GeoLocationService, Logger]
})
export class GeoLocationModule {}
46 changes: 46 additions & 0 deletions apps/api-gateway/src/geo-location/geo-location.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { CountryInterface, StateInterface, CityInterface } from '@credebl/common/interfaces/geolocation.interface';
import { Inject, Injectable } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { BaseService } from 'libs/service/base.service';

@Injectable()
export class GeoLocationService extends BaseService {
constructor(@Inject('NATS_CLIENT') private readonly serviceProxy: ClientProxy) {
super('GeoLocationService');
}

/**
*
* @param
* @returns Get all Countries list
*/
async getAllCountries(): Promise<CountryInterface[]> {
this.logger.log(`Finding all countries,GeoLocationService::getAllCountries`);
return this.sendNatsMessage(this.serviceProxy, 'get-all-countries', '');
}

/**
*
* @param
* @returns Get all states list by using countryId
*/
async getStatesByCountryId(countryId: string): Promise<StateInterface[]> {
const payload = { countryId };
this.logger.log(`Finding cities for countryId= ${countryId},GeoLocationService::getCitiesByStateAndCountry`);
return this.sendNatsMessage(this.serviceProxy, 'get-all-states', payload);
}

/**
*
* @param
* @returns Get all cities list by using stateId and countryId
*/

async getCitiesByStateAndCountry(countryId: string, stateId: string): Promise<CityInterface[]> {
const payload = { countryId, stateId };
this.logger.log(
`Finding cities for stateId= ${stateId} and countryId= ${countryId},GeoLocationService::getCitiesByStateAndCountry`
);
return this.sendNatsMessage(this.serviceProxy, 'get-all-cities', payload);
}
}
35 changes: 19 additions & 16 deletions apps/api-gateway/src/organization/dtos/create-organization-dto.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ApiExtraModels, ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { IsNotEmpty, IsOptional, IsString, IsUrl, MaxLength, MinLength } from 'class-validator';
import { IsNotEmpty, IsNumber, IsOptional, IsString, IsUrl, MaxLength, MinLength } from 'class-validator';

import { Transform } from 'class-transformer';
import { IsNotSQLInjection, trim } from '@credebl/common/cast.helper';
Expand Down Expand Up @@ -53,21 +53,24 @@ export class CreateOrganizationDto {
@IsString({ message: 'registrationNumber must be in string format.' })
registrationNumber?: string;

@ApiPropertyOptional()
@IsOptional()
@Transform(({ value }) => trim(value))
@IsString({ message: 'country must be in string format.' })
country?: string;
@ApiProperty({ example: 'IN' })
@IsNotEmpty({ message: 'country is required' })
@MinLength(2, { message: 'country must be at least 2 characters' })
@MaxLength(50, { message: 'country must be at most 50 characters' })
@IsNumber()
countryId?: number;

@ApiPropertyOptional()
@IsOptional()
@Transform(({ value }) => trim(value))
@IsString({ message: 'state must be in string format.' })
state?: string;
@ApiProperty({ example: 'MH' })
@IsNotEmpty({ message: 'state is required' })
@MinLength(2, { message: 'state must be at least 2 characters' })
@MaxLength(50, { message: 'state must be at most 50 characters' })
@IsNumber()
stateId?: number;

@ApiPropertyOptional()
@IsOptional()
@Transform(({ value }) => trim(value))
@IsString({ message: 'city must be in string format.' })
city?: string;
@ApiProperty({ example: 'Mumbai' })
@IsNotEmpty({ message: 'city is required' })
@MinLength(2, { message: 'city must be at least 2 characters' })
@MaxLength(50, { message: 'city must be at most 50 characters' })
@IsNumber()
cityId?: number;
}
24 changes: 24 additions & 0 deletions apps/geo-location/src/geo-location.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Controller } from '@nestjs/common';
import { GeoLocationService } from './geo-location.service';
import { MessagePattern } from '@nestjs/microservices';
import { CountryInterface, StateInterface, CityInterface } from '@credebl/common/interfaces/geolocation.interface';

@Controller()
export class GeoLocationController {
constructor(private readonly geoLocationService: GeoLocationService) {}

@MessagePattern({ cmd: 'get-all-countries' })
async getAllCountries(): Promise<CountryInterface[]> {
return this.geoLocationService.getAllCountries();
}

@MessagePattern({ cmd: 'get-all-states' })
async getStatesByCountryId(payload: { countryId: string }): Promise<StateInterface[]> {
return this.geoLocationService.getStatesByCountryId(payload);
}

@MessagePattern({ cmd: 'get-all-cities' })
async getCitiesByStateAndCountry(payload: { countryId: string; stateId: string }): Promise<CityInterface[]> {
ganeshawle25 marked this conversation as resolved.
Show resolved Hide resolved
return this.geoLocationService.getCitiesByStateAndCountry(payload);
}
}
26 changes: 26 additions & 0 deletions apps/geo-location/src/geo-location.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Logger, Module } from '@nestjs/common';
import { GeoLocationController } from './geo-location.controller';
import { GeoLocationService } from './geo-location.service';
import { ClientsModule, Transport } from '@nestjs/microservices';
import { CommonModule } from '@credebl/common';
import { CacheModule } from '@nestjs/cache-manager';
import { getNatsOptions } from '@credebl/common/nats.config';
import { PrismaService } from '@credebl/prisma-service';
import { GeoLocationRepository } from './geo-location.repository';

@Module({
imports: [
ClientsModule.register([
{
name: 'NATS_CLIENT',
transport: Transport.NATS,
options: getNatsOptions(process.env.GEOLOCATION_NKEY_SEED)
}
]),
CommonModule,
CacheModule.register()
],
controllers: [GeoLocationController],
providers: [GeoLocationService, Logger, PrismaService, GeoLocationRepository]
})
export class GeoLocationModule {}
63 changes: 63 additions & 0 deletions apps/geo-location/src/geo-location.repository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { CountryInterface, StateInterface, CityInterface } from '@credebl/common/interfaces/geolocation.interface';
import { PrismaService } from '@credebl/prisma-service';
import { Injectable, Logger } from '@nestjs/common';

@Injectable()
export class GeoLocationRepository {
constructor(
private readonly prisma: PrismaService,
private readonly logger: Logger
) {}

async findAllCountries(): Promise<CountryInterface[]> {
try {
return await this.prisma.countries.findMany({
select: {
id: true,
name: true
}
});
} catch (error) {
this.logger.error(`Error in GeoLocationRepository::[findAllCountries]: ${error}`);
throw error;
}
}
async findStatesByCountryId(countryId: string): Promise<StateInterface[]> {
try {
return await this.prisma.states.findMany({
where: { countryId: Number(countryId) },
select: {
id: true,
name: true,
countryId: true,
countryCode: true
}
});
} catch (error) {
this.logger.error(`Error in GeoLocationRepository::[findStatesByCountryId]: ${error} `);
throw error;
}
}

async findCitiesByStateAndCountry(countryId: string, stateId: string): Promise<CityInterface[]> {
try {
return await this.prisma.cities.findMany({
where: {
stateId: Number(stateId),
countryId: Number(countryId)
},
select: {
id: true,
name: true,
stateId: true,
stateCode: true,
countryId: true,
countryCode: true
}
});
} catch (error) {
this.logger.error(`Error finding cities for stateId ${stateId} and countryId ${countryId}: ${error}`);
throw error;
}
}
}
Loading