Browse Source

implemented promises and removed callbacks

feature/promiseMigration
Nareshkumar Rao 3 years ago
parent
commit
f25dcfa858
  1. 98
      src/db/models/User.helper.ts
  2. 66
      src/db/utils.ts
  3. 55
      src/routes/CodeRoute.ts
  4. 45
      src/routes/CovidRoute.ts
  5. 54
      src/routes/LoginRoute.ts
  6. 87
      src/routes/TelegramWebhookRoute.ts
  7. 50
      src/routes/VerifyRoute.ts
  8. 44
      src/telegram.ts

98
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<UserInstance | null> {
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<UserInstance | null> {
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<UserInstance | null> {
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<boolean> {
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<void> {
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");
}

66
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<void> {
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<UserInstance | null> {
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;
}

55
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<string> {
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<VerificationString> {
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;
}

45
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" });
}
}

54
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<boolean> {
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));
}
}

87
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<void> {
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<void> {
const user = await getUserByTelegramID(telegramID);
if (!user) throw new Error("User not found");
user.isInfected = true;
await user.save();
}

50
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"});
}
}

44
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<void> {
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<void> {
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();

Loading…
Cancel
Save