wip
This commit is contained in:
parent
95310651d8
commit
1f9a9896e9
|
@ -36,7 +36,8 @@
|
||||||
"got": "^11.8.6",
|
"got": "^11.8.6",
|
||||||
"ioredis": "^5.3.1",
|
"ioredis": "^5.3.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.2.0"
|
"rxjs": "^7.2.0",
|
||||||
|
"timezonecomplete": "^5.12.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "^9.0.0",
|
"@nestjs/cli": "^9.0.0",
|
||||||
|
@ -8576,6 +8577,14 @@
|
||||||
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
|
"integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/timezonecomplete": {
|
||||||
|
"version": "5.12.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/timezonecomplete/-/timezonecomplete-5.12.4.tgz",
|
||||||
|
"integrity": "sha512-K+ocagBAl5wu9Ifh5oHKhRRLb0wP7j0VjAzjboZsT6bnVmtJNRe3Wnk2IPp0C4Uc8HpLly3gbfUrTlJ3M7vCPA==",
|
||||||
|
"dependencies": {
|
||||||
|
"tzdata": "^1.0.25"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/tmp": {
|
"node_modules/tmp": {
|
||||||
"version": "0.0.33",
|
"version": "0.0.33",
|
||||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||||
|
@ -8867,6 +8876,11 @@
|
||||||
"node": ">=4.2.0"
|
"node": ">=4.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tzdata": {
|
||||||
|
"version": "1.0.38",
|
||||||
|
"resolved": "https://registry.npmjs.org/tzdata/-/tzdata-1.0.38.tgz",
|
||||||
|
"integrity": "sha512-KIgVvZTLt+DWzr3MOENNLCLdsNB+usedRYYHCVfVbA7TDewj8mfjlWmj3Mv6FfdrvfeE6Oprt+qE47YiL90duQ=="
|
||||||
|
},
|
||||||
"node_modules/uid": {
|
"node_modules/uid": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/uid/-/uid-2.0.2.tgz",
|
||||||
|
|
|
@ -59,7 +59,8 @@
|
||||||
"got": "^11.8.6",
|
"got": "^11.8.6",
|
||||||
"ioredis": "^5.3.1",
|
"ioredis": "^5.3.1",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
"rxjs": "^7.2.0"
|
"rxjs": "^7.2.0",
|
||||||
|
"timezonecomplete": "^5.12.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@nestjs/cli": "^9.0.0",
|
"@nestjs/cli": "^9.0.0",
|
||||||
|
|
|
@ -7,6 +7,9 @@ import { CreateAdUseCase } from './domain/usecases/create-ad.usecase';
|
||||||
import { AdRepository } from './adapters/secondaries/ad.repository';
|
import { AdRepository } from './adapters/secondaries/ad.repository';
|
||||||
import { DatabaseModule } from '../database/database.module';
|
import { DatabaseModule } from '../database/database.module';
|
||||||
import { CqrsModule } from '@nestjs/cqrs';
|
import { CqrsModule } from '@nestjs/cqrs';
|
||||||
|
import { Messager } from './adapters/secondaries/messager';
|
||||||
|
import { TimezoneFinder } from './adapters/secondaries/timezone-finder';
|
||||||
|
import { GeoTimezoneFinder } from '../geography/adapters/secondaries/geo-timezone-finder';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -36,7 +39,14 @@ import { CqrsModule } from '@nestjs/cqrs';
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
controllers: [AdMessagerController],
|
controllers: [AdMessagerController],
|
||||||
providers: [AdProfile, AdRepository, CreateAdUseCase],
|
providers: [
|
||||||
|
AdProfile,
|
||||||
|
Messager,
|
||||||
|
AdRepository,
|
||||||
|
TimezoneFinder,
|
||||||
|
GeoTimezoneFinder,
|
||||||
|
CreateAdUseCase,
|
||||||
|
],
|
||||||
exports: [],
|
exports: [],
|
||||||
})
|
})
|
||||||
export class AdModule {}
|
export class AdModule {}
|
||||||
|
|
|
@ -6,51 +6,59 @@ import { Mapper } from '@automapper/core';
|
||||||
import { CommandBus } from '@nestjs/cqrs';
|
import { CommandBus } from '@nestjs/cqrs';
|
||||||
import { CreateAdCommand } from '../../commands/create-ad.command';
|
import { CreateAdCommand } from '../../commands/create-ad.command';
|
||||||
import { CreateAdRequest } from '../../domain/dtos/create-ad.request';
|
import { CreateAdRequest } from '../../domain/dtos/create-ad.request';
|
||||||
import { ValidationError, validateOrReject } from 'class-validator';
|
import { validateOrReject } from 'class-validator';
|
||||||
|
import { Messager } from '../secondaries/messager';
|
||||||
|
import { GeoTimezoneFinder } from 'src/modules/geography/adapters/secondaries/geo-timezone-finder';
|
||||||
|
|
||||||
@Controller()
|
@Controller()
|
||||||
export class AdMessagerController {
|
export class AdMessagerController {
|
||||||
constructor(
|
constructor(
|
||||||
|
private readonly messager: Messager,
|
||||||
private readonly commandBus: CommandBus,
|
private readonly commandBus: CommandBus,
|
||||||
@InjectMapper() private readonly mapper: Mapper,
|
@InjectMapper() private readonly mapper: Mapper,
|
||||||
|
private readonly timezoneFinder: GeoTimezoneFinder,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@RabbitSubscribe({
|
@RabbitSubscribe({
|
||||||
name: 'adCreated',
|
name: 'adCreated',
|
||||||
})
|
})
|
||||||
async adCreatedHandler(message: string): Promise<void> {
|
async adCreatedHandler(message: string): Promise<void> {
|
||||||
|
let createAdRequest: CreateAdRequest;
|
||||||
try {
|
try {
|
||||||
// parse message to conform to CreateAdRequest (not a real instance yet)
|
// parse message to conform to CreateAdRequest (not a real instance yet)
|
||||||
const parsedMessage: CreateAdRequest = JSON.parse(message);
|
const parsedMessage: CreateAdRequest = JSON.parse(message);
|
||||||
console.log(parsedMessage);
|
|
||||||
// create a real instance of CreateAdRequest from parsed message
|
// create a real instance of CreateAdRequest from parsed message
|
||||||
// const createAdRequest: CreateAdRequest = this.mapper.map(
|
createAdRequest = this.mapper.map(
|
||||||
// parsedMessage,
|
parsedMessage,
|
||||||
// CreateAdRequest,
|
CreateAdRequest,
|
||||||
// CreateAdRequest,
|
CreateAdRequest,
|
||||||
// );
|
);
|
||||||
const createAdRequest = new CreateAdRequest();
|
|
||||||
createAdRequest.originType = parsedMessage.originType;
|
|
||||||
createAdRequest.destinationType = parsedMessage.destinationType;
|
|
||||||
createAdRequest.waypoints = parsedMessage.waypoints.map((waypoint) => ({
|
|
||||||
lon: waypoint.lon,
|
|
||||||
lat: waypoint.lat,
|
|
||||||
}));
|
|
||||||
console.log(createAdRequest);
|
|
||||||
// validate instance
|
// validate instance
|
||||||
await validateOrReject(createAdRequest.waypoints[0]);
|
await validateOrReject(createAdRequest);
|
||||||
|
// validate nested objects (fixes direct nested validation bug)
|
||||||
|
for (const waypoint of createAdRequest.waypoints) {
|
||||||
|
try {
|
||||||
|
await validateOrReject(waypoint);
|
||||||
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createAdRequest.timezone = this.timezoneFinder.timezones(
|
||||||
|
createAdRequest.waypoints[0].lon,
|
||||||
|
createAdRequest.waypoints[0].lat,
|
||||||
|
)[0];
|
||||||
const ad: Ad = await this.commandBus.execute(
|
const ad: Ad = await this.commandBus.execute(
|
||||||
new CreateAdCommand(createAdRequest),
|
new CreateAdCommand(createAdRequest),
|
||||||
);
|
);
|
||||||
console.log(ad);
|
console.log(ad);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (Array.isArray(e)) {
|
this.messager.publish(
|
||||||
e.forEach((error) =>
|
'logging.matcher.ad.crit',
|
||||||
error instanceof ValidationError
|
JSON.stringify({
|
||||||
? console.log(error.constraints)
|
createAdRequest,
|
||||||
: console.log(error),
|
error: e,
|
||||||
);
|
}),
|
||||||
}
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export abstract class MessageBroker {
|
||||||
|
exchange: string;
|
||||||
|
|
||||||
|
constructor(exchange: string) {
|
||||||
|
this.exchange = exchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract publish(routingKey: string, message: string): void;
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { MessageBroker } from './message-broker';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class Messager extends MessageBroker {
|
||||||
|
constructor(
|
||||||
|
private readonly _amqpConnection: AmqpConnection,
|
||||||
|
configService: ConfigService,
|
||||||
|
) {
|
||||||
|
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||||
|
}
|
||||||
|
|
||||||
|
publish = (routingKey: string, message: string): void => {
|
||||||
|
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||||
|
};
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { GeoTimezoneFinder } from '../../../geography/adapters/secondaries/geo-timezone-finder';
|
||||||
|
import { IFindTimezone } from '../../../geography/domain/interfaces/timezone-finder.interface';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class TimezoneFinder implements IFindTimezone {
|
||||||
|
constructor(private readonly geoTimezoneFinder: GeoTimezoneFinder) {}
|
||||||
|
|
||||||
|
timezones = (lon: number, lat: number): string[] =>
|
||||||
|
this.geoTimezoneFinder.timezones(lon, lat);
|
||||||
|
}
|
|
@ -8,12 +8,10 @@ import {
|
||||||
IsNumber,
|
IsNumber,
|
||||||
IsOptional,
|
IsOptional,
|
||||||
IsString,
|
IsString,
|
||||||
ValidateNested,
|
|
||||||
} from 'class-validator';
|
} from 'class-validator';
|
||||||
import { PointType } from '../../../geography/domain/types/point-type.enum';
|
import { PointType } from '../../../geography/domain/types/point-type.enum';
|
||||||
import { Frequency } from '../types/frequency.enum';
|
import { Frequency } from '../types/frequency.enum';
|
||||||
import { Coordinates } from '../../../geography/domain/types/coordinates.type';
|
import { Coordinates } from '../../../geography/domain/entities/coordinates';
|
||||||
import { Type } from 'class-transformer';
|
|
||||||
|
|
||||||
export class CreateAdRequest {
|
export class CreateAdRequest {
|
||||||
@IsString()
|
@IsString()
|
||||||
|
@ -114,9 +112,7 @@ export class CreateAdRequest {
|
||||||
destinationType: PointType;
|
destinationType: PointType;
|
||||||
|
|
||||||
@IsArray()
|
@IsArray()
|
||||||
@ValidateNested({ each: true })
|
|
||||||
@ArrayMinSize(2)
|
@ArrayMinSize(2)
|
||||||
@Type(() => Coordinates)
|
|
||||||
@AutoMap(() => [Coordinates])
|
@AutoMap(() => [Coordinates])
|
||||||
waypoints: Coordinates[];
|
waypoints: Coordinates[];
|
||||||
|
|
||||||
|
@ -140,4 +136,6 @@ export class CreateAdRequest {
|
||||||
@IsString()
|
@IsString()
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
updatedAt: string;
|
updatedAt: string;
|
||||||
|
|
||||||
|
timezone: string;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import { AutoMap } from '@automapper/classes';
|
import { AutoMap } from '@automapper/classes';
|
||||||
import { PointType } from '../../../geography/domain/types/point-type.enum';
|
import { PointType } from '../../../geography/domain/types/point-type.enum';
|
||||||
import { Coordinates } from '../../../geography/domain/types/coordinates.type';
|
import { Coordinates } from '../../../geography/domain/entities/coordinates';
|
||||||
|
|
||||||
export class Ad {
|
export class Ad {
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
|
@ -22,7 +22,7 @@ export class Ad {
|
||||||
toDate: Date;
|
toDate: Date;
|
||||||
|
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
monTime: string;
|
monTime: Date;
|
||||||
|
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
tueTime: string;
|
tueTime: string;
|
||||||
|
|
|
@ -4,7 +4,8 @@ import { Injectable } from '@nestjs/common';
|
||||||
import { Ad } from '../domain/entities/ad';
|
import { Ad } from '../domain/entities/ad';
|
||||||
import { AdPresenter } from '../adapters/primaries/ad.presenter';
|
import { AdPresenter } from '../adapters/primaries/ad.presenter';
|
||||||
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
|
import { CreateAdRequest } from '../domain/dtos/create-ad.request';
|
||||||
import { Coordinates } from 'src/modules/geography/domain/types/coordinates.type';
|
import { Coordinates } from '../../geography/domain/entities/coordinates';
|
||||||
|
import moment from 'moment-timezone';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class AdProfile extends AutomapperProfile {
|
export class AdProfile extends AutomapperProfile {
|
||||||
|
@ -21,16 +22,14 @@ export class AdProfile extends AutomapperProfile {
|
||||||
CreateAdRequest,
|
CreateAdRequest,
|
||||||
forMember(
|
forMember(
|
||||||
(dest) => dest.waypoints,
|
(dest) => dest.waypoints,
|
||||||
mapFrom(
|
mapFrom((source) =>
|
||||||
(source) =>
|
source.waypoints.map(
|
||||||
source.waypoints.map(
|
(waypoint) =>
|
||||||
(waypoint) =>
|
new Coordinates(
|
||||||
new Coordinates(
|
waypoint.lon ?? undefined,
|
||||||
waypoint.lon ?? undefined,
|
waypoint.lat ?? undefined,
|
||||||
waypoint.lat ?? undefined,
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
// .filter((waypoint) => waypoint),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -54,6 +53,18 @@ export class AdProfile extends AutomapperProfile {
|
||||||
(dest) => dest.updatedAt,
|
(dest) => dest.updatedAt,
|
||||||
mapFrom((source) => new Date(source.updatedAt)),
|
mapFrom((source) => new Date(source.updatedAt)),
|
||||||
),
|
),
|
||||||
|
// forMember(
|
||||||
|
// (dest) => dest.monTime,
|
||||||
|
// mapFrom((source) =>
|
||||||
|
// source.monTime
|
||||||
|
// ? new Date(
|
||||||
|
// moment
|
||||||
|
// .tz(`${source.fromDate} ${source.monTime}`, source.timezone)
|
||||||
|
// .format(),
|
||||||
|
// )
|
||||||
|
// : undefined,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
import { createMap, Mapper } from '@automapper/core';
|
|
||||||
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
|
|
||||||
import { Injectable } from '@nestjs/common';
|
|
||||||
import { Coordinates } from '../../geography/domain/types/coordinates.type';
|
|
||||||
|
|
||||||
@Injectable()
|
|
||||||
export class CoordinatesProfile extends AutomapperProfile {
|
|
||||||
constructor(@InjectMapper() mapper: Mapper) {
|
|
||||||
super(mapper);
|
|
||||||
}
|
|
||||||
|
|
||||||
override get profile() {
|
|
||||||
return (mapper: any) => {
|
|
||||||
createMap(mapper, Coordinates, Coordinates);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { PointType } from './point-type.enum';
|
import { PointType } from './point-type.enum';
|
||||||
import { Coordinates } from './coordinates.type';
|
import { Coordinates } from '../entities/coordinates';
|
||||||
|
|
||||||
export type Point = Coordinates & {
|
export type Point = Coordinates & {
|
||||||
type?: PointType;
|
type?: PointType;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { Coordinates } from 'src/modules/geography/domain/types/coordinates.type';
|
import { Coordinates } from '../../../../geography/domain/entities/coordinates';
|
||||||
|
|
||||||
export class SpacetimePoint {
|
export class SpacetimePoint {
|
||||||
coordinates: Coordinates;
|
coordinates: Coordinates;
|
||||||
|
|
|
@ -11,7 +11,6 @@ import { Day } from '../../types/day.type';
|
||||||
|
|
||||||
export class Time {
|
export class Time {
|
||||||
private timeRequest: IRequestTime;
|
private timeRequest: IRequestTime;
|
||||||
private defaultMarginDuration: number;
|
|
||||||
private defaultValidityDuration: number;
|
private defaultValidityDuration: number;
|
||||||
frequency: Frequency;
|
frequency: Frequency;
|
||||||
fromDate: Date;
|
fromDate: Date;
|
||||||
|
@ -25,7 +24,6 @@ export class Time {
|
||||||
defaultValidityDuration: number,
|
defaultValidityDuration: number,
|
||||||
) {
|
) {
|
||||||
this.timeRequest = timeRequest;
|
this.timeRequest = timeRequest;
|
||||||
this.defaultMarginDuration = defaultMarginDuration;
|
|
||||||
this.defaultValidityDuration = defaultValidityDuration;
|
this.defaultValidityDuration = defaultValidityDuration;
|
||||||
this.schedule = {};
|
this.schedule = {};
|
||||||
this.marginDurations = {
|
this.marginDurations = {
|
||||||
|
|
Loading…
Reference in New Issue