Skip to content

Commit

Permalink
Merge pull request #17 from gaveshalabs/feat/weatherdata-metadata-ref…
Browse files Browse the repository at this point in the history
…actor

feat/weatherdata metadata refactor
  • Loading branch information
lihini authored Feb 7, 2024
2 parents 499c4dd + c5e2d8b commit 96a6e8c
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 6 deletions.
6 changes: 6 additions & 0 deletions src/modules/points/dto/redeem-my-points.dto.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ApiProperty } from '@nestjs/swagger';

export class RedeemMyPointsInputDto {
@ApiProperty()
readonly num_points: number;
}
4 changes: 4 additions & 0 deletions src/modules/points/entities/point-transaction.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';
import { PointTransactionTypes } from 'src/modules/common/enums/point-transaction-types.enum';
import { v4 as uuidv4 } from 'uuid';
import { PointTransactionMetadataSchema } from '../schemas/point-transaction-metadata.schema';

@Schema({
timestamps: true,
Expand All @@ -19,6 +20,9 @@ export class PointTransaction {

@Prop()
transaction_type: PointTransactionTypes;

@Prop({ type: PointTransactionMetadataSchema })
metadata: PointTransactionMetadataSchema;
}

export type PointTransactionDocument = PointTransaction & Document;
Expand Down
22 changes: 21 additions & 1 deletion src/modules/points/points.controller.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
import { Body, Controller, Get, Post, UseGuards } from '@nestjs/common';
import {
Body,
Controller,
Get,
Post,
UseGuards,
Headers,
} from '@nestjs/common';
import { PointsService } from './points.service';
import { ApiTags } from '@nestjs/swagger';
import { Point } from './entities/point.entity';
import { RedeemPointsInputDto } from './dto/redeem-points.dto';
import { RedeemPointsResponseDto } from './dto/redeem-points-response.dto';
import { ValidateGaveshaClientGuard } from '../common/guards/gavesha-client.guard';
import { ValidateGaveshaUserGuard } from '../common/guards/gavesha-user.guard';
import { RedeemMyPointsInputDto } from './dto/redeem-my-points.dto';

@Controller('points')
@ApiTags('points')
Expand All @@ -25,4 +33,16 @@ export class PointsController {
): Promise<RedeemPointsResponseDto> {
return await this.pointsService.redeemPoints(redeemPointsInputDto);
}

@Post('/my-redeem')
@UseGuards(ValidateGaveshaClientGuard, ValidateGaveshaUserGuard)
async myRedeemPoints(
@Headers('gavesha-user-api-key') gavesha_user_api_key: string,
@Body() redeemMyPointsInputDto: RedeemMyPointsInputDto,
): Promise<RedeemPointsResponseDto> {
return await this.pointsService.myRedeemPoints(
gavesha_user_api_key,
redeemMyPointsInputDto,
);
}
}
4 changes: 2 additions & 2 deletions src/modules/points/points.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ describe('PointsService', () => {
author_user_id,
123456789000,
[
{ timestamp: new Date('2024-01-04T23:00:00Z').getTime() }, // 4:30 AM in SL time
{ timestamp: new Date('2024-01-04T23:00:00Z').getTime() }, // 4:30 AM in SL time
] as CreateWeatherDatumDto[],
session,
);
Expand All @@ -191,7 +191,7 @@ describe('PointsService', () => {
author_user_id,
123456789000,
[
{ timestamp: new Date('2024-01-05T23:00:00Z').getTime() }, // next day 4:30 AM in SL time
{ timestamp: new Date('2024-01-05T23:00:00Z').getTime() }, // next day 4:30 AM in SL time
] as CreateWeatherDatumDto[],
session,
);
Expand Down
56 changes: 55 additions & 1 deletion src/modules/points/points.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import { RedeemPointsResponseDto } from './dto/redeem-points-response.dto';
import { WeatherDataPoint } from '../weather-data/entities/weather-datapoint.entity';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const moment = require('moment');
import { RedeemMyPointsInputDto } from './dto/redeem-my-points.dto';
import { SessionService } from '../users/session/session.service';

@Injectable()
/**
Expand All @@ -36,6 +38,7 @@ export class PointsService {
* @param pointModel The model for Point documents.
* @param weatherDatumModel The model for WeatherDatum documents.
* @param mongoConnection The MongoDB connection.
* @param sessionService - The session service.
*/
constructor(
@InjectModel(PointTracker.name)
Expand All @@ -54,6 +57,8 @@ export class PointsService {
private weatherDatumModel: Model<WeatherDatum>,

@InjectConnection() private readonly mongoConnection: Connection,

private sessionService: SessionService,
) {}

// @Cron('*/10 * * * * *') // Every 5 seconds
Expand Down Expand Up @@ -90,6 +95,7 @@ export class PointsService {
PointTransactionTypes.DEDUCT,
user.author_user_id,
PointsConfigs.POINTS_DAILY_PENALTY,
'reduced points due to daily penalty',
);
});
}
Expand All @@ -104,6 +110,40 @@ export class PointsService {
PointTransactionTypes.REDEEM,
author_user_id,
-1 * num_points,
'reduced points for redeeming by admin',
); // Note the minus 1.

return {
success: true,
message: `Successfully redeemed ${num_points} points.`,
result,
};
} catch (error) {
return {
success: false,
message: error.message,
};
}
}

async myRedeemPoints(
gavesha_user_api_key: string,
redeemMyPointsInputDto: RedeemMyPointsInputDto,
) {
const { num_points } = redeemMyPointsInputDto;

// Decode the author_user_id from gavesha_user_api_key.
const user =
await this.sessionService.validateGaveshaUserApiKey(gavesha_user_api_key);

const author_user_id = user._id;

try {
const result = await this.deductPoints(
PointTransactionTypes.REDEEM,
author_user_id,
-1 * num_points,
`reduced points due to redeeming by user ${author_user_id}`,
); // Note the minus 1.

return {
Expand All @@ -123,6 +163,7 @@ export class PointsService {
transactionType: PointTransactionTypes,
author_user_id: string,
reduceBy: number,
remarks: string,
): Promise<Point> {
const session = await this.mongoConnection.startSession();
session.startTransaction();
Expand All @@ -144,6 +185,8 @@ export class PointsService {
} else if (transactionType === PointTransactionTypes.DEDUCT) {
// For DEDUCT type, adjust the 'reduceBy' value to not go below zero.
updatedPoints = Math.max(currentPoints - Math.abs(reduceBy), 0);
} else if (transactionType === PointTransactionTypes.REDEEM) {
updatedPoints = currentPoints - Math.abs(reduceBy);
}

try {
Expand All @@ -170,6 +213,9 @@ export class PointsService {
author_user_id,
amount: reduceBy, // Negative value.
transaction_type: transactionType,
metadata: {
remarks,
},
});
await newPointTransaction.save({ session });

Expand Down Expand Up @@ -264,6 +310,9 @@ export class PointsService {
author_user_id,
amount: pointsToCommit,
transaction_type: PointTransactionTypes.ADD,
metadata: {
remarks: 'added points for users contribution',
},
});
await newPointTransaction.save({ session });

Expand Down Expand Up @@ -388,7 +437,12 @@ export class PointsService {
.utcOffset(330)
.toDate()
.toDateString();
console.debug('check to add bonus points. datum timestamp =', datumDateStr, 'server time =', serverDateStr);
console.debug(
'check to add bonus points. datum timestamp =',
datumDateStr,
'server time =',
serverDateStr,
);

if (datumDateStr === serverDateStr) {
points += PointsConfigs.POINTS_PER_DAY;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export class PointTransactionMetadataSchema {
remarks: string;
}
4 changes: 2 additions & 2 deletions src/modules/users/session/session.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class SessionService {
try {
result = await this.jwtService.verifyAsync(key);
} catch (e) {
throw new HttpException('API Key validation failed', 401);
throw new HttpException('API Key validation failed, err 1001', 401);
}

// Get the user from the database based on the email from the JWT.
Expand All @@ -40,7 +40,7 @@ export class SessionService {

// If the key is not the same as the one in the database,
if (user.gavesha_user_api_key !== key) {
throw new HttpException('API Key validation failed', 401);
throw new HttpException('API Key validation failed, err 1002', 401);
}

return user;
Expand Down

0 comments on commit 96a6e8c

Please sign in to comment.