From e43074e450eb19272fe01f4397bf86193a066681 Mon Sep 17 00:00:00 2001 From: Lihini Senanayake Date: Sat, 6 Jan 2024 20:01:59 +0530 Subject: [PATCH 1/5] fix: internal server error returned when latest weather data is not available --- .../weather-stations/weather-stations.controller.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/modules/weather-stations/weather-stations.controller.ts b/src/modules/weather-stations/weather-stations.controller.ts index 4b7b4c3..0b54987 100644 --- a/src/modules/weather-stations/weather-stations.controller.ts +++ b/src/modules/weather-stations/weather-stations.controller.ts @@ -67,6 +67,13 @@ export class WeatherStationsController { weatherStationId, ); + if (!weatherData) { + return { + weatherData: null, + pointsOfUser: null, + }; + } + // Get points of the user of the weather station. const pointsOfUser = await this.pointsService.findByUserId( weatherData.author_user_id, From 20b5e5f7dc103168a08f1e759878f35965655990 Mon Sep 17 00:00:00 2001 From: Lihini Senanayake Date: Tue, 9 Jan 2024 02:28:59 +0530 Subject: [PATCH 2/5] fix: change cron job schedule to run at 11:45 PM Sri Lanka time --- src/modules/points/points.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/points/points.service.ts b/src/modules/points/points.service.ts index 049e36c..9695858 100644 --- a/src/modules/points/points.service.ts +++ b/src/modules/points/points.service.ts @@ -54,8 +54,8 @@ export class PointsService { @InjectConnection() private readonly mongoConnection: Connection, ) {} - @Cron(CronExpression.EVERY_DAY_AT_11PM) // @Cron('*/10 * * * * *') // Every 5 seconds + @Cron('15 18 * * *') // 6:15 PM server time (UTC), 11:45 PM local time async handleInspectPointReductionForTheDayCron() { console.log('Running cron'); From 5b8c877df0dfff70c8f8f374073727aa3c557804 Mon Sep 17 00:00:00 2001 From: Lihini Senanayake Date: Tue, 9 Jan 2024 02:30:53 +0530 Subject: [PATCH 3/5] fix: tslint errors --- src/modules/points/points.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/points/points.service.ts b/src/modules/points/points.service.ts index 9695858..852e289 100644 --- a/src/modules/points/points.service.ts +++ b/src/modules/points/points.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@nestjs/common'; import { InjectConnection, InjectModel } from '@nestjs/mongoose'; -import { Cron, CronExpression } from '@nestjs/schedule'; +import { Cron } from '@nestjs/schedule'; import mongoose, { Connection, Model } from 'mongoose'; import { PointTransactionTypes } from '../common/enums/point-transaction-types.enum'; import { CreateWeatherDatumDto } from '../weather-data/dto/create-weather-datum.dto'; From 27a4f03f6b0547e0f642ada403523cfa6b240c25 Mon Sep 17 00:00:00 2001 From: Lihini Senanayake Date: Tue, 9 Jan 2024 22:53:23 +0530 Subject: [PATCH 4/5] fix: daily bonus points not added when data is uploaded before 5:30 AM Sri Lanka time --- package-lock.json | 31 +++++++++++++++++++-- package.json | 6 +++-- src/modules/points/points.service.spec.ts | 33 +++++++++++++++++++++++ src/modules/points/points.service.ts | 21 +++++++++++---- 4 files changed, 82 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4cecdd4..3cf09b5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "weatherkids-data-api", - "version": "0.0.1", + "version": "0.0.4", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "weatherkids-data-api", - "version": "0.0.1", + "version": "0.0.4", "license": "UNLICENSED", "dependencies": { "@nestjs/common": "^10.2.10", @@ -24,6 +24,7 @@ "firebase-admin": "^11.11.0", "firebase-functions": "^4.6.0", "google-auth-library": "^9.2.0", + "moment": "^2.30.1", "mongoose": "^7.5.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", @@ -44,6 +45,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", "jest": "^29.7.0", + "mockdate": "^3.0.5", "mongodb": "^6.3.0", "mongodb-memory-server": "^9.1.4", "prettier": "^3.0.0", @@ -9298,6 +9300,20 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mockdate": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.5.tgz", + "integrity": "sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==", + "dev": true + }, + "node_modules/moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", + "engines": { + "node": "*" + } + }, "node_modules/mongodb": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.3.0.tgz", @@ -19566,6 +19582,17 @@ "minimist": "^1.2.6" } }, + "mockdate": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/mockdate/-/mockdate-3.0.5.tgz", + "integrity": "sha512-iniQP4rj1FhBdBYS/+eQv7j1tadJ9lJtdzgOpvsOHng/GbcDh2Fhdeq+ZRldrPYdXvCyfFUmFeEwEGXZB5I/AQ==", + "dev": true + }, + "moment": { + "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==" + }, "mongodb": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.3.0.tgz", diff --git a/package.json b/package.json index c7df0c1..85fd328 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "weatherkids-data-api", - "version": "0.0.3", + "version": "0.0.4", "description": "", "author": "", "private": true, @@ -41,6 +41,7 @@ "firebase-admin": "^11.11.0", "firebase-functions": "^4.6.0", "google-auth-library": "^9.2.0", + "moment": "^2.30.1", "mongoose": "^7.5.3", "reflect-metadata": "^0.1.13", "rxjs": "^7.8.1", @@ -61,6 +62,7 @@ "eslint-config-prettier": "^9.0.0", "eslint-plugin-prettier": "^5.0.0", "jest": "^29.7.0", + "mockdate": "^3.0.5", "mongodb": "^6.3.0", "mongodb-memory-server": "^9.1.4", "prettier": "^3.0.0", @@ -93,4 +95,4 @@ }, "preset": "@shelf/jest-mongodb" } -} \ No newline at end of file +} diff --git a/src/modules/points/points.service.spec.ts b/src/modules/points/points.service.spec.ts index e781dc5..e2fa970 100644 --- a/src/modules/points/points.service.spec.ts +++ b/src/modules/points/points.service.spec.ts @@ -29,6 +29,7 @@ import { JwtService } from '@nestjs/jwt'; import { UsersService } from '../users/users.service'; import { OAuth2Client } from 'google-auth-library'; import { User, UserSchema } from '../users/entities/user.entity'; +import { set, reset } from 'mockdate'; describe('PointsService', () => { let pointsService: PointsService; @@ -166,5 +167,37 @@ describe('PointsService', () => { PointsConfigs.POINTS_PER_HOUR + PointsConfigs.POINTS_PER_DAY, ); }); + + it('should add bonus points if the user has uploaded data on the same date they were collected in sri lanka timezone', async () => { + set('2024-01-05T10:00:00Z'); // 5:30 PM in SL time + const result = await pointsService.calculatePoints( + author_user_id, + 123456789000, + [ + { timestamp: new Date('2024-01-04T23:00:00Z').getTime() }, // 4:30 AM in SL time + ] as CreateWeatherDatumDto[], + session, + ); + + expect(result).toBe( + PointsConfigs.POINTS_PER_HOUR + PointsConfigs.POINTS_PER_DAY, + ); + reset(); + }); + + it('should not add bonus points if the user has uploaded data on a different date than they were collected in sri lanka timezone', async () => { + set('2024-01-05T10:00:00Z'); // 5:30 PM in SL time + const result = await pointsService.calculatePoints( + author_user_id, + 123456789000, + [ + { timestamp: new Date('2024-01-05T23:00:00Z').getTime() }, // next day 4:30 AM in SL time + ] as CreateWeatherDatumDto[], + session, + ); + + expect(result).toBe(PointsConfigs.POINTS_PER_HOUR); + reset(); + }); }); }); diff --git a/src/modules/points/points.service.ts b/src/modules/points/points.service.ts index 852e289..a7778f6 100644 --- a/src/modules/points/points.service.ts +++ b/src/modules/points/points.service.ts @@ -21,6 +21,8 @@ import { } from './entities/point-tracker.entity'; import { RedeemPointsInputDto } from './dto/redeem-points.dto'; import { RedeemPointsResponseDto } from './dto/redeem-points-response.dto'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const moment = require('moment'); @Injectable() /** @@ -376,12 +378,21 @@ export class PointsService { if (isNewDay) { // Check if the datapoint is uploaded within same day. // Check if server date. - const serverDate = new Date(); - serverDate.setUTCHours(0, 0, 0, 0); - const serverDateISO = serverDate.toISOString(); - - if (dateISO === serverDateISO) { + const datumDateStr = moment(weatherDatum.timestamp) + .utc() + .utcOffset(330) + .toDate() + .toDateString(); // +05:30 timezone + const serverDateStr = moment() + .utc() + .utcOffset(330) + .toDate() + .toDateString(); + console.debug('check to add bonus points. datum timestamp =', datumDateStr, 'server time =', serverDateStr); + + if (datumDateStr === serverDateStr) { points += PointsConfigs.POINTS_PER_DAY; + console.debug('bonus points added'); } } } From a142c5a27ea4c71d8cff98a071b15d70df0200d2 Mon Sep 17 00:00:00 2001 From: Lihini Senanayake Date: Wed, 10 Jan 2024 12:35:14 +0530 Subject: [PATCH 5/5] fix: null pointer error in /weather-stations/latest --- src/modules/weather-data/weather-data.service.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/modules/weather-data/weather-data.service.ts b/src/modules/weather-data/weather-data.service.ts index a5ac634..2bd2e59 100644 --- a/src/modules/weather-data/weather-data.service.ts +++ b/src/modules/weather-data/weather-data.service.ts @@ -168,10 +168,10 @@ export class WeatherDataService { transformWeatherDatum(datum) { return { _id: datum._id, - author_user_id: datum.metadata.author_user_id, - sensor_id: datum.metadata.sensor_id, - weather_station_id: datum.metadata.weather_station_id, - coordinates: datum.metadata.coordinates, + author_user_id: datum.metadata?.author_user_id, + sensor_id: datum.metadata?.sensor_id, + weather_station_id: datum.metadata?.weather_station_id, + coordinates: datum.metadata?.coordinates, timestamp: datum.timestamp, temperature: datum.temperature, humidity: datum.humidity, @@ -246,10 +246,14 @@ export class WeatherDataService { weatherStationId: string, ): Promise { const datum = (await this.weatherDatumModel - .findOne({ weather_station_id: weatherStationId }) + .findOne({ "metadata.weather_station_id": weatherStationId }) .sort({ timestamp: -1 }) .exec()) as WeatherDatum; + if (!datum) { + return null; + } + return this.transformWeatherDatum(datum); }