Skip to content

Commit

Permalink
9 refactoring (#21)
Browse files Browse the repository at this point in the history
* 9: refactor: commands in /commands

* 9: refactor: services

* 9: refactor: auth service

* 9: refactor: moved order notification into order service

* 9: docs: comments and readme updated
  • Loading branch information
3cki authored Mar 29, 2022
1 parent 84410e6 commit 554b9f7
Show file tree
Hide file tree
Showing 15 changed files with 234 additions and 168 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ You could also create a second bot using the BotFather as a development bot. In
### Remaining environment variables

1. Set `FIRESTORE_USER_COLLECTION` to the name of the collection in Firebase Firestore that will store all user entries. (e.g. `users`). To separate your development database from your production database, you could simply use a different collection name in your local environment variables, such as `dev-users`.
2. Do the same to all other environment variables following this schema: `FIRESTORE_<ENTITY>_COLLECTION`.

---

Expand Down
21 changes: 21 additions & 0 deletions src/commands/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// --- imports
const { Composer } = require("telegraf");
// --- services
const { checkAdmin } = require("../services/auth");
// --- helpers
const handleError = require("../helpers/errors");

const admin = Composer.command("admin", async (ctx) => {
try {
// look up id in admin collection
const admin = await checkAdmin(ctx);
if (!admin) return; // is not admin

// is admin
ctx.telegram.sendMessage(ctx.chat.id, `Du bist ein Admin!`, {});
} catch (err) {
handleError(err, bot, ctx, "admin");
}
});

module.exports = Composer.compose([admin]);
68 changes: 68 additions & 0 deletions src/commands/general.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
// --- imports
const { Composer } = require("telegraf");
// --- services
const { checkAndCreateUser } = require("../services/auth");
const { getMenu, generateMenuString } = require("../services/menus");
// --- helpers
const handleError = require("../helpers/errors");

const start = Composer.command("start", async (ctx) => {
try {
// get user object or create a new one
const user = await checkAndCreateUser(ctx);

// respond with welcome message
ctx.telegram.sendMessage(
ctx.chat.id,
`Yo moin, ${user.first_name}! Willkommen beim Pizza Tuesday Bot!`,
{}
);
} catch (err) {
handleError(err, ctx, "start");
}
});

const hunger = Composer.command("hunger", async (ctx) => {
try {
// get menu from database
const menu = await getMenu();

// no menu is found -> return message that no menu is available
if (!menu)
return ctx.telegram.sendMessage(
ctx.chat.id,
"Aktuell ist noch kein Menü für den nächsten Pizza Tuesday verfügbar. Bestellungen können leider noch nicht aufgegeben werden."
);

// menu is found -> start order wizard
await ctx.scene.enter("ORDER_WIZARD_SCENE_ID", {
options: menu.options,
});
} catch (err) {
handleError(err, ctx, "hunger");
}
});

const menu = Composer.command("menu", async (ctx) => {
try {
// get menu from database
const menu = await getMenu();

// no menu is found -> return message that no menu is available
if (!menu)
return ctx.telegram.sendMessage(
ctx.chat.id,
"Aktuell ist noch kein Menü für den nächsten Pizza Tuesday verfügbar. Auch bestellungen können leider noch nicht aufgegeben werden."
);

// menu is found -> generate menu string and send it to user
const menuString = generateMenuString(menu.options);
ctx.telegram.sendMessage(ctx.chat.id, menuString, {
parse_mode: "MarkdownV2",
});
} catch (err) {
handleError(err, ctx, "menu");
}
});

module.exports = Composer.compose([start, hunger, menu]);
32 changes: 0 additions & 32 deletions src/helpers/check-admin.js

This file was deleted.

14 changes: 10 additions & 4 deletions src/helpers/errors.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
const { adminErrorNotification } = require("./notifications");
// --- services
const { adminErrorNotification } = require("../services/notifications");

const handleError = async (err, bot, ctx, command) => {
const handleError = async (err, ctx, command) => {
// log to console
console.log(err);
bot.telegram.sendMessage(

// inform user
ctx.telegram.sendMessage(
ctx.chat.id,
`Da scheint wohl etwas schiefgelaufen zu sein, der Bot konnte die Anfrage leider nicht verarbeiten. Bitte versuche es später noch einmal.`,
{}
);
await adminErrorNotification(bot, err, command);

// inform admins
await adminErrorNotification(ctx, err, command);
};

module.exports = handleError;
1 change: 1 addition & 0 deletions src/helpers/generate-order-string.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// --- helpers
const { priceFormatter } = require("./price-formatter");

const generateOrderString = (order, options) => {
Expand Down
54 changes: 0 additions & 54 deletions src/helpers/notifications.js

This file was deleted.

69 changes: 6 additions & 63 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,73 +1,16 @@
// --- imports
require("dotenv").config();
const initBot = require("./init-bot");
// --- helpers
const checkAndCreateUser = require("./helpers/check-and-create-user");
const checkAdmin = require("./helpers/check-admin");
const handleError = require("./helpers/errors");
const { getMenu, generateMenuString } = require("./helpers/menus");
// --- initialization
const bot = initBot();

// --- commands
bot.command("start", async (ctx) => {
try {
const user = await checkAndCreateUser(ctx);
bot.telegram.sendMessage(
ctx.chat.id,
`Yo moin, ${user.first_name}! Willkommen beim Pizza Tuesday Bot!`,
{}
);
} catch (err) {
handleError(err, bot, ctx, "start");
}
});

bot.command("hunger", async (ctx) => {
try {
const menu = await getMenu();
if (!menu)
return bot.telegram.sendMessage(
ctx.chat.id,
"Aktuell ist noch kein Menü für den nächsten Pizza Tuesday verfügbar. Bestellungen können leider noch nicht aufgegeben werden."
);

await ctx.scene.enter("ORDER_WIZARD_SCENE_ID", {
bot,
options: menu.options,
});
} catch (err) {
handleError(err, bot, ctx, "hunger");
}
});
const generalCommands = require("./commands/general");
const adminCommands = require("./commands/admin");

bot.command("admin", async (ctx) => {
try {
const admin = await checkAdmin(ctx, bot);
if (!admin) return;

bot.telegram.sendMessage(ctx.chat.id, `Du bist ein Admin!`, {});
} catch (err) {
handleError(err, bot, ctx, "admin");
}
});
// --- initialization
const bot = initBot();

bot.command("menu", async (ctx) => {
try {
const menu = await getMenu();
if (!menu)
return bot.telegram.sendMessage(
ctx.chat.id,
"Aktuell ist noch kein Menü für den nächsten Pizza Tuesday verfügbar. Auch bestellungen können leider noch nicht aufgegeben werden."
);
const menuString = generateMenuString(menu.options);
bot.telegram.sendMessage(ctx.chat.id, menuString, {
parse_mode: "MarkdownV2",
});
} catch (err) {
handleError(err, bot, ctx, "menu");
}
});
// --- commands
bot.use(generalCommands, adminCommands);

// --- processing
bot.launch();
Expand Down
1 change: 1 addition & 0 deletions src/scenes/order-wizard/amount-selection.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// --- helpers
const { generateOrderString } = require("../../helpers/generate-order-string");

const amountSelection = async (ctx) => {
Expand Down
3 changes: 2 additions & 1 deletion src/scenes/order-wizard/menu-display.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// --- services
const { generateMenuString } = require("../../services/menus");
// --- helpers
const { generateOrderString } = require("../../helpers/generate-order-string");
const { generateMenuString } = require("../../helpers/menus");

const menuDisplay = async (ctx) => {
const stringPrefix = "Was darf's denn sein? Wir haben heute:";
Expand Down
11 changes: 3 additions & 8 deletions src/scenes/order-wizard/order-confirmation.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
const { createOrder } = require("../../helpers/orders");
const { adminOrderNotification } = require("../../helpers/notifications");
// --- services
const { createOrder } = require("../../services/orders");

const orderConfirmation = async (ctx) => {
// get input
Expand Down Expand Up @@ -34,12 +34,7 @@ const orderConfirmation = async (ctx) => {
} und nochmal eine, wenn sie fertig ist.`
);

await createOrder(ctx, ctx.session.order);
await adminOrderNotification(
ctx.scene.state.bot,
ctx.session.order,
ctx.scene.state.options
);
await createOrder(ctx, ctx.session.order, ctx.scene.state.options);
return ctx.scene.leave();
};

Expand Down
30 changes: 29 additions & 1 deletion src/helpers/check-and-create-user.js → src/services/auth.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,34 @@
// --- imports
const { getFirestore } = require("firebase-admin/firestore");

const checkAdmin = async (ctx, bot) => {
const db = getFirestore();
const id = ctx.from.id;

// collection and document references
const collection = db.collection(process.env.FIRESTORE_ADMIN_COLLECTION);
const doc = collection.doc(id.toString());

try {
const response = await doc.get(); // try reading from database

// document exists -> return document data
if (response.exists) {
const data = response.data();
return data;
}

ctx.telegram.sendMessage(
ctx.chat.id,
"Dein Account hat nicht die benötigten Privilegien für diese Aktion.",
{}
);
return false;
} catch (err) {
throw err;
}
};

const checkAndCreateUser = async (ctx) => {
const db = getFirestore();
const id = ctx.from.id;
Expand Down Expand Up @@ -28,4 +56,4 @@ const checkAndCreateUser = async (ctx) => {
}
};

module.exports = checkAndCreateUser;
module.exports = { checkAdmin, checkAndCreateUser };
Loading

0 comments on commit 554b9f7

Please sign in to comment.