From f25dcfa8587e51f3098dd75f095347393a411119 Mon Sep 17 00:00:00 2001 From: Nareshkumar Rao Date: Thu, 5 Aug 2021 19:28:16 +0200 Subject: [PATCH 1/3] implemented promises and removed callbacks --- src/db/models/User.helper.ts | 98 ++++++++++++------------------ src/db/utils.ts | 66 ++++++-------------- src/routes/CodeRoute.ts | 55 ++++++++--------- src/routes/CovidRoute.ts | 45 ++++++++------ src/routes/LoginRoute.ts | 54 ++++++++-------- src/routes/TelegramWebhookRoute.ts | 87 ++++++++++---------------- src/routes/VerifyRoute.ts | 50 +++++++-------- src/telegram.ts | 44 ++++---------- 8 files changed, 205 insertions(+), 294 deletions(-) diff --git a/src/db/models/User.helper.ts b/src/db/models/User.helper.ts index 342522d..6e4625b 100644 --- a/src/db/models/User.helper.ts +++ b/src/db/models/User.helper.ts @@ -1,80 +1,60 @@ import { TelegramID, UserRowID, VerificationString } from "../../types"; import { User, UserInstance } from "./User"; -export function getUserByTelegramID( - telegramID: TelegramID, - callback: (user?: UserInstance, message?: string) => void -): void { - User.findOne({ +export async function getUserByTelegramID( + telegramID: TelegramID +): Promise { + const user = await User.findOne({ where: { telegram: telegramID, }, - }) - .then((result) => { - callback(!!result ? result : undefined); - }) - .catch(() => { - callback(undefined); - }); + }); + return user; } -export function getUserByRowID( - rowID: UserRowID, - callback: (user?: UserInstance, message?: string) => void -): void { - User.findOne({ +export async function getUserByRowID( + rowID: UserRowID +): Promise { + const user = await User.findOne({ where: { id: rowID, }, - }) - .then((result) => { - callback(!!result ? result : undefined); - }) - .catch(() => { - callback(undefined); - }); + }); + return user; } -export function getUserByVerification( - verification: VerificationString, - callback: (user?: UserInstance, message?: string) => void -): void { - User.findOne({ +export async function getUserByVerification( + verification: VerificationString +): Promise { + const user = await User.findOne({ where: { verification: verification, }, - }) - .then((result) => { - callback(!!result ? result : undefined); - }) - .catch(() => { - callback(undefined); - }); + }); + return user; } -export function getUserCovidPositivity(telegramID: TelegramID, callback: (isInfected?: boolean) => void): void { - getUserByTelegramID(telegramID, user => { - if (!!user) { - const infectionDuration = +user.infectionDate - Date.now(); - if (infectionDuration > 60 * 60 * 24 * 14) { - setUserCovidPositivity(telegramID, false, success => { - callback(success ? false : undefined); - }); - } else { - callback(user.isInfected); - } - } else { - callback(); - } - }); +export async function getUserCovidPositivity( + telegramID: TelegramID +): Promise { + const user = await getUserByTelegramID(telegramID); + if (!user) throw new Error("User not found"); + const infectionDuration = +user.infectionDate - Date.now(); + if (infectionDuration > 60 * 60 * 24 * 14) { + await setUserCovidPositivity(telegramID, false); + return false; + } else { + return user.isInfected; + } } -export function setUserCovidPositivity(telegramID: TelegramID, infectionState: boolean, callback: (success: boolean) => void): void { - getUserByTelegramID(telegramID, user => { - if (!!user) { - user.isInfected = infectionState; - user.infectionDate = new Date(); - user.save().then(() => callback(true)).catch(() => callback(false)); - } else { callback(false) } - }); +export async function setUserCovidPositivity( + telegramID: TelegramID, + infectionState: boolean +): Promise { + const user = await getUserByTelegramID(telegramID); + if (!user) throw new Error("User not found"); + user.isInfected = infectionState; + user.infectionDate = new Date(); + if (!(await user.save())) throw new Error("Could not save user state"); } diff --git a/src/db/utils.ts b/src/db/utils.ts index 53f92f0..3379e82 100644 --- a/src/db/utils.ts +++ b/src/db/utils.ts @@ -1,56 +1,30 @@ import { strings_en } from "../strings"; import { sendTelegramMessage } from "../telegram"; -import { TelegramID, UserRowID } from "../types"; +import { TelegramID } from "../types"; import { Contact } from "./models/Contact"; -import { User } from "./models/User"; -import { getUserByRowID, getUserByTelegramID } from "./models/User.helper"; +import { User, UserInstance } from "./models/User"; +import { getUserByTelegramID } from "./models/User.helper"; -export function addContact( +export async function addContact( userATelegram: TelegramID, - userBTelegram: TelegramID, - callback: (success: boolean, message?: string) => void -): void { - getUserByTelegramID(userATelegram, (userA) => { - getUserByTelegramID(userBTelegram, (userB) => { - if (!userA || !userB) { - callback(false, "Could not find user."); - return; - } + userBTelegram: TelegramID +): Promise { + const userA = await getUserByTelegramID(userATelegram); + const userB = await getUserByTelegramID(userBTelegram); - Contact.create({ user: userA.id, with: userB.id }) - .then(() => { - console.log( - `Registering contact between ${userA.id} and ${userB.id}` - ); - sendTelegramMessage(userB.telegram, strings_en.telegram_qr_scanned); - callback(true, "Successfully added contact"); - }) - .catch((e) => { - callback(false, e); - }); - }); - }); + if (!userA || !userB) { + throw new Error("Could not found users"); + } + + await Contact.create({ user: userA.id, with: userB.id }); + await sendTelegramMessage(userB.telegram, strings_en.telegram_qr_scanned); } -export function createUser( - telegram: TelegramID, - callback: (success: boolean, message: string) => void -): void { - User.create({ +export async function createUser( + telegram: TelegramID +): Promise { + const user = await User.create({ telegram: telegram, - }) - .then((user) => { - if (!user) { - callback(false, "Could not create user"); - } else { - callback(true, "Success"); - } - }) - .catch((reason) => { - if (reason.name == "SequelizeUniqueConstraintError") { - callback(false, "User already exists"); - } else { - callback(false, "Unknown error"); - } - }); + }); + return user; } diff --git a/src/routes/CodeRoute.ts b/src/routes/CodeRoute.ts index acbf941..c06babb 100644 --- a/src/routes/CodeRoute.ts +++ b/src/routes/CodeRoute.ts @@ -5,41 +5,37 @@ import { TelegramID, VerificationString } from "../types"; import { User, UserInstance } from "../db/models/User"; import { getUserByTelegramID } from "../db/models/User.helper"; -export function CodeRoute(req: Request, res: Response) { +export async function CodeRoute(req: Request, res: Response) { if (!req.session.userTelegramID) { res.status(401).send("Not logged in"); return; } - createQRCode(req.session.userTelegramID, (err, url) => { - res.status(url ? 200 : 401).send({ error: err, data: url }); - }); + try { + const url = await createQRCode(req.session.userTelegramID); + res.send({ data: url }); + } catch (error) { + res + .status(500) + .send({ error: error instanceof Error ? error.message : "Error" }); + } } -function createQRCode( - telegram: TelegramID, - callback: (errorMessage: string | Error, url?: string) => void -): void { - getUserByTelegramID(telegram, (user) => { - !!user && - refreshVerification(user, (result) => { - const verifyURL = `${ - process.env.WEBSITE_URL - }/#/verify/${encodeURIComponent(result.verification)}`; - QRCode.toDataURL( - verifyURL, - { width: 300, height: 300 } as QRCodeToDataURLOptions, - (error, url) => { - callback(error, url); - } - ); - }); - }); +async function createQRCode(telegram: TelegramID): Promise { + const user = await getUserByTelegramID(telegram); + if (!user) throw new Error("User not found"); + const newVerification = await refreshVerification(user); + const verifyURL = `${process.env.WEBSITE_URL}/#/verify/${encodeURIComponent( + newVerification + )}`; + return await QRCode.toDataURL(verifyURL, { + width: 300, + height: 300, + } as QRCodeToDataURLOptions); } -function refreshVerification( - user: UserInstance, - callback: (success: UserInstance) => void -): void { +async function refreshVerification( + user: UserInstance +): Promise { let newVerification = bcrypt .hashSync(`${new Date().getTime()}-${user.telegram}`, 5) .replace(/[^a-zA-Z0-9]+/g, "") as VerificationString; @@ -48,7 +44,6 @@ function refreshVerification( newVerification.length / 2 ) as VerificationString; user.verification = newVerification; - user.save().then((result) => { - callback(result); - }); + await user.save(); + return newVerification; } diff --git a/src/routes/CovidRoute.ts b/src/routes/CovidRoute.ts index e2470e0..d2c9584 100644 --- a/src/routes/CovidRoute.ts +++ b/src/routes/CovidRoute.ts @@ -1,26 +1,33 @@ import { Request, Response } from "express"; -import { getUserCovidPositivity, setUserCovidPositivity } from "../db/models/User.helper"; +import { + getUserCovidPositivity, + setUserCovidPositivity, +} from "../db/models/User.helper"; interface CovidRouteRequest extends Request { - body:{ - setPositive: boolean; - } + body: { + setPositive: boolean; + }; } -export function CovidRoute(req: CovidRouteRequest, res:Response){ - if(!req.session.userTelegramID){ - res.status(401).send("Not logged in"); - return; - } - - if(req.body.setPositive){ - setUserCovidPositivity(req.session.userTelegramID, true, success=>{ - res.send({covidPositive: true}); - }); - }else{ - getUserCovidPositivity(req.session.userTelegramID, isInfected=>{ - res.send({covidPositive: isInfected}); - }); +export async function CovidRoute(req: CovidRouteRequest, res: Response) { + if (!req.session.userTelegramID) { + res.status(401).send("Not logged in"); + return; + } + try { + if (req.body.setPositive) { + await setUserCovidPositivity(req.session.userTelegramID, true); + res.send({ covidPositive: true }); + } else { + const isInfected = await getUserCovidPositivity( + req.session.userTelegramID + ); + res.send({ covidPositive: isInfected }); } + } catch (error) { + res + .send(500) + .send({ error: error instanceof Error ? error.message : "Error" }); + } } - diff --git a/src/routes/LoginRoute.ts b/src/routes/LoginRoute.ts index 18f64ff..c940910 100644 --- a/src/routes/LoginRoute.ts +++ b/src/routes/LoginRoute.ts @@ -16,40 +16,44 @@ interface LoginRequest extends Request { }; } -export function LoginRoute(req: LoginRequest, res: Response) { +export async function LoginRoute(req: LoginRequest, res: Response) { const telegramResponse = req.body.telegramResponse; - authUser(telegramResponse, (authorized) => { + try { + const authorized = await authUser(telegramResponse); if (authorized) { // User is already logged in if (req.session.userTelegramID == telegramResponse.id) { - res.send({authorized: authorized}); + res.send({ authorized: authorized }); return; } + // User not logged in const verified = req.session.isVerified; const verifiedBy = req.session.verifiedByTelegramID; - req.session.regenerate(() => { + req.session.regenerate(async () => { req.session.userTelegramID = telegramResponse.id; if (verified) { - addContact(telegramResponse.id, verifiedBy, (success) => { - res.send({ - authorized: authorized, - contactSuccess: success, - }); + await addContact(telegramResponse.id, verifiedBy); + res.send({ + authorized: true, + contactSuccess: true, }); } else { - res.send({authorized: authorized}); + res.send({ authorized: authorized }); } }); } else { - res.status(401).send(authorized); + res.status(401).send({ error: "Unauthorized" }); } - }); + } catch (error) { + res + .status(500) + .send({ error: error instanceof Error ? error.message : "Error" }); + } } -function authUser( - telegramResponse: TelegramLoginResponse, - callback: (authorized: boolean, message?: string) => void -): void { +async function authUser( + telegramResponse: TelegramLoginResponse +): Promise { let dataCheckArray = []; for (const [key, value] of Object.entries(telegramResponse)) { @@ -71,17 +75,13 @@ function authUser( const authorized = confirmationHash == telegramResponse.hash; if (!authorized) { - callback(false); - return; + return false; } - getUserByTelegramID(telegramResponse.id, (user) => { - if (!!user) { - callback(true); - } else { - createUser(telegramResponse.id, (success, message) => { - callback(success, message); - }); - } - }); + const user = await getUserByTelegramID(telegramResponse.id); + if (!!user) { + return true; + } else { + return !!(await createUser(telegramResponse.id)); + } } diff --git a/src/routes/TelegramWebhookRoute.ts b/src/routes/TelegramWebhookRoute.ts index 353af6a..3c1c3be 100644 --- a/src/routes/TelegramWebhookRoute.ts +++ b/src/routes/TelegramWebhookRoute.ts @@ -19,13 +19,13 @@ interface TelegramWebhookRequest extends Request { }; } -export function TelegramWebhookRoute( +export async function TelegramWebhookRoute( req: TelegramWebhookRequest, res: Response ) { try { if (req.body.message.connected_website) { - sendTelegramMessage( + await sendTelegramMessage( req.body.message.from.id, "Thanks for using OurSejahtera! Let's stay safer together <3" ); @@ -33,67 +33,46 @@ export function TelegramWebhookRoute( const messageText = req.body.message.text; const telegramID = req.body.message.from.id; if (messageText.toLowerCase() == "/covidpositive") { - userInfected(telegramID, (success) => { - if (success) { - sendTelegramMessage( - telegramID, - strings_en.telegram_inform_positive - ); - informContacts(telegramID); - } else { - sendTelegramMessage(telegramID, "Sorry, something went wrong."); - } - }); + await userInfected(telegramID); + await sendTelegramMessage( + telegramID, + strings_en.telegram_inform_positive + ); + await informContacts(telegramID); } } } catch (e) { - console.log("Could not get Telegram Message"); + console.log( + e instanceof Error ? e.message : "Could not get Telegram Message" + ); } res.send(); } -function informContacts(telegramID: TelegramID) { - getUserByTelegramID(telegramID, (user) => { - if (user) { - Contact.findAll({ - where: { - [Op.or]: [{ user: user.id }, { with: user.id }], - }, - }).then((result) => { - result.forEach((contact) => { - const otherPersonID = - contact.user == user.id ? contact.with : contact.user; - getUserByRowID(otherPersonID, (otherUser) => { - otherUser && - sendTelegramMessage( - otherUser.telegram, - strings_en.telegram_inform_infect - ); - }); - }); - }); - } +async function informContacts(telegramID: TelegramID): Promise { + const user = await getUserByTelegramID(telegramID); + if (!user) throw new Error("User not found"); + const contacts = await Contact.findAll({ + where: { + [Op.or]: [{ user: user.id }, { with: user.id }], + }, }); -} -function userInfected( - telegramID: TelegramID, - callback: (success: boolean) => void -): void { - getUserByTelegramID(telegramID, (user) => { - if (!!user) { - user.isInfected = true; - user - .save() - .then((result) => { - callback(!!result); - }) - .catch(() => { - callback(false); - }); - } else { - callback(false); - } + contacts.forEach(async (contact) => { + const otherPersonID = contact.user == user.id ? contact.with : contact.user; + const otherUser = await getUserByRowID(otherPersonID); + if (!otherUser) throw new Error("Other user does not exist"); + await sendTelegramMessage( + otherUser.telegram, + strings_en.telegram_inform_infect + ); }); } + +async function userInfected(telegramID: TelegramID): Promise { + const user = await getUserByTelegramID(telegramID); + if (!user) throw new Error("User not found"); + user.isInfected = true; + await user.save(); +} diff --git a/src/routes/VerifyRoute.ts b/src/routes/VerifyRoute.ts index 0c05992..0197ab1 100644 --- a/src/routes/VerifyRoute.ts +++ b/src/routes/VerifyRoute.ts @@ -10,35 +10,29 @@ interface VerifyRequest extends Request { }; } -export function VerifyRoute(req: VerifyRequest, res: Response) { - getUserByVerification( - decodeURIComponent(req.body.id) as VerificationString, - (verifiedByUser, message) => { - if (!!verifiedByUser) { - req.session.isVerified = !!verifiedByUser; - req.session.verifiedByTelegramID = verifiedByUser.telegram; - if (req.session.userTelegramID) { - // If Logged In - addContact( - req.session.userTelegramID, - verifiedByUser.telegram, - (success, message) => { - res - .status(success ? 200 : 400) - .send({ success: success, message: message, loggedIn: true }); - } - ); - } else { - // If Not Logged In - res.send({ - success: !!verifiedByUser, - message: message, - loggedIn: false, - }); - } +export async function VerifyRoute(req: VerifyRequest, res: Response) { + const verifiedByUser = await getUserByVerification( + decodeURIComponent(req.body.id) as VerificationString + ); + try{ + if (!!verifiedByUser) { + req.session.isVerified = !!verifiedByUser; + req.session.verifiedByTelegramID = verifiedByUser.telegram; + if (req.session.userTelegramID) { + // If Logged In + await addContact(req.session.userTelegramID, verifiedByUser.telegram); + res.send({ success: true, loggedIn: true }); } else { - res.status(400).send({ success: !!verifiedByUser, message: message }); + // If Not Logged In + res.send({ + success: false, + loggedIn: false, + }); } + } else { + res.status(400).send({ success: false }); } - ); + }catch(e){ + res.status(500).send({error: e instanceof Error ? e.message : "Error"}); + } } diff --git a/src/telegram.ts b/src/telegram.ts index 7d631ab..0c2515e 100644 --- a/src/telegram.ts +++ b/src/telegram.ts @@ -1,42 +1,24 @@ import axios from "axios"; import { TelegramID } from "./types"; -export function setTelegramWebHook( - callback: (success: boolean) => void = () => {} -): void { +export async function setTelegramWebHook(): Promise { const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/setWebhook`; - axios - .post(url, { - url: `${process.env.SERVER_API_URL}/${process.env.TELEGRAM_SECRET}`, - allowed_updates: [], - drop_pending_updates: true, - }) - .then((res) => { - callback(!!res); - }) - .catch((err) => { - callback(!!err); - }); + await axios.post(url, { + url: `${process.env.SERVER_API_URL}/${process.env.TELEGRAM_SECRET}`, + allowed_updates: [], + drop_pending_updates: true, + }); } -export function sendTelegramMessage( +export async function sendTelegramMessage( telegramID: TelegramID, - message: string, - callback: (success: boolean) => void = () => {} -): void { + message: string +): Promise { const url = `https://api.telegram.org/bot${process.env.TELEGRAM_TOKEN}/sendMessage`; - axios - .post(url, { - chat_id: telegramID, - text: message, - }) - .then((res) => { - callback(!!res); - }) - .catch((err) => { - console.error("Problem sending Telegram message."); - callback(!!err); - }); + const response = await axios.post(url, { + chat_id: telegramID, + text: message, + }); } setTelegramWebHook(); From ebf1128930556f7799fd82289291b8868196bb52 Mon Sep 17 00:00:00 2001 From: Nareshkumar Rao Date: Thu, 5 Aug 2021 19:36:55 +0200 Subject: [PATCH 2/3] added error messaging --- src/telegram.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/telegram.ts b/src/telegram.ts index 0c2515e..9cca20a 100644 --- a/src/telegram.ts +++ b/src/telegram.ts @@ -21,4 +21,10 @@ export async function sendTelegramMessage( }); } -setTelegramWebHook(); + +setTelegramWebHook() +.catch(error=>{ + console.error("Error setting Telegram Webhook"); + error instanceof Error && console.error(error.message); +}); + From bc4745d3714642f284d6be957a52f05c4d446082 Mon Sep 17 00:00:00 2001 From: Nareshkumar Rao Date: Thu, 5 Aug 2021 21:44:51 +0200 Subject: [PATCH 3/3] hotfix --- src/db/models/User.helper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/db/models/User.helper.ts b/src/db/models/User.helper.ts index baf7909..7e6bb8c 100644 --- a/src/db/models/User.helper.ts +++ b/src/db/models/User.helper.ts @@ -39,7 +39,7 @@ export async function getUserCovidPositivity( ): Promise { const user = await getUserByTelegramID(telegramID); if (!user) throw new Error("User not found"); - const infectionDuration = Date.now() - +user.infectionDate; + const infectionDuration = new Date().getTime() - user.infectionDate.getTime(); if (infectionDuration > 60 * 60 * 24 * 14 * 1000) { await setUserCovidPositivity(telegramID, false); return false;