From ec5489990712a92ed032a75c4d05c0bcceff9d0c Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sat, 6 Jan 2024 19:51:13 +0530 Subject: [PATCH 1/9] fix: server date for weather datapoint upload same day --- src/modules/points/points.service.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/modules/points/points.service.ts b/src/modules/points/points.service.ts index 75803e8..093b190 100644 --- a/src/modules/points/points.service.ts +++ b/src/modules/points/points.service.ts @@ -371,7 +371,15 @@ export class PointsService { localPointTrackers.set(dateISO, processedHours); if (isNewDay) { - points += PointsConfigs.POINTS_PER_DAY; + // 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) { + points += PointsConfigs.POINTS_PER_DAY; + } } } } From e1f53679254ff2f90887421d9730a98abf6c447c Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sat, 6 Jan 2024 20:01:21 +0530 Subject: [PATCH 2/9] chore: added tvoc --- src/modules/weather-data/entities/weather-datum.entity.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/weather-data/entities/weather-datum.entity.ts b/src/modules/weather-data/entities/weather-datum.entity.ts index 22442a0..5f5ac1f 100644 --- a/src/modules/weather-data/entities/weather-datum.entity.ts +++ b/src/modules/weather-data/entities/weather-datum.entity.ts @@ -55,6 +55,9 @@ export class WeatherDatum { @Prop() percentage_light_intensity: number; + + @Prop() + tvoc: number; } export type WeatherDatumDocument = WeatherDatum & Document; From fecfa6b709e9be8151f81322eef58b6faeba92d4 Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sat, 6 Jan 2024 20:17:32 +0530 Subject: [PATCH 3/9] chore --- src/modules/weather-data/weather-data.service.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/modules/weather-data/weather-data.service.ts b/src/modules/weather-data/weather-data.service.ts index 73f9322..b310588 100644 --- a/src/modules/weather-data/weather-data.service.ts +++ b/src/modules/weather-data/weather-data.service.ts @@ -80,11 +80,17 @@ export class WeatherDataService { .exec(); // Remove the existing weather data from the data to be inserted. + // Also check timestamp of weather datapoint + const currentUtcTimestamp = new Date().getTime(); // Get current UTC timestamp + data = data.filter((datum) => { const datumDate = new Date(datum.timestamp); // Convert timestamp to Date object - return !existingWeatherData.some( - (existingDatum) => - existingDatum.timestamp.getTime() === datumDate.getTime(), + return ( + datumDate.getTime() <= currentUtcTimestamp && // Check if the timestamp is not in the future + !existingWeatherData.some( + (existingDatum) => + existingDatum.timestamp.getTime() === datumDate.getTime(), + ) ); }); From 89de8c8775320c4ae06e4ed31ff166f523d17e1f Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sat, 6 Jan 2024 20:18:37 +0530 Subject: [PATCH 4/9] chore --- src/modules/weather-data/weather-data.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/weather-data/weather-data.service.ts b/src/modules/weather-data/weather-data.service.ts index b310588..b145d34 100644 --- a/src/modules/weather-data/weather-data.service.ts +++ b/src/modules/weather-data/weather-data.service.ts @@ -86,7 +86,7 @@ export class WeatherDataService { data = data.filter((datum) => { const datumDate = new Date(datum.timestamp); // Convert timestamp to Date object return ( - datumDate.getTime() <= currentUtcTimestamp && // Check if the timestamp is not in the future + datumDate.getTime() <= currentUtcTimestamp + 86400 && // Check if the timestamp is not in the future !existingWeatherData.some( (existingDatum) => existingDatum.timestamp.getTime() === datumDate.getTime(), From 28e443a0e9950a3d7983433fc9378eaf8d4eaa1a Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sat, 6 Jan 2024 23:54:45 +0530 Subject: [PATCH 5/9] fix: weather data summary click 500 error --- .../weather-stations.controller.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/modules/weather-stations/weather-stations.controller.ts b/src/modules/weather-stations/weather-stations.controller.ts index 4b7b4c3..b32b763 100644 --- a/src/modules/weather-stations/weather-stations.controller.ts +++ b/src/modules/weather-stations/weather-stations.controller.ts @@ -68,18 +68,21 @@ export class WeatherStationsController { ); // Get points of the user of the weather station. - const pointsOfUser = await this.pointsService.findByUserId( - weatherData.author_user_id, - ); + let pointsOfUser = 0; + if (!weatherData) { + return { + weatherData, + pointsOfUser, + }; + } + pointsOfUser = ( + await this.pointsService.findByUserId(weatherData.author_user_id) + ).amount; return { weatherData, pointsOfUser, }; - - // return this.weatherDataService.findLatestByWeatherStationId( - // weatherStationId, - // ); } @Patch(':id') From 6167cf8255f39a812d416269907f72d48c9b3733 Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sun, 7 Jan 2024 01:26:11 +0530 Subject: [PATCH 6/9] fix: get existing trackers --- src/modules/points/points.service.spec.ts | 57 +++++++------------ src/modules/points/points.service.ts | 11 ++-- .../weather-data/weather-data.service.ts | 2 +- 3 files changed, 28 insertions(+), 42 deletions(-) diff --git a/src/modules/points/points.service.spec.ts b/src/modules/points/points.service.spec.ts index cfd56b0..e781dc5 100644 --- a/src/modules/points/points.service.spec.ts +++ b/src/modules/points/points.service.spec.ts @@ -23,10 +23,17 @@ import { PointsController } from './points.controller'; import { PointsService } from './points.service'; import { CreateWeatherDatumDto } from '../weather-data/dto/create-weather-datum.dto'; import { PointsConfigs } from './configs/points.config'; +import { SessionService } from '../users/session/session.service'; +import { AuthService } from '../auth/auth.service'; +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'; describe('PointsService', () => { let pointsService: PointsService; + let mockUserModel = Model; let mockPointTrackerModel = Model; let mockPointTransactionModel = Model; let mockLastProcessedEntryModel = Model; @@ -41,6 +48,7 @@ describe('PointsService', () => { const uri = mongod.getUri(); mockMongoConnection = (await connect(uri)).connection; + mockUserModel = mockMongoConnection.model(User.name, UserSchema); mockPointTrackerModel = mockMongoConnection.model( PointTracker.name, PointTrackerSchema, @@ -63,6 +71,15 @@ describe('PointsService', () => { controllers: [PointsController], providers: [ PointsService, + SessionService, + AuthService, + JwtService, + UsersService, + OAuth2Client, + { + provide: getModelToken(User.name), + useValue: mockUserModel, + }, { provide: getModelToken(PointTracker.name), useValue: mockPointTrackerModel, @@ -137,11 +154,11 @@ describe('PointsService', () => { expect(result).toBe(0); }); - it('should return the correct points for a single future weather data point for a new date', async () => { + it('should return the correct points for a single future weather data point for a today', async () => { const result = await pointsService.calculatePoints( author_user_id, - 123456789, - [{ timestamp: 123456790 }] as CreateWeatherDatumDto[], + 123456789000, + [{ timestamp: new Date().getTime() }] as CreateWeatherDatumDto[], session, ); @@ -149,39 +166,5 @@ describe('PointsService', () => { PointsConfigs.POINTS_PER_HOUR + PointsConfigs.POINTS_PER_DAY, ); }); - - it('should return the correct points for multiple future weather data points for a single new date.', async () => { - const result = await pointsService.calculatePoints( - author_user_id, - 123456789, - [ - { timestamp: 1704523621000 }, - { timestamp: 1704527221000 }, - ] as CreateWeatherDatumDto[], - session, - ); - - expect(result).toBe( - PointsConfigs.POINTS_PER_HOUR * 2 + PointsConfigs.POINTS_PER_DAY, - ); - }); - - it('should return the correct points for multiple future weather data points for a multiple new dates.', async () => { - const result = await pointsService.calculatePoints( - author_user_id, - 123456789, - [ - { timestamp: 1704192176000 }, - { timestamp: 1704192695000 }, - { timestamp: 1704192854000 }, - { timestamp: 1704332150000 }, - ] as CreateWeatherDatumDto[], - session, - ); - - expect(result).toBe( - PointsConfigs.POINTS_PER_HOUR * 2 + PointsConfigs.POINTS_PER_DAY * 2, - ); - }); }); }); diff --git a/src/modules/points/points.service.ts b/src/modules/points/points.service.ts index 093b190..049e36c 100644 --- a/src/modules/points/points.service.ts +++ b/src/modules/points/points.service.ts @@ -131,6 +131,8 @@ export class PointsService { const currentUserPoints = await this.pointModel.findOne({ author_user_id }); const currentPoints = currentUserPoints ? currentUserPoints.amount : 0; + let updatedPoints = currentPoints; + // Check the type of transaction and validate accordingly. if ( transactionType === PointTransactionTypes.REDEEM && @@ -139,7 +141,7 @@ export class PointsService { throw new Error('Not enough points to redeem.'); } else if (transactionType === PointTransactionTypes.DEDUCT) { // For DEDUCT type, adjust the 'reduceBy' value to not go below zero. - reduceBy = currentPoints < Math.abs(reduceBy) ? -currentPoints : reduceBy; + updatedPoints = Math.max(currentPoints - Math.abs(reduceBy), 0); } try { @@ -149,8 +151,8 @@ export class PointsService { author_user_id, }, { - $inc: { - amount: reduceBy, // Increment negative. + $set: { + amount: updatedPoints, }, last_point_calculated_timestamp: Date.now(), }, @@ -339,6 +341,7 @@ export class PointsService { // Get the existing point trackers from DB and populate local cache. const existingTrackers = await this.pointTrackerModel.find( { + author_user_id, date: { $in: uniqueDates }, }, null, @@ -356,7 +359,7 @@ export class PointsService { for (const weatherDatum of newWeatherData) { // Only consider future data. if (weatherDatum.timestamp > lastProcessedTimestamp) { - const date = new Date(weatherDatum.timestamp); + const date = new Date(weatherDatum.timestamp); // UTC received. date.setUTCHours(0, 0, 0, 0); const dateISO = date.toISOString(); const hourOnly = new Date(weatherDatum.timestamp).getUTCHours(); diff --git a/src/modules/weather-data/weather-data.service.ts b/src/modules/weather-data/weather-data.service.ts index b145d34..7b3b0b4 100644 --- a/src/modules/weather-data/weather-data.service.ts +++ b/src/modules/weather-data/weather-data.service.ts @@ -86,7 +86,7 @@ export class WeatherDataService { data = data.filter((datum) => { const datumDate = new Date(datum.timestamp); // Convert timestamp to Date object return ( - datumDate.getTime() <= currentUtcTimestamp + 86400 && // Check if the timestamp is not in the future + datumDate.getTime() <= currentUtcTimestamp + 86400000 && // Check if the timestamp is not in the future !existingWeatherData.some( (existingDatum) => existingDatum.timestamp.getTime() === datumDate.getTime(), From 465136d15f7f3d4c6e6a701306591d0968ffc5e5 Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sun, 7 Jan 2024 01:59:29 +0530 Subject: [PATCH 7/9] chore: env --- .env.local.example | 6 ++++++ .env.sample | 2 -- .gitignore | 1 + 3 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 .env.local.example delete mode 100644 .env.sample diff --git a/.env.local.example b/.env.local.example new file mode 100644 index 0000000..d0b68ac --- /dev/null +++ b/.env.local.example @@ -0,0 +1,6 @@ +# Database +MONGO_URL= + +# Firebase +MOBILE_CLIENT_ID= +JWT_SECRET= \ No newline at end of file diff --git a/.env.sample b/.env.sample deleted file mode 100644 index 8750162..0000000 --- a/.env.sample +++ /dev/null @@ -1,2 +0,0 @@ -# Database -MONGO_URL= diff --git a/.gitignore b/.gitignore index 2123d56..f064600 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ lerna-debug.log* .env .env.dev .env.prod +.env.local From 89c1b7f31a6dee31321abbe9d696109ad50a3f83 Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sun, 7 Jan 2024 09:30:02 +0530 Subject: [PATCH 8/9] fix: pointsOfUser fix. --- .../weather-stations/weather-stations.controller.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/modules/weather-stations/weather-stations.controller.ts b/src/modules/weather-stations/weather-stations.controller.ts index b32b763..cd3b421 100644 --- a/src/modules/weather-stations/weather-stations.controller.ts +++ b/src/modules/weather-stations/weather-stations.controller.ts @@ -68,16 +68,16 @@ export class WeatherStationsController { ); // Get points of the user of the weather station. - let pointsOfUser = 0; + let pointsOfUser = null; if (!weatherData) { return { weatherData, pointsOfUser, }; } - pointsOfUser = ( - await this.pointsService.findByUserId(weatherData.author_user_id) - ).amount; + pointsOfUser = await this.pointsService.findByUserId( + weatherData.author_user_id, + ); return { weatherData, From 12cdff1e463550928f9d43c06ab018e7c3538b10 Mon Sep 17 00:00:00 2001 From: rjsenanayaka Date: Sun, 7 Jan 2024 19:27:28 +0530 Subject: [PATCH 9/9] fix: weatherdata response fix --- src/modules/weather-data/weather-data.service.ts | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/modules/weather-data/weather-data.service.ts b/src/modules/weather-data/weather-data.service.ts index 7b3b0b4..74c94ba 100644 --- a/src/modules/weather-data/weather-data.service.ts +++ b/src/modules/weather-data/weather-data.service.ts @@ -60,6 +60,7 @@ export class WeatherDataService { const session = await this.mongoConnection.startSession(); session.startTransaction(); let insertedData = []; + let existingWeatherData = []; try { // (1) Commit weather data into the database. try { @@ -71,7 +72,7 @@ export class WeatherDataService { // Filter out the weather data that already exists within the database with same timestamps. // This is to prevent duplicate weather data. - const existingWeatherData = await this.weatherDatumModel + existingWeatherData = await this.weatherDatumModel .find({ timestamp: { $in: data.map((datum) => datum.timestamp), @@ -140,7 +141,9 @@ export class WeatherDataService { await session.commitTransaction(); // Return the _id, timestamp, created_at fields. - return insertedData.map((datum) => { + const responseData = [...insertedData, ...existingWeatherData]; + + return responseData.map((datum) => { return { _id: datum._id, timestamp: datum.timestamp,