diff --git a/README.md b/README.md
index 2e252ffe..1cef5baf 100644
--- a/README.md
+++ b/README.md
@@ -1,14 +1,15 @@
Cats Cradle :yarn:
-Get ready to embark on an adventure with **Cats Cradle** - the upcoming co-op
-RPG that will transport you to a nostalgic world filled with wonder. Join us on
-this exciting journey as we continue to develop and bring this game to life.
+Embark on an nostalgic adventure with **Cats Cradle** - the upcoming co-op RPG
+that will transport you to a world filled with wonder. Join us on this journey
+as we flesh in the game and bring it to life.
-This repo houses the game's code. This enterprise architecture monorepo includes
-numerous microservices built on a PaaS with IaC for streamlined DevOps CI/CD.
+This repo houses the game's code in a enterprise architecture monorepo. It
+includes numerous microservices built on a PaaS with IaC for streamlined DevOps
+CI/CD.
-Although each package is maintained primarily for the game, most stable packages
-are individually published to
+Although each package is maintained primarily for the game, most of the stable
+packages are individually published to
[NPM](https://www.npmjs.com/search?q=%40cats-cradle) and available under
open-source software license.
diff --git a/services/character-sheet/openapi-spec.json b/services/character-sheet/openapi-spec.json
index 34732f45..115be073 100644
--- a/services/character-sheet/openapi-spec.json
+++ b/services/character-sheet/openapi-spec.json
@@ -149,7 +149,7 @@
"SNOW_LEOPARD",
"CHIMERA",
"SLOW_MOVER",
- "SNAKE_OF_WATER",
+ "SNAKE_OF_THE_WATER",
"BANDIT",
"ROWAN",
"CHUBBS"
@@ -547,7 +547,7 @@
"required": true,
"in": "path",
"schema": {
- "default": "1f0fb038-21f8-47ff-9de1-010502a010d3",
+ "default": "9201a8eb-e105-4760-938f-0afc6166834c",
"type": "string"
}
}
@@ -586,11 +586,11 @@
"properties": {
"_id": {
"type": "string",
- "default": "de2e5e17-70ee-4c27-b01a-c38bc6c3e4e2"
+ "default": "afdd27df-e56f-42b5-a76b-668bb791375b"
},
"instanceId": {
"type": "string",
- "default": "26be8bd5-5d6f-4bbd-8878-b14675fc8dd5"
+ "default": "f1641d0f-9595-4677-9949-b29dbceaf3e7"
},
"archetypeId": {
"type": "string",
@@ -630,7 +630,7 @@
"SNOW_LEOPARD",
"CHIMERA",
"SLOW_MOVER",
- "SNAKE_OF_WATER",
+ "SNAKE_OF_THE_WATER",
"BANDIT",
"ROWAN",
"CHUBBS"
@@ -647,11 +647,11 @@
"properties": {
"id": {
"type": "string",
- "default": "be51385e-9c08-40ba-b92c-d6b3790db555"
+ "default": "1077d648-a6aa-468b-86f7-788e42421f90"
},
"instanceId": {
"type": "string",
- "default": "2e308a56-a26d-4513-ba79-2a412f5c113b"
+ "default": "7b6744b0-f364-4833-9c5d-2273361f32b1"
},
"place": {
"type": "string",
@@ -674,7 +674,7 @@
"properties": {
"characterSheetId": {
"type": "string",
- "default": "8eddefd6-612c-421b-a033-ac5234a330e4"
+ "default": "88623540-0638-4e3d-8e15-a86792290835"
},
"affiliationId": {
"type": "string",
diff --git a/services/character-sheet/package.json b/services/character-sheet/package.json
index f2f62562..c079132c 100644
--- a/services/character-sheet/package.json
+++ b/services/character-sheet/package.json
@@ -40,7 +40,6 @@
"aws-lambda": "1.0.7",
"aws-serverless-express": "~3.4.0",
"class-transformer": "0.5.1",
- "class-validator": "0.13.2",
"express": "4.18.2",
"node-cache": "5.1.2",
"reflect-metadata": "0.1.13",
diff --git a/services/weather-control/src/module/weather/query.dto.ts b/services/weather-control/src/module/weather/query.dto.ts
index ee831106..fd5a4f76 100644
--- a/services/weather-control/src/module/weather/query.dto.ts
+++ b/services/weather-control/src/module/weather/query.dto.ts
@@ -1,7 +1,16 @@
import { IsLongitude, IsLatitude } from '@cats-cradle/validation-schemas';
import { ApiProperty } from '@nestjs/swagger';
+import { IsDate } from 'class-validator';
export class QueryDto {
+ @IsDate()
+ @ApiProperty({
+ description: 'Date',
+ default: new Date(),
+ type: String,
+ })
+ date: string;
+
@IsLatitude()
@ApiProperty({
description: 'Latitude',
diff --git a/services/weather-control/src/module/weather/weather.controller.ts b/services/weather-control/src/module/weather/weather.controller.ts
index 4765e600..c61fa40f 100644
--- a/services/weather-control/src/module/weather/weather.controller.ts
+++ b/services/weather-control/src/module/weather/weather.controller.ts
@@ -8,16 +8,18 @@ import {
Query,
} from '@nestjs/common';
import { WeatherService } from './weather.service';
+import { QueryDto } from './query.dto';
@Controller({ path: 'weather', version: ['1', VERSION_NEUTRAL] })
export class WeatherController {
constructor(private readonly weatherService: WeatherService) {}
@Post()
- async fetch(
- @Query('latitude') latitude: number,
- @Query('longitude') longitude: number,
- ) {
- return this.weatherService.get(latitude, longitude);
+ async fetch(@Body() body: QueryDto) {
+ return this.weatherService.get(
+ new Date(body.date),
+ body.latitude,
+ body.longitude,
+ );
}
}
diff --git a/services/weather-control/src/module/weather/weather.e2e-spec.ts b/services/weather-control/src/module/weather/weather.e2e-spec.ts
index 2b389b78..6f94ee3c 100644
--- a/services/weather-control/src/module/weather/weather.e2e-spec.ts
+++ b/services/weather-control/src/module/weather/weather.e2e-spec.ts
@@ -1,11 +1,12 @@
import supertest from 'supertest';
import { Test, TestingModule } from '@nestjs/testing';
-import { INestApplication, Injectable } from '@nestjs/common';
+import { INestApplication } from '@nestjs/common';
import { FakerFactory } from '@cats-cradle/faker-factory';
import { WeatherService } from './weather.service';
import { WeatherController } from './weather.controller';
import { ClimateType } from './climates.type';
import { QueryDto } from './query.dto';
+import { TimeOfDayType } from './time-of-day.type';
describe('/weather', () => {
let app: INestApplication;
@@ -30,21 +31,63 @@ describe('/weather', () => {
});
describe('POST /weather', () => {
- it('should determine climate', async () => {
- const body = await FakerFactory.create(QueryDto, {
- // longitude: '0',
- });
- console.log(body);
- console.log(body);
-
- const response = await supertest(app.getHttpServer())
- .post('/weather')
- .send(body)
- .expect(201);
-
- expect(response.body).toMatchObject({
- climate: ClimateType.POLAR,
- });
- });
+ it.each([
+ [0, TimeOfDayType.MIDNIGHT],
+ [2, TimeOfDayType.MIDNIGHT],
+ [5, TimeOfDayType.DAWN],
+ [8, TimeOfDayType.MORNING],
+ [12, TimeOfDayType.NOON],
+ [17, TimeOfDayType.EVENING],
+ [20, TimeOfDayType.DUSK],
+ [23, TimeOfDayType.MIDNIGHT],
+ ])(
+ 'should determine hour %i as %s',
+ async (hour: number, timeOfDay: TimeOfDayType) => {
+ const now = new Date();
+ now.setHours(hour);
+
+ const body = await FakerFactory.create(QueryDto, {
+ date: now.toISOString(),
+ });
+
+ const response = await supertest(app.getHttpServer())
+ .post('/weather')
+ .send(body)
+ .expect(201);
+
+ expect(response.body).toMatchObject({
+ timeOfDay,
+ });
+ },
+ );
+
+ it.each([
+ [60, ClimateType.POLAR],
+ [40, ClimateType.CONTINENTAL],
+ [25, ClimateType.TEMPERATE],
+ [20, ClimateType.DRY],
+ [-15, ClimateType.TROPICAL],
+ [-20, ClimateType.DRY],
+ [-25, ClimateType.TEMPERATE],
+ [-40, ClimateType.CONTINENTAL],
+ [-60, ClimateType.POLAR],
+ [-90, ClimateType.POLAR],
+ ])(
+ 'should determine climate %i as %s',
+ async (latitude: number, climate: ClimateType) => {
+ const body = await FakerFactory.create(QueryDto, {
+ latitude: latitude.toString(),
+ });
+
+ const response = await supertest(app.getHttpServer())
+ .post('/weather')
+ .send(body)
+ .expect(201);
+
+ expect(response.body).toMatchObject({
+ climate,
+ });
+ },
+ );
});
});
diff --git a/services/weather-control/src/module/weather/weather.service.ts b/services/weather-control/src/module/weather/weather.service.ts
index ca15d011..b8586fff 100644
--- a/services/weather-control/src/module/weather/weather.service.ts
+++ b/services/weather-control/src/module/weather/weather.service.ts
@@ -1,37 +1,70 @@
/* eslint @typescript-eslint/no-var-requires: "off" */
import { Injectable } from '@nestjs/common';
import { ClimateType } from './climates.type';
+import { TimeOfDayType } from './time-of-day.type';
@Injectable()
export class WeatherService {
- async get(longitude: number, latitude: number): Promise {
- const climate = this.getClimate(latitude);
+ async get(
+ date: Date,
+ latitude: number | string,
+ longitude: number | string,
+ ): Promise {
return {
- climate,
+ timeOfDay: this.getTimeOfDay(date),
+ climate: this.getClimate(latitude),
};
}
+ // time of day effects are based on time
+ getTimeOfDay(date?: Date): TimeOfDayType {
+ if (date === undefined) {
+ date = new Date();
+ }
+ const hour = date.getHours();
+
+ switch (true) {
+ case hour >= 0 && hour < 4:
+ return TimeOfDayType.MIDNIGHT;
+ case hour >= 4 && hour < 6:
+ return TimeOfDayType.DAWN;
+ case hour >= 6 && hour < 10:
+ return TimeOfDayType.MORNING;
+ case hour >= 10 && hour < 16:
+ return TimeOfDayType.NOON;
+ case hour >= 16 && hour < 20:
+ return TimeOfDayType.EVENING;
+ case hour >= 20 && hour < 21:
+ return TimeOfDayType.DUSK;
+ case hour >= 21 && hour < 24:
+ default:
+ return TimeOfDayType.MIDNIGHT;
+ }
+ }
+
// ranges from 90, -90 angle (180 degrees mirrored on both sides of world)
// pattern is generally polar climate, temperate and continental, dry climates, tropical climate
- getClimate(latitude: number) {
+ getClimate(latitude: number | string): ClimateType {
+ const value = Number(latitude);
+
switch (true) {
- case latitude > 60:
+ case value >= 60:
return ClimateType.POLAR;
- case latitude > 40:
+ case value >= 40:
return ClimateType.CONTINENTAL;
- case latitude > 25:
+ case value >= 25:
return ClimateType.TEMPERATE;
- case latitude > 20:
+ case value >= 20:
return ClimateType.DRY;
- case latitude > -15:
+ case value >= -15:
return ClimateType.TROPICAL;
- case latitude > -20:
+ case value >= -20:
return ClimateType.DRY;
- case latitude > -25:
+ case value >= -25:
return ClimateType.TEMPERATE;
- case latitude > -40:
+ case value >= -40:
return ClimateType.CONTINENTAL;
- case latitude < -60:
+ case value <= -60:
default:
return ClimateType.POLAR;
}