Skip to content

Commit

Permalink
Merge pull request #11 from stanleyowen/dev
Browse files Browse the repository at this point in the history
v1.2
  • Loading branch information
stanleyowen authored Jun 27, 2022
2 parents c4f2fbf + 9dbb910 commit d884322
Show file tree
Hide file tree
Showing 13 changed files with 585 additions and 393 deletions.
15 changes: 11 additions & 4 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@ const helmet = require("helmet");
const express = require("express");
const rateLimit = require("express-rate-limit");

if (process.env.NODE_ENV !== "production") require("dotenv").config();
if (
process.env.NODE_ENV !== "production" &&
process.env.NODE_ENV !== "staging"
) {
require("dotenv").config();
} else require("./lib/crashReporter");

const app = express();
const PORT = process.env.PORT || 5000;
const limiter = {
statusCode: 429,
code: "Too Many Requests",
statusMessage: "Too Many Requests",
message:
"We're sorry, but you have made too many requests to our servers. Please try again later.",
};
Expand All @@ -24,7 +29,7 @@ app.use(
JSON.stringify(
{
statusCode: 401,
code: "Unauthorized",
statusMessage: "Unauthorized",
message:
"Connnection has been blocked by CORS Policy: The origin header(s) is not equal to the supplied origin.",
},
Expand Down Expand Up @@ -90,7 +95,7 @@ app.use((req, res, next) => {
JSON.stringify(
{
statusCode: 401,
code: "Unauthorized",
statusMessage: "Unauthorized",
message:
"The pages you are trying to access requires authentication. Please try again.",
},
Expand All @@ -104,10 +109,12 @@ const mainRouter = require("./routes/main.route");
const lineRouter = require("./routes/line.route");
const herokuRouter = require("./routes/heroku.route");
const whatsAppRouter = require("./routes/whatsapp.route");
const pipedreamRouter = require("./routes/pipedream.route");
app.use("/", mainRouter);
app.use("/line", lineRouter);
app.use("/whatsapp", whatsAppRouter);
app.use("/heroku", herokuRouter);
app.use("/pipedream", pipedreamRouter);

app.listen(PORT, () => {
console.log(`Server is running on PORT ${PORT}`);
Expand Down
50 changes: 50 additions & 0 deletions lib/crashReporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const axios = require("axios");

// These following functions Catch unexpected errors
// Errors occurred will be made to the webhook endpoint
// Exits the process with the error code

process.on("unhandledRejection", (reason, promise) => {
console.error(reason);
axios
.post(`${process.env.WEBHOOK_URL}/crashReporter`, {
statusCode: 500,
statusMessage: "Internal Server Error",
originalError: {
name: "Error",
message: "Unhandled Rejection",
reason,
promise,
},
})
.then(() => {
console.error("Unhandled rejection data sent. Exiting app...");
process.exit(1);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
});

process.on("uncaughtException", (error) => {
console.error(error);
axios
.post(`${process.env.WEBHOOK_URL}/crashReporter`, {
statusCode: 500,
statusMessage: "Internal Server Error",
originalError: {
name: "Error",
message: "Uncaught Exception",
error,
},
})
.then(() => {
console.warn("Uncaught exception data sent. Exiting app...");
process.exit(1);
})
.catch((err) => {
console.error(err);
process.exit(1);
});
});
23 changes: 23 additions & 0 deletions lib/errorReporter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const axios = require("axios");

function errorReporter(error) {
console.warn(error);

// Only send the error to the webhook on "staging" amd "production" environment
process.env.NODE_ENV === "production" || process.env.NODE_ENV === "staging"
? axios
.post(`${process.env.WEBHOOK_URL}/errorReporter`, {
statusCode: error?.response?.status ?? 500,
statusMessage: error?.response?.statusText ?? "Internal Server Error",
originalError: {
name: error?.response?.data?.name ?? "Error",
message: error?.response?.data?.message ?? "Unknown Error",
error: error?.response?.data?.error ?? error,
},
})
.then(() => console.info("Error data sent"))
.catch((err) => console.error(err))
: null;
}

module.exports = errorReporter;
30 changes: 30 additions & 0 deletions lib/herokuOperation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
const Heroku = require("heroku-client");
const heroku = new Heroku({ token: process.env.HEROKU_API_KEY });
const errorReporter = require("../lib/errorReporter");

// Get the environment variables from Heroku
function getHerokuEnvVars(appName, cb) {
heroku
.get(`/apps/${appName}/config-vars`)
.then((env) => cb({ statusCode: 200, data: env }))
.catch((err) => {
errorReporter(err);
cb({ statusCode: err.statusCode ?? 400, data: err });
});
}

// Update the environment variables on Heroku
// Using the vallue of null to delete variable(s)
function updateHerokuEnvVars(appName, body, cb) {
heroku
.patch(`/apps/${appName}/config-vars`, {
body,
})
.then((env) => cb({ statusCode: 200, data: env }))
.catch((err) => {
errorReporter(err);
cb({ statusCode: err.statusCode ?? 400, data: err });
});
}

module.exports = { getHerokuEnvVars, updateHerokuEnvVars };
112 changes: 112 additions & 0 deletions lib/lineOperation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
const line = require("@line/bot-sdk");
const stickers = require("../lib/sticker.lib.json");
const errorReporter = require("../lib/errorReporter");
const { getHerokuEnvVars, updateHerokuEnvVars } = require("./herokuOperation");

const client = new line.Client({
channelAccessToken: process.env.LINE_CHANNEL_ACCESS_TOKEN,
});

function validateKeywords(category, message) {
// Get category and save the category keywords to key
let key = [];
let isCategory = false;

if (category === "okay")
key = ["ya", "sip", "yup", "ok", "ye", "thx", "thank"];
if (category === "laugh") key = ["wk", "ha", "lol", "yey"];
if (category === "greetings") key = ["hi", "hello", "hey", "hola"];

// Loop each keyword in key and check if the message contains the following keywords
if (message)
key.forEach((keyword) => {
if (message.includes(keyword) && message.indexOf(keyword) <= 1)
// Use OR method to make sure it returns true when the previous state is false
isCategory = isCategory || true;
});

return isCategory ? category : false;
}

function replayMessageReaction(category, body, cb) {
// Get the category and save the stickers length
const stickerIndex = Math.floor(Math.random() * stickers[category].length);

// Send the sticker to the user
client
.replyMessage(body.events[0].replyToken, {
type: "sticker",
packageId: stickers[category][stickerIndex].packageId,
stickerId: stickers[category][stickerIndex].stickerId,
})
.then(() =>
// Return the status code and message after the sticker is sent
cb({
statusCode: 200,
statusMessage: "Ok",
message: "Reply Message sent successfully.",
})
)
.catch((err) => {
// Return errors if something went wrong
errorReporter(err);
cb({
statusCode: 400,
...err,
});
});
}

function validateBotCommands(commandType, token, cb) {
let appEnv = null,
message = null;
let appName =
(process.env.NODE_ENV === "production" ? "bot" : "dev") + "-edelweiss";

// Get the heroku app name based on the NODE_ENV
getHerokuEnvVars(appName, (env) => {
if (env.statusCode === 200) {
if (commandType === "/done") appEnv = "DAILY_1";

// Check whether the message has been replied
// If the message has been replied once, the second reminder will be sent
if (env.data[`${appEnv}_CF_1`] === "true") {
env.data[`${appEnv}_CF_2`] = "true";
message = process.env[`${appEnv}_CF_MESSAGE_2`];
} else {
env.data[`${appEnv}_CF_1`] = "true";
message = process.env[`${appEnv}_CF_MESSAGE_1`];
}

// Update the environment variables on Heroku
updateHerokuEnvVars(appName, env.data, () =>
// Sent confirmation message to the user
client
.replyMessage(token, {
type: "text",
text: message?.replace(/\\n/g, "\n"),
})
.then(() =>
cb({
statusCode: 200,
statusMessage: "Ok",
message: "Reply Message sent successfully.",
})
)
.catch((err) => {
errorReporter(err);
cb({
statusCode: 400,
...err,
});
})
);
} else cb(env);
});
}

module.exports = {
validateKeywords,
replayMessageReaction,
validateBotCommands,
};
Loading

0 comments on commit d884322

Please sign in to comment.