Skip to content
This repository was archived by the owner on Sep 30, 2022. It is now read-only.

Commit

Permalink
feat: Extreme hacky way of adding another command for past questions
Browse files Browse the repository at this point in the history
Come back to this later and make it make sense
  • Loading branch information
CHR-onicles committed Sep 5, 2022
1 parent cd0044e commit 002f167
Show file tree
Hide file tree
Showing 6 changed files with 346 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -134,3 +134,4 @@ logs*.*
course_resources/
RemoteAuth.zip
dist/
past_questions/
230 changes: 230 additions & 0 deletions src/commands/academic/pasco.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
import { IArgs, IClient } from "../../types";
import { List, Message } from "whatsapp-web.js";
import { getMutedStatus } from "../../models/misc";
import {
PAST_QUESTIONS_REPLIES,
WAIT_REPLIES,
REACT_EMOJIS,
} from "../../utils/data";
import {
currentEnv,
pickRandomReply,
currentPrefix,
sendPastQuestions,
} from "../../utils/helpers";

// Past Questions are referred to as "pasco"

const execute = async (client: IClient, msg: Message, args: IArgs) => {
if ((await getMutedStatus()) === true) return;

const { isListResponse, lastPrefixUsed } = args;
// if (currentEnv === 'production') {
const contact = await msg.getContact();
const curChat = await msg.getChat();
const chatFromContact = await contact.getChat();

if (curChat.isGroup) await msg.react(pickRandomReply(REACT_EMOJIS));

const list = new List(
"\nThis is a list of courses with available past questions",
"See courses",
[
{
title: "",
rows: [
// {
// id:
// lastPrefixUsed === process.env.DEV_PREFIX
// ? "pasco-416_dev"
// : "pasco-416_prod",
// title: "System Programming",
// description: "CSCD 416",
// },
// {
// id:
// lastPrefixUsed === process.env.DEV_PREFIX
// ? "pasco-418_dev"
// : "pasco-418_prod",
// title: "Computer Systems Security",
// description: "CSCD 418",
// },
{
id:
lastPrefixUsed === process.env.DEV_PREFIX
? "pasco-422_dev"
: "pasco-422_prod",
title: "Human Computer Interaction",
description: "CSCD 422",
},
// {
// id:
// lastPrefixUsed === process.env.DEV_PREFIX
// ? "pasco-424_dev"
// : "pasco-424_prod",
// title: "Management Principles",
// description: "CSCD 424",
// },
// {
// id:
// lastPrefixUsed === process.env.DEV_PREFIX
// ? "pasco-400_dev"
// : "pasco-400_prod",
// title: "Project",
// description: "CSCD 400",
// },
// { id: lastPrefixUsed === process.env.DEV_PREFIX ? 'pasco-426_dev' : 'pasco-426_prod', title: 'Multimedia Applications', description: 'CSCD 426' },
// {
// id:
// lastPrefixUsed === process.env.DEV_PREFIX
// ? "pasco-428_dev"
// : "pasco-428_prod",
// title: "Expert Systems",
// description: "CSCD 428",
// },
// { id: lastPrefixUsed === process.env.DEV_PREFIX ? 'pasco-432_dev' : 'pasco-432_prod', title: 'Concurrent & Distributed Systems', description: 'CSCD 432' },
// { id: lastPrefixUsed === process.env.DEV_PREFIX ? 'pasco-434_dev' : 'pasco-434_prod', title: 'Mobile Computing', description: 'CSCD 434' },
],
},
],
pickRandomReply(PAST_QUESTIONS_REPLIES),
"Powered by Ethereal bot"
);

!isListResponse && (await chatFromContact.sendMessage(list));
// } else {
// await msg.reply("The bot is currently hosted locally, so this operation cannot be performed.\n\nThe Grandmaster's data is at stake🐦")
// }

if (isListResponse) {
if (msg.selectedRowId) {
const selectedRowId = msg.selectedRowId.split("-")[1];

console.log(`[SLIDES CMD] Slides from ${currentEnv} env`);

switch (selectedRowId) {
case "416_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES)); // have to repeat this to avoid it leaking when bot environments are running simultaneously
sendPastQuestions(msg, "CSCD 416");
break;

case "416_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 416");
break;

case "418_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 418");
break;

case "418_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 418");
break;

case "422_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 422");
break;

case "422_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 422");
break;

case "424_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 424");
break;

case "424_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 424");
break;

case "400_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 400");
break;

case "400_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 400");
break;

case "426_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 426");
break;

case "426_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 426");
break;

case "428_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 428");
break;

case "428_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 428");
break;

case "432_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 432");
break;

case "432_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 432");
break;

case "434_dev":
if (currentEnv !== "development") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 434");
break;

case "434_prod":
if (currentEnv !== "production") break;
await msg.reply(pickRandomReply(WAIT_REPLIES));
sendPastQuestions(msg, "CSCD 434");
break;

default:
break;
}
}

args.isListResponse = false;
}
};

module.exports = {
name: "pasco",
description: "Get course materials for all courses 📚",
alias: ["pascos", "pq"],
category: "everyone", // admin | everyone
help: `To use this command, type:\n*${currentPrefix}pasco*, then choose a course from the list provided`,
execute,
};
4 changes: 4 additions & 0 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,10 @@ if (process.env.MONGO_URL) {
client.commands &&
client.commands.get("slides")?.execute(client, msg, args);
break;
case "pasco":
client.commands &&
client.commands.get("pasco")?.execute(client, msg, args);
break;
case "class":
client.commands &&
client.commands.get("class")?.execute(client, msg, args);
Expand Down
59 changes: 59 additions & 0 deletions src/models/pastQuestions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// --------------------------------------------------
// pastQuestions.ts contains the schema for course past questions
// --------------------------------------------------

const { Schema, model } = require('mongoose');
const fs = require('fs');


/**
* Schema for course past questions
*/
const PastQuestionsSchema = new Schema({
title: String,
courseCode: String,
binData: String, // when Buffer is used, puppeteer complains that it's not properly encoded
});

const prodModelName = "pq-files";
const PastQuestionsModel = model(prodModelName, PastQuestionsSchema);
//todo: Since we can't push `past_questions`, we should only allow uploading courses to development collection

/**
* Helper function to encode the local courses materials and save them on the cloud database.
* @async
*/
const initCollection = async () => {
const count = await PastQuestionsModel.countDocuments({});
console.log('[PAST_QUESTIONS MODEL] Doc count:', count);
if (!count) {
const dir = './past_questions';
for (const folder of fs.readdirSync(dir)) {
console.log('[PAST_QUESTIONS MODEL]', folder)
const courseCode = folder.split('-')[0].trim();
for (const file of fs.readdirSync(dir + '/' + folder)) {
const binData = fs.readFileSync(dir + '/' + folder + '/' + file, { encoding: 'base64' });
const doc = new PastQuestionsModel({ title: file, courseCode, binData });
try {
await doc.save();
} catch (err) {
console.error('[PAST_QUESTIONS MODEL ERROR]', err);
}
}
}
console.log("[PAST_QUESTIONS MODEL] Done encoding all past questions!");
} else console.log('[PAST_QUESTIONS MODEL]', prodModelName + " collection is not empty");
}
initCollection();


/**
* Gets specific past questions from the database.
* @param {string} courseCode String representing the course code for a specific course
* @returns
*/
export const getPastQuestions = async (courseCode: string) => {
const res = await PastQuestionsModel.find({ courseCode });
// console.log('[PAST_QUESTIONS MODEL]', res);
return res;
}
13 changes: 13 additions & 0 deletions src/utils/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,19 @@ export const COURSE_MATERIALS_REPLIES = [
"Your wish is my command 🐦",
];

/**
* Array containing replies to `!slides` command.
*/
export const PAST_QUESTIONS_REPLIES = [
"Need some past questions?",
"Oh you need pasco? 🐦",
"Need any past questions?",
"What past questions can I help you with?",
"Looking for pasco?",
"Your search for pasco ends here 🐦",
"Your wish is my command 🐦",
];

/**
* Map containing some extra info about the bot/random messages to be sent to users
* based on weighted chances.
Expand Down
39 changes: 39 additions & 0 deletions src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { MIME_TYPES, ALL_CLASSES } from "./data";
import { getResource } from "../models/resources";
import { IClient, ICourse } from "../types";
import { TCommands } from "../types";
import { getPastQuestions } from "../models/pastQuestions";

// GLOBAL VARIABLES ----------------------------------
/**
Expand Down Expand Up @@ -647,6 +648,43 @@ const sendSlides = async (msg: Message, courseCode: string) => {
}
};

/**
* Helper function to retrieve past questions from DB to send to user.
* @param msg Message object from whatsapp.
* @param courseCode String representing course code.
* @async
*/
const sendPastQuestions = async (msg: Message, courseCode: string) => {
let isDone = false;
console.log("[HELPERS - SS] Getting past questions...");
const materials = await getPastQuestions(courseCode);
if (materials.length) console.log(" [HELPERS - SS]Got past questions");
else console.error(" [HELPERS - SS ERROR] No past questions received from DB");
for (const material of materials) {
const curMaterial = material;
const file_extension =
curMaterial.title.split(".")[curMaterial.title.split(".").length - 1]; // always extract the last "." and what comes after
const foundMimeType = MIME_TYPES.find(
(obj) => obj.fileExtension === file_extension
);

if (foundMimeType) {
const { mime_type } = foundMimeType;
const slide = new MessageMedia(
mime_type,
curMaterial.binData,
curMaterial.title
);
await msg.reply(slide);
console.log("[HELPERS - SS] Sent a past question");
if (material === materials[materials.length - 1]) isDone = true;
}
// if (isDone) await msg.reply(`Done 👍🏽 from ${currentEnv}`);
if (isDone) await msg.reply(`Done 👍🏽`);
console.log(" [HELPERS - SS]Done sending past questions");
}
};

/**
* Checks whether a user is a bot admin. User passed can be a whatsapp contact or a whatsapp number as a String.
* @param contact Object that represents a contact on whatsapp.
Expand Down Expand Up @@ -881,4 +919,5 @@ export {
getTimeLeftForSetTimeout,
checkForSpam,
checkForChance,
sendPastQuestions,
};

0 comments on commit 002f167

Please sign in to comment.