feat: set paste route

This commit is contained in:
alok8bb 2022-07-08 11:12:21 +05:30
parent 6abe5aebdf
commit e1c79a1840
No known key found for this signature in database
GPG Key ID: 748A8580B906551C
10 changed files with 285 additions and 23 deletions

4
.env
View File

@ -1 +1,5 @@
PORT = 8080
PGUSER=alok-pg
PGHOST=localhost
PGDATABASE=okiba
PGPORT=5432

4
.gitignore vendored
View File

@ -1,3 +1,5 @@
node_modules/
public/
src/test
test/
data/
.env

View File

@ -11,12 +11,15 @@
"license": "ISC",
"devDependencies": {
"@types/express": "^4.17.13",
"@types/node": "^18.0.1",
"@types/node": "^18.0.3",
"@types/pg": "^8.6.5",
"ts-node-dev": "^2.0.0",
"typescript": "^4.7.4"
},
"dependencies": {
"chalk": "^4.1.2",
"dotenv": "^16.0.1",
"express": "^4.18.1"
"express": "^4.18.1",
"pg": "^8.7.3"
}
}

170
pnpm-lock.yaml generated
View File

@ -2,20 +2,26 @@ lockfileVersion: 5.4
specifiers:
'@types/express': ^4.17.13
'@types/node': ^18.0.1
'@types/node': ^18.0.3
'@types/pg': ^8.6.5
chalk: ^4.1.2
dotenv: ^16.0.1
express: ^4.18.1
pg: ^8.7.3
ts-node-dev: ^2.0.0
typescript: ^4.7.4
dependencies:
chalk: 4.1.2
dotenv: 16.0.1
express: 4.18.1
pg: 8.7.3
devDependencies:
'@types/express': 4.17.13
'@types/node': 18.0.1
ts-node-dev: 2.0.0_qqrtuuv3y2pz7xoxv47yka6pmi
'@types/node': 18.0.3
'@types/pg': 8.6.5
ts-node-dev: 2.0.0_fxk5i3xm3ivo7fjwhcizcinpla
typescript: 4.7.4
packages:
@ -27,8 +33,8 @@ packages:
'@jridgewell/trace-mapping': 0.3.9
dev: true
/@jridgewell/resolve-uri/3.0.8:
resolution: {integrity: sha512-YK5G9LaddzGbcucK4c8h5tWFmMPBvRZ/uyWmN1/SbBdIvqGUdWGkJ5BAaccgs6XbzVLsqbPJrBSFwKv3kT9i7w==}
/@jridgewell/resolve-uri/3.1.0:
resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
engines: {node: '>=6.0.0'}
dev: true
@ -39,7 +45,7 @@ packages:
/@jridgewell/trace-mapping/0.3.9:
resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==}
dependencies:
'@jridgewell/resolve-uri': 3.0.8
'@jridgewell/resolve-uri': 3.1.0
'@jridgewell/sourcemap-codec': 1.4.14
dev: true
@ -63,19 +69,19 @@ packages:
resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==}
dependencies:
'@types/connect': 3.4.35
'@types/node': 18.0.1
'@types/node': 18.0.3
dev: true
/@types/connect/3.4.35:
resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==}
dependencies:
'@types/node': 18.0.1
'@types/node': 18.0.3
dev: true
/@types/express-serve-static-core/4.17.29:
resolution: {integrity: sha512-uMd++6dMKS32EOuw1Uli3e3BPgdLIXmezcfHv7N4c1s3gkhikBplORPpMq3fuWkxncZN1reb16d5n8yhQ80x7Q==}
dependencies:
'@types/node': 18.0.1
'@types/node': 18.0.3
'@types/qs': 6.9.7
'@types/range-parser': 1.2.4
dev: true
@ -93,8 +99,16 @@ packages:
resolution: {integrity: sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==}
dev: true
/@types/node/18.0.1:
resolution: {integrity: sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==}
/@types/node/18.0.3:
resolution: {integrity: sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==}
dev: true
/@types/pg/8.6.5:
resolution: {integrity: sha512-tOkGtAqRVkHa/PVZicq67zuujI4Oorfglsr2IbKofDwBSysnaqSx7W1mDqFqdkGE6Fbgh+PZAl0r/BWON/mozw==}
dependencies:
'@types/node': 18.0.3
pg-protocol: 1.5.0
pg-types: 2.2.0
dev: true
/@types/qs/6.9.7:
@ -109,7 +123,7 @@ packages:
resolution: {integrity: sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ==}
dependencies:
'@types/mime': 1.3.2
'@types/node': 18.0.1
'@types/node': 18.0.3
dev: true
/@types/strip-bom/3.0.0:
@ -139,6 +153,13 @@ packages:
hasBin: true
dev: true
/ansi-styles/4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
dependencies:
color-convert: 2.0.1
dev: false
/anymatch/3.1.2:
resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==}
engines: {node: '>= 8'}
@ -202,6 +223,11 @@ packages:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
dev: true
/buffer-writer/2.0.0:
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
engines: {node: '>=4'}
dev: false
/bytes/3.1.2:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
@ -214,6 +240,14 @@ packages:
get-intrinsic: 1.1.2
dev: false
/chalk/4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
dependencies:
ansi-styles: 4.3.0
supports-color: 7.2.0
dev: false
/chokidar/3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@ -229,6 +263,17 @@ packages:
fsevents: 2.3.2
dev: true
/color-convert/2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
dependencies:
color-name: 1.1.4
dev: false
/color-name/1.1.4:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: false
/concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
@ -425,6 +470,11 @@ packages:
path-is-absolute: 1.0.1
dev: true
/has-flag/4.0.0:
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
engines: {node: '>=8'}
dev: false
/has-symbols/1.0.3:
resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==}
engines: {node: '>= 0.4'}
@ -586,6 +636,10 @@ packages:
wrappy: 1.0.2
dev: true
/packet-reader/1.0.0:
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
dev: false
/parseurl/1.3.3:
resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==}
engines: {node: '>= 0.8'}
@ -604,11 +658,82 @@ packages:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
dev: false
/pg-connection-string/2.5.0:
resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==}
dev: false
/pg-int8/1.0.1:
resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==}
engines: {node: '>=4.0.0'}
/pg-pool/3.5.1_pg@8.7.3:
resolution: {integrity: sha512-6iCR0wVrro6OOHFsyavV+i6KYL4lVNyYAB9RD18w66xSzN+d8b66HiwuP30Gp1SH5O9T82fckkzsRjlrhD0ioQ==}
peerDependencies:
pg: '>=8.0'
dependencies:
pg: 8.7.3
dev: false
/pg-protocol/1.5.0:
resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==}
/pg-types/2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
dependencies:
pg-int8: 1.0.1
postgres-array: 2.0.0
postgres-bytea: 1.0.0
postgres-date: 1.0.7
postgres-interval: 1.2.0
/pg/8.7.3:
resolution: {integrity: sha512-HPmH4GH4H3AOprDJOazoIcpI49XFsHCe8xlrjHkWiapdbHK+HLtbm/GQzXYAZwmPju/kzKhjaSfMACG+8cgJcw==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=2.0.0'
peerDependenciesMeta:
pg-native:
optional: true
dependencies:
buffer-writer: 2.0.0
packet-reader: 1.0.0
pg-connection-string: 2.5.0
pg-pool: 3.5.1_pg@8.7.3
pg-protocol: 1.5.0
pg-types: 2.2.0
pgpass: 1.0.5
dev: false
/pgpass/1.0.5:
resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==}
dependencies:
split2: 4.1.0
dev: false
/picomatch/2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/postgres-array/2.0.0:
resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==}
engines: {node: '>=4'}
/postgres-bytea/1.0.0:
resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==}
engines: {node: '>=0.10.0'}
/postgres-date/1.0.7:
resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==}
engines: {node: '>=0.10.0'}
/postgres-interval/1.2.0:
resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==}
engines: {node: '>=0.10.0'}
dependencies:
xtend: 4.0.2
/proxy-addr/2.0.7:
resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==}
engines: {node: '>= 0.10'}
@ -727,6 +852,11 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/split2/4.1.0:
resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==}
engines: {node: '>= 10.x'}
dev: false
/statuses/2.0.1:
resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==}
engines: {node: '>= 0.8'}
@ -742,6 +872,13 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/supports-color/7.2.0:
resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
engines: {node: '>=8'}
dependencies:
has-flag: 4.0.0
dev: false
/supports-preserve-symlinks-flag/1.0.0:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
@ -764,7 +901,7 @@ packages:
hasBin: true
dev: true
/ts-node-dev/2.0.0_qqrtuuv3y2pz7xoxv47yka6pmi:
/ts-node-dev/2.0.0_fxk5i3xm3ivo7fjwhcizcinpla:
resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==}
engines: {node: '>=0.8.0'}
hasBin: true
@ -783,7 +920,7 @@ packages:
rimraf: 2.7.1
source-map-support: 0.5.21
tree-kill: 1.2.2
ts-node: 10.8.2_qqrtuuv3y2pz7xoxv47yka6pmi
ts-node: 10.8.2_fxk5i3xm3ivo7fjwhcizcinpla
tsconfig: 7.0.0
typescript: 4.7.4
transitivePeerDependencies:
@ -792,7 +929,7 @@ packages:
- '@types/node'
dev: true
/ts-node/10.8.2_qqrtuuv3y2pz7xoxv47yka6pmi:
/ts-node/10.8.2_fxk5i3xm3ivo7fjwhcizcinpla:
resolution: {integrity: sha512-LYdGnoGddf1D6v8REPtIH+5iq/gTDuZqv2/UJUU7tKjuEU8xVZorBM+buCGNjj+pGEud+sOoM4CX3/YzINpENA==}
hasBin: true
peerDependencies:
@ -811,7 +948,7 @@ packages:
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.3
'@types/node': 18.0.1
'@types/node': 18.0.3
acorn: 8.7.1
acorn-walk: 8.2.0
arg: 4.1.3
@ -872,7 +1009,6 @@ packages:
/xtend/4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}
dev: true
/yn/3.1.1:
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}

21
src/db/bin.ts Normal file
View File

@ -0,0 +1,21 @@
import { Pool, QueryResult } from "pg";
import { Word } from "../utils/types";
import { Query } from "./queries";
// query wrappers
export const getAvailableWord = async (db: Pool): Promise<Word | undefined> => {
const data: void | QueryResult<Word> = await db
.query(Query.getAvailableWord)
.catch((err) => err);
if (data != undefined) {
let word = data.rows[0];
return word;
}
return undefined;
};
export const setWordTaken = async (db: Pool, id: number) => {
await db.query(Query.setWordTaken(id)).catch((err) => err);
};

9
src/db/queries.ts Normal file
View File

@ -0,0 +1,9 @@
// query strings
export const Query = {
getAvailableWord:
"SELECT * FROM words WHERE taken = 'f' ORDER BY random() LIMIT 1;",
setWordTaken(id: number) {
return `UPDATE words SET taken = 't' WHERE id = ${id}`;
},
};

View File

@ -1,15 +1,37 @@
import express, { Response, Request, Express } from "express";
import dotenv from "dotenv";
import BinRouter from "./routes/bin";
import { Client, Pool } from "pg";
import { createDataDir, errorHandler, logError, logSuccess } from "./utils";
dotenv.config();
const app: Express = express();
createDataDir();
// init db
const pool = new Pool();
const client = new Client();
client
.connect()
.then(() => {
logSuccess("Connected to database!");
})
.catch((err: Error) => {
logError(`Could not connect to database! \n\n${err.message}`);
});
// start server
const app: Express = express();
const port = process.env.PORT;
app.use(express.text());
app.get("/", (req: Request, res: Response) => {
res.send("Hello, World!");
});
app.use("/bin/", BinRouter(pool));
app.use(errorHandler);
app.listen(port, () => {
console.log(`Server started on port ${port}`);
logSuccess(`Server started on port ${port}`);
});

36
src/routes/bin.ts Normal file
View File

@ -0,0 +1,36 @@
import { Router, Request, Response, NextFunction } from "express";
import { Pool, QueryResult } from "pg";
import fs from "fs";
import path from "path";
import { Word } from "../utils/types";
import { projectRoot } from "../utils";
import { getAvailableWord, setWordTaken } from "../db/bin";
export default function BinRouter(db: Pool) {
const router: Router = Router();
router.post("/paste", async (req: Request, res: Response) => {
let body: string = req.body;
const word: Word | undefined = await getAvailableWord(db);
if (word != undefined) {
await fs.writeFile(
path.join(projectRoot, "data", word.val + ".txt"),
body,
(err) => err
);
setWordTaken(db, word.id);
console.log(word.id);
return res.status(200).json({
endpoint: word.val,
message: "Code pasted successfully!",
});
}
res.status(500).json({ message: "Something went wrong" });
});
return router;
}

24
src/utils/index.ts Normal file
View File

@ -0,0 +1,24 @@
import chalk from "chalk";
import { ErrorRequestHandler } from "express";
import path from "path";
import fs from "fs";
// logs
export const logError = (msg: string) => console.error(chalk.bold.red(msg));
export const logSuccess = (msg: string) => console.log(chalk.bold.green(msg));
export const projectRoot = path.join(__dirname, "..", "..");
export const errorHandler: ErrorRequestHandler = (err, _, res, __) => {
logError(err);
return res.status(500).json({ message: "Internal server error!" });
};
export const createDataDir = () => {
let dir = path.join(projectRoot, "data");
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir);
}
};

5
src/utils/types.ts Normal file
View File

@ -0,0 +1,5 @@
export type Word = {
id: number;
val: string;
taken: boolean;
};