Skip to content

Commit c4293a9

Browse files
authored
Merge pull request OSSPhilippines#70 from scinscinscin/v4
Add quiet routes, plain routes, refactor internal code, add more documentation
2 parents efadd84 + eaa6e2e commit c4293a9

19 files changed

+639
-192
lines changed

.editorconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[*]
2+
indent_style = tabs
3+
indent_size = 4

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,4 @@ debug.log
44
.DS_Store
55
.now
66
.env
7+
dist/

now.json

Lines changed: 21 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,23 @@
11
{
2-
"version": 2,
3-
"builds": [{
4-
"src": "app.js",
5-
"use": "@now/node-server"
6-
}],
7-
"routes": [{
8-
"headers": {
9-
"Access-Control-Allow-Origin": "*",
10-
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
11-
"Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Accept"
12-
},
13-
"src": "/.*",
14-
"dest": "/app.js"
15-
}],
16-
"env": {
17-
"VERSION": "1"
18-
}
2+
"version": 2,
3+
"builds": [
4+
{
5+
"src": "src/api.ts",
6+
"use": "@vercel/node"
7+
}
8+
],
9+
"routes": [
10+
{
11+
"headers": {
12+
"Access-Control-Allow-Origin": "*",
13+
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
14+
"Access-Control-Allow-Headers": "X-Requested-With, Content-Type, Accept"
15+
},
16+
"src": "/(.*)",
17+
"dest": "src/api.ts"
18+
}
19+
],
20+
"env": {
21+
"VERSION": "1"
22+
}
1923
}

src/api.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import express from "express";
22
import morgan from "morgan";
33
import { errorHandler } from "./api/errorHandler";
4+
import { plainRouter } from "./api/plainRouter";
45
import { router } from "./api/router";
56
import { userAgentMiddleware } from "./api/userAgent";
67

@@ -11,11 +12,19 @@ const app = express();
1112
app.use(morgan("common"));
1213
app.use(userAgentMiddleware);
1314

14-
app.use("/", router);
15+
/**
16+
* Plain CMD/Basic routes have both quiet and full modes
17+
* Same with regular / routes with ansi color codes
18+
*/
19+
app.use(["/quiet/basic", "/quiet/cmd", "/quiet/plain"], plainRouter);
20+
app.use(["/basic", "/cmd", "/plain"], plainRouter);
21+
22+
app.use(["/quiet", "/"], router);
1523
app.use("/", errorHandler);
1624

25+
// Not found handler
1726
app.use("*", (_req, res) =>
18-
res.send(
27+
res.status(404).send(
1928
`Welcome to COVID-19 Tracker CLI v${version} by Waren Gonzaga with Wareneutron Developers\n
2029
Please visit: https://warengonza.ga/covid19-tracker-cli\n`
2130
)

src/api/errorHandler.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
import { ErrorRequestHandler } from "express";
2-
import { generateColorTable } from "../utils/generateTable";
32

3+
/**
4+
*
5+
* @param error Error object, received from errors thrown in the code
6+
* @param res Response object from Express
7+
*/
48
export const errorHandler: ErrorRequestHandler = (error, _, res, _next) => {
59
const statusCode = res.statusCode === 200 ? 500 : res.statusCode;
610
res.status(statusCode);
7-
res.send(generateColorTable([error.message], "red"));
11+
res.send(error.message + "\n");
812
res.end();
913
};

src/api/handleAsync.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { Request, Response, NextFunction } from "express";
22
type Handler<R> = (req: Request, res: Response, next: NextFunction) => R;
3+
4+
/**
5+
* @example router.use("/path/", handleAsync((req, res, next)=>{res.send("Hello World!")}));
6+
* @param asyncFn An asyncronous function that takes in req, res, and next
7+
* @returns An asyncronous function where errors will be catched and sent to the error handler
8+
*/
39
const handleAsync: (asyncFn: Handler<Promise<void>>) => Handler<void> = (
410
asyncFn
511
) => {

src/api/plainRouter.ts

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { Router } from "express";
2+
import handleAsync from "./handleAsync";
3+
import {
4+
globalInformationPlain,
5+
informationPerCountryPlain,
6+
historyPerCountryPlain,
7+
globalHistoryPlain,
8+
} from "../utils/plainHandlers";
9+
import { isQuiet } from "./router";
10+
11+
/**
12+
* The plainRouter handles all the plain routes such as /basic, /cmd, and /plain
13+
* It also handles the quiet version of these routes
14+
*/
15+
export const plainRouter = Router({ mergeParams: true });
16+
17+
plainRouter.get(
18+
"/history/:mode?",
19+
handleAsync(async (req, res, next) => {
20+
// get mode from params
21+
let mode = req.params.mode as "cases" | "deaths" | "recovered";
22+
23+
//default to cases if mode is undefined
24+
mode = mode === undefined ? "cases" : mode;
25+
26+
// if the mode is not in the api then return to next handler
27+
if (!["cases", "deaths", "recovered"].includes(mode)) return next();
28+
res.send(await globalHistoryPlain(mode, isQuiet(req)));
29+
})
30+
);
31+
32+
plainRouter.get(
33+
"/history/:country/:mode?",
34+
handleAsync(async (req, res, next) => {
35+
const country = req.params.country;
36+
// get mode from params
37+
let mode = req.params.mode as "cases" | "deaths" | "recovered";
38+
39+
//default to cases if mode is undefined
40+
mode = mode === undefined ? "cases" : mode;
41+
42+
// if the mode is not in the api then return to next handler
43+
if (!["cases", "deaths", "recovered"].includes(mode)) return next();
44+
res.send(await historyPerCountryPlain(country, mode, isQuiet(req)));
45+
})
46+
);
47+
48+
plainRouter.get(
49+
"/:country",
50+
handleAsync(async (req, res, _next) => {
51+
const country = req.params.country;
52+
res.send(await informationPerCountryPlain(country, isQuiet(req)));
53+
})
54+
);
55+
56+
plainRouter.get(
57+
"/",
58+
handleAsync(async (req, res, _next) => {
59+
res.send(await globalInformationPlain(isQuiet(req)));
60+
})
61+
);

src/api/router.ts

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Router } from "express";
1+
import { Request, Router } from "express";
22
import {
33
globalHistory,
44
globalInformation,
@@ -7,6 +7,14 @@ import {
77
} from "../utils/handlers";
88
import handleAsync from "./handleAsync";
99

10+
/**
11+
*
12+
* @param req Express request
13+
* @returns Boolean if the request starts with /quiet
14+
*/
15+
export const isQuiet: (req: Request) => boolean = (req) =>
16+
req.baseUrl.startsWith("/quiet");
17+
1018
/**
1119
* The rootRouter handles all the processing of the requests *after* passing through
1220
* all middlewares except not found and error handling middleware
@@ -19,21 +27,20 @@ router.get(
1927
handleAsync(async (req, res, next) => {
2028
// get mode from params
2129
let mode = req.params.mode as "cases" | "deaths" | "recovered";
30+
2231
//default to cases if mode is undefined
2332
mode = mode === undefined ? "cases" : mode;
24-
console.log(mode);
2533

2634
// if the mode is not in the api then return to next handler
2735
if (!["cases", "deaths", "recovered"].includes(mode)) return next();
28-
res.send(await globalHistory(mode));
36+
res.send(await globalHistory(mode, isQuiet(req)));
2937
})
3038
);
3139

3240
router.get(
3341
"/history/:country/:mode?",
3442
handleAsync(async (req, res, next) => {
3543
const country = req.params.country;
36-
console.log("eere");
3744
// get mode from params
3845
let mode = req.params.mode as "cases" | "deaths" | "recovered";
3946

@@ -42,21 +49,21 @@ router.get(
4249

4350
// if the mode is not in the api then return to next handler
4451
if (!["cases", "deaths", "recovered"].includes(mode)) return next();
45-
res.send(await historyPerCountry(country, mode));
52+
res.send(await historyPerCountry(country, mode, isQuiet(req)));
4653
})
4754
);
4855

4956
router.get(
5057
"/:country",
5158
handleAsync(async (req, res, _next) => {
5259
const country = req.params.country;
53-
res.send(await informationPerCountry(country));
60+
res.send(await informationPerCountry(country, isQuiet(req)));
5461
})
5562
);
5663

5764
router.get(
5865
"/",
59-
handleAsync(async (_req, res, _next) => {
60-
res.send(await globalInformation());
66+
handleAsync(async (req, res, _next) => {
67+
res.send(await globalInformation(isQuiet(req)));
6168
})
6269
);

src/api/userAgent.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Request, Response, NextFunction } from "express";
2+
const { version } = require("../../package.json");
23

34
// Type of middleware and handler
45
export type Handler = (
@@ -7,17 +8,28 @@ export type Handler = (
78
next: NextFunction
89
) => Promise<void> | void;
910

11+
/**
12+
*
13+
* @param userAgent The user agent of the requester
14+
* @returns A boolean that is true of the user agent provided is from curl / wget / httpie
15+
*/
1016
const isTerminal: (userAgent: string | undefined) => boolean = (userAgent) => {
1117
if (userAgent === undefined) return false;
1218
if (/curl|wget|httpie/i.test(userAgent)) return true;
1319
return false;
1420
};
1521

1622
export const userAgentMiddleware: Handler = (req, res, next) => {
23+
/**
24+
* Get the user agent from the request
25+
* Determine if the user agent is from curl / wget / httpie
26+
* If true then proceed using the next function
27+
* Else return with message
28+
*/
1729
const userAgent = req.headers["user-agent"];
1830
if (!isTerminal(userAgent)) {
1931
res.send(
20-
`Welcome to COVID-19 Tracker CLI v3.9.3 by Waren Gonzaga.\n\nPlease visit: https://warengonza.ga/covid19-tracker-cli`
32+
`Welcome to COVID-19 Tracker CLI v${version} by Waren Gonzaga with Wareneutron Developers\nPlease visit: https://warengonza.ga/covid19-tracker-cli\n`
2133
);
2234
return;
2335
}

src/cli.ts

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import argv from "minimist";
2-
import { generateColorTable } from "./utils/generateTable";
32
import {
43
globalHistory,
54
globalInformation,
65
historyPerCountry,
76
informationPerCountry,
87
} from "./utils/handlers";
8+
import {
9+
globalHistoryPlain,
10+
globalInformationPlain,
11+
historyPerCountryPlain,
12+
informationPerCountryPlain,
13+
} from "./utils/plainHandlers";
914

1015
const args = argv(process.argv.slice(2));
11-
let { history, mode, help } = args;
16+
let { history, mode, help, quiet, plain } = args;
1217
const country = args._[0];
1318

1419
const { version } = require("../package.json");
@@ -22,29 +27,49 @@ Country: Can be a country name or ISO 3166-1 alpha-2 country code
2227
2328
Options:
2429
--history Show a chart of country's cases of world's cases
25-
--mode Use with --history to make show a chart of cases, deaths, or recovered`;
30+
--mode Use with --history to make show a chart of cases, deaths, or recovered
31+
--quiet Only show necessary information
32+
--plain Enable plain mode`;
2633

2734
let output: string = "";
2835
const main = async () => {
2936
if (help) return console.log(helpMessage);
37+
quiet = quiet === undefined ? false : quiet;
3038

31-
if (history === undefined || typeof history === "undefined") {
32-
if (country === undefined) output = await globalInformation();
33-
else output = await informationPerCountry(country);
39+
if (history === undefined) {
40+
if (country === undefined) {
41+
output =
42+
plain === true
43+
? await globalInformationPlain(quiet)
44+
: await globalInformation(quiet);
45+
} else {
46+
output =
47+
plain === true
48+
? await informationPerCountryPlain(country, quiet)
49+
: await informationPerCountry(country, quiet);
50+
}
3451
}
3552

36-
mode = mode === undefined || typeof mode === "undefined" ? "cases" : mode; // defauilt to cases if mode is not present
53+
mode = mode === undefined ? "cases" : mode; // default to cases if mode is not present
3754
if (!["cases", "deaths", "recovered"].includes(mode)) mode === "cases"; // default to cases if mode is not cases | deaths | recovered
3855

3956
if (history) {
40-
if (country === undefined) output = await globalHistory(mode);
41-
else output = await historyPerCountry(country, mode);
57+
if (country === undefined) {
58+
output =
59+
plain === true
60+
? await globalHistoryPlain(mode, quiet)
61+
: await globalHistory(mode, quiet);
62+
} else {
63+
output =
64+
plain === true
65+
? await historyPerCountryPlain(country, mode, quiet)
66+
: await historyPerCountry(country, mode, quiet);
67+
}
4268
}
4369

4470
console.log(output);
4571
};
4672

4773
main().catch((err) => {
48-
let errorTable = generateColorTable([err.message], "red");
49-
console.log(errorTable);
74+
console.log(err.message + "\n");
5075
});

0 commit comments

Comments
 (0)