Skip to content

Commit

Permalink
Merge pull request #9 from gaveshalabs/rukshanjs/points
Browse files Browse the repository at this point in the history
fix: server date for weather datapoint upload same day
  • Loading branch information
lihini authored Jan 7, 2024
2 parents e43074e + 12cdff1 commit 87e0a5f
Show file tree
Hide file tree
Showing 8 changed files with 68 additions and 54 deletions.
6 changes: 6 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Database
MONGO_URL=

# Firebase
MOBILE_CLIENT_ID=
JWT_SECRET=
2 changes: 0 additions & 2 deletions .env.sample

This file was deleted.

1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ lerna-debug.log*
.env
.env.dev
.env.prod
.env.local
57 changes: 20 additions & 37 deletions src/modules/points/points.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<User>;
let mockPointTrackerModel = Model<PointTracker>;
let mockPointTransactionModel = Model<PointTransaction>;
let mockLastProcessedEntryModel = Model<LastProcessedEntry>;
Expand All @@ -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,
Expand All @@ -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,
Expand Down Expand Up @@ -137,51 +154,17 @@ 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,
);

expect(result).toBe(
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,
);
});
});
});
21 changes: 16 additions & 5 deletions src/modules/points/points.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 &&
Expand All @@ -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 {
Expand All @@ -149,8 +151,8 @@ export class PointsService {
author_user_id,
},
{
$inc: {
amount: reduceBy, // Increment negative.
$set: {
amount: updatedPoints,
},
last_point_calculated_timestamp: Date.now(),
},
Expand Down Expand Up @@ -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,
Expand All @@ -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();
Expand All @@ -371,7 +374,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;
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/modules/weather-data/entities/weather-datum.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ export class WeatherDatum {

@Prop()
percentage_light_intensity: number;

@Prop()
tvoc: number;
}

export type WeatherDatumDocument = WeatherDatum & Document;
Expand Down
19 changes: 14 additions & 5 deletions src/modules/weather-data/weather-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -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),
Expand All @@ -80,11 +81,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 + 86400000 && // Check if the timestamp is not in the future
!existingWeatherData.some(
(existingDatum) =>
existingDatum.timestamp.getTime() === datumDate.getTime(),
)
);
});

Expand Down Expand Up @@ -134,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,
Expand Down
13 changes: 8 additions & 5 deletions src/modules/weather-stations/weather-stations.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,18 +75,21 @@ export class WeatherStationsController {
}

// Get points of the user of the weather station.
const pointsOfUser = await this.pointsService.findByUserId(
let pointsOfUser = null;
if (!weatherData) {
return {
weatherData,
pointsOfUser,
};
}
pointsOfUser = await this.pointsService.findByUserId(
weatherData.author_user_id,
);

return {
weatherData,
pointsOfUser,
};

// return this.weatherDataService.findLatestByWeatherStationId(
// weatherStationId,
// );
}

@Patch(':id')
Expand Down

0 comments on commit 87e0a5f

Please sign in to comment.