Skip to content

Commit

Permalink
Add next draw date feature to game model
Browse files Browse the repository at this point in the history
  • Loading branch information
denizyesilirmak committed Aug 5, 2023
1 parent 6ea4592 commit 134253c
Show file tree
Hide file tree
Showing 13 changed files with 222 additions and 23 deletions.
24 changes: 22 additions & 2 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@ var utils_1 = require("./src/utils");
var express_rate_limit_1 = require("express-rate-limit");
var scheduler_1 = require("./src/scheduler");
var rate_limit_1 = require("./src/config/rate-limit");
/**
* @description Environment variables
* NODE_ENV: development | production
* this logs whether the app is running in development or production mode
*/
(0, utils_1.log)('NODE_ENV', process.env.NODE_ENV, 'green');
//connect to database
/**
* @description Start the database connection
*/
(0, database_1.default)();
var app = (0, express_1.default)();
exports.app = app;
Expand All @@ -32,12 +39,25 @@ app.use(vadidation_1.registerEmailValidation);
app.use(vadidation_1.registerEmailOtpValidation);
app.use(vadidation_1.loginEmailValidation);
app.use(auth_1.authorizationMiddleware);
//routes
/**
* @description Routes
* @memberof App
* This is where we define our routes
*/
routes_1.routes.initRoutes();
//draw scheduler
scheduler_1.drawScheduler.start();
//static files
app.use('/images', express_1.default.static("".concat(__dirname, "/src/static/images")));
/**
* @description Start the server
* @memberof App
* if the app is running in production mode, we need to use https
* otherwise, we can use http
* @see https://nodejs.org/api/https.html
* load the ssl certificates and create a https server instance
* ssl certificates are stored in shared docker volume
*/
if (process.env.NODE_ENV === 'production') {
var privateKey = fs_1.default.readFileSync('/root/securiry/ssl/privkey.pem', 'utf8');
var certificate = fs_1.default.readFileSync('/root/securiry/ssl/cert.pem', 'utf8');
Expand Down
38 changes: 38 additions & 0 deletions dist/src/helpers/email.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ var mail_composer_1 = __importDefault(require("nodemailer/lib/mail-composer"));
var random_1 = require("./random");
var otp_model_1 = __importDefault(require("../models/otp/otp.model"));
var utils_1 = require("../utils");
/**
* @description Gmail tokens
* @memberof EmailHelper
* this object contains gmail tokens
* these tokens are used to create gmail service
* @see https://developers.google.com/gmail/api/quickstart/nodejs
* token stored in .env file
*/
var tokens = {
access_token: process.env.GMAIL_ACCESS_TOKEN,
refresh_token: process.env.GMAIL_REFRESH_TOKEN,
Expand All @@ -58,13 +66,28 @@ var getGmailService = function () {
var gmail = googleapis_1.google.gmail({ version: 'v1', auth: oAuth2Client });
return gmail;
};
/**
* @description Encode message to base64
* @param {Buffer} message
* @memberof EmailHelper
* @returns string
* this function is used to encode message to base64 and replace some characters
*/
var encodeMessage = function (message) {
return Buffer.from(message)
.toString('base64')
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');
};
/**
* @description Create mail
* this function is used to create mail with nodemailer and mailcomposer
* mail options are passed as parameter
* when mail is created, it is encoded to base64 and returned
* @param options
* @returns
*/
var createMail = function (options) { return __awaiter(void 0, void 0, void 0, function () {
var mailComposer, message;
return __generator(this, function (_a) {
Expand All @@ -78,6 +101,21 @@ var createMail = function (options) { return __awaiter(void 0, void 0, void 0, f
}
});
}); };
/**
* @description Send otp email
* @param {string} email
* @param {string} name
* @param {string} lastName
* @param {string} type
* @memberof EmailHelper
* this function is used to send otp email to user
* it takes email, name, lastName and type as parameter
* type can be 'register' or 'login' and it is used to determine email subject
* when email is sent, it is saved to database with otp code and email identifier
* email identifier is used to delete email from gmail if user deletes otp email
* @returns {Promise<{id: string, otpResult: any}>}
* todo: this function should be refactored. it is too long and complex now
*/
var sendOtpEmail = function (email, name, lastName, type) { return __awaiter(void 0, void 0, void 0, function () {
var otp, options, gmail, rawMessage, _a, _b, id, otpResult, options, gmail, rawMessage, _c, _d, id, otpResult;
return __generator(this, function (_e) {
Expand Down
1 change: 0 additions & 1 deletion dist/src/middlewares/loger.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ exports.loger = void 0;
var log_model_1 = __importDefault(require("../models/log/log.model"));
var utils_1 = require("../utils");
var telegram_1 = __importDefault(require("../services/telegram"));
telegram_1.default.startService();
var loger = function (req, res, next) {
(0, utils_1.log)('REQUEST', "".concat(req.method, " ").concat(req.protocol, "://").concat(req.get('host')).concat(req.originalUrl, " ").concat(req.ip, " ").concat(req.get('user-agent')), 'green');
log_model_1.default.create({
Expand Down
24 changes: 22 additions & 2 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,16 @@ import { rateLimit } from 'express-rate-limit';
import { drawScheduler } from './src/scheduler';
import { rateLimitConfig } from './src/config/rate-limit';

/**
* @description Environment variables
* NODE_ENV: development | production
* this logs whether the app is running in development or production mode
*/
log('NODE_ENV', process.env.NODE_ENV, 'green');

//connect to database
/**
* @description Start the database connection
*/
connectDB();

const app = express();
Expand All @@ -39,7 +46,11 @@ app.use(registerEmailOtpValidation);
app.use(loginEmailValidation);
app.use(authorizationMiddleware);

//routes
/**
* @description Routes
* @memberof App
* This is where we define our routes
*/
routes.initRoutes();

//draw scheduler
Expand All @@ -48,6 +59,15 @@ drawScheduler.start();
//static files
app.use('/images', express.static(`${__dirname}/src/static/images`));

/**
* @description Start the server
* @memberof App
* if the app is running in production mode, we need to use https
* otherwise, we can use http
* @see https://nodejs.org/api/https.html
* load the ssl certificates and create a https server instance
* ssl certificates are stored in shared docker volume
*/
if (process.env.NODE_ENV === 'production') {
const privateKey = fs.readFileSync('/root/securiry/ssl/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/root/securiry/ssl/cert.pem', 'utf8');
Expand Down
38 changes: 38 additions & 0 deletions src/helpers/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,14 @@ import { generateActivationCode } from './random';
import otpModel from '../models/otp/otp.model';
import { log } from '../utils';

/**
* @description Gmail tokens
* @memberof EmailHelper
* this object contains gmail tokens
* these tokens are used to create gmail service
* @see https://developers.google.com/gmail/api/quickstart/nodejs
* token stored in .env file
*/
const tokens = {
access_token: process.env.GMAIL_ACCESS_TOKEN,
refresh_token: process.env.GMAIL_REFRESH_TOKEN,
Expand All @@ -26,6 +34,13 @@ const getGmailService = () => {
return gmail;
};

/**
* @description Encode message to base64
* @param {Buffer} message
* @memberof EmailHelper
* @returns string
* this function is used to encode message to base64 and replace some characters
*/
const encodeMessage = (message: Buffer) => {
return Buffer.from(message)
.toString('base64')
Expand All @@ -34,12 +49,35 @@ const encodeMessage = (message: Buffer) => {
.replace(/=+$/, '');
};

/**
* @description Create mail
* this function is used to create mail with nodemailer and mailcomposer
* mail options are passed as parameter
* when mail is created, it is encoded to base64 and returned
* @param options
* @returns
*/
const createMail = async (options: Mail.Options) => {
const mailComposer = new MailComposer(options);
const message = await mailComposer.compile().build();
return encodeMessage(message);
};

/**
* @description Send otp email
* @param {string} email
* @param {string} name
* @param {string} lastName
* @param {string} type
* @memberof EmailHelper
* this function is used to send otp email to user
* it takes email, name, lastName and type as parameter
* type can be 'register' or 'login' and it is used to determine email subject
* when email is sent, it is saved to database with otp code and email identifier
* email identifier is used to delete email from gmail if user deletes otp email
* @returns {Promise<{id: string, otpResult: any}>}
* todo: this function should be refactored. it is too long and complex now
*/
const sendOtpEmail = async (
email: string,
name: string,
Expand Down
2 changes: 0 additions & 2 deletions src/middlewares/loger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import logModel from '../models/log/log.model';
import { log } from '../utils';
import TelegramService from '../services/telegram';

TelegramService.startService();

const loger = (req: Request, res: Response, next: NextFunction) => {
log(
'REQUEST',
Expand Down
6 changes: 6 additions & 0 deletions src/models/game/game.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ const GameSchema = new Schema({
required: false,
default: 'lottery',
},
nextDrawDate: {
type: Date,
required: false,
default: Date.now,
},
});

export interface IGameSchema {
Expand All @@ -95,6 +100,7 @@ export interface IGameSchema {
cronExpressionDescription: string;
gameCode: string;
gameType: string;
nextDrawDate: Date;
_id: Types.ObjectId;
}

Expand Down
37 changes: 29 additions & 8 deletions src/routes/admin/admin.route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ import logModel from '../../models/log/log.model';

const router = Router();

/*
* @description Get all users
* @route GET /api/admin/users
* @access Private
* @memberof AdminRouter
*/
router.get('/users', async (req: Request, res: Response) => {
const users = await userModel.find().sort({ createdAt: -1 }).exec();

Expand All @@ -14,16 +20,31 @@ router.get('/users', async (req: Request, res: Response) => {
});
});

/*
* @description Get all logs
* @route GET /api/admin/logs
* @access Private
* @memberof AdminRouter
* @param {number} pageIndex
* @returns {Promise<void>}
* @memberof AdminRouter
* @returns void
*/
router.get('/logs/:pageIndex', async (req: Request, res: Response) => {
const pageIndex = parseInt(req.params.pageIndex);
const logs = await logModel.find().sort({ createdAt: -1 }).skip(pageIndex * 10).limit(10).exec();
const pageIndex = parseInt(req.params.pageIndex);
const logs = await logModel
.find()
.sort({ createdAt: -1 })
.skip(pageIndex * 10)
.limit(10)
.exec();

res.status(200).json({
success: true,
count: logs.length,
page: pageIndex,
logs: logs,
});
res.status(200).json({
success: true,
count: logs.length,
page: pageIndex,
logs: logs,
});
});

export { router as adminRouter };
5 changes: 5 additions & 0 deletions src/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import { generalRouter } from './general/general.route';
import { profileRouter } from './profile/profile.route';
import { sslRouter } from './ssl/ssl.route';

/**
* @description Routes class
* @class Routes
* All routes are initialized here
*/
class Routes {
initRoutes() {
app.use(`/api/${process.env.API_VERSION}/`, generalRouter);
Expand Down
31 changes: 31 additions & 0 deletions src/scheduler/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,19 @@ import { log, randomNumberGenerator } from '../utils';
import gameModel, { IGameSchema } from '../models/game/game.model';
import drawModel from '../models/draw/draw.model';
import telegramServiceInstance from '../services/telegram';
import cronParser from 'cron-parser';
import { Timezone } from 'node-schedule';

class DrawScheduler {
private schedule!: typeof Schedule;
private jobs!: Job[];

/**
* @description Start automatic draw scheduler
* Get all games from database and create a job for each game with cron expression
* @returns void
* @memberof DrawScheduler
*/
start() {
log('SCHEDULER', 'Automatic draw scheduler started', 'orange');

Expand All @@ -20,9 +28,32 @@ class DrawScheduler {
});
}

/**
* @description draw for given game
* it will be called by scheduler when cron job is triggered
* this function will generate random numbers and save them to database
* set next draw date for given game for next cron job
* @param {IGameSchema} game
* @memberof DrawScheduler
* @returns void
*/

private draw(game: IGameSchema) {
log('SCHEDULER', `Draw for ${game.name} game will be held`, 'orange');
telegramServiceInstance.sendMessage(`Draw for ${game.name}`);

//get next draw date
const nextDrawDate = cronParser
.parseExpression(game.cronExpression, {
tz: 'Europe/Istanbul',
})
.next();

//update next draw date
gameModel.findByIdAndUpdate(game._id, {
nextDrawDate: nextDrawDate.toDate(),
});

const draw = new drawModel({
game: game._id,
numbers: randomNumberGenerator(
Expand Down
Loading

0 comments on commit 134253c

Please sign in to comment.