Compare commits
No commits in common. "13fb4db1d1a6b8342865f55f1816b50350b8bff4" and "5a7021b674f18b8f345328cf78702a61ed4fe306" have entirely different histories.
13fb4db1d1
...
5a7021b674
@ -27,13 +27,18 @@ const defaults = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export async function postNewPage() {
|
export async function postNewPage() {
|
||||||
return shoofetch(`${apiUrl}/page/new`, {
|
return fetch(`${apiUrl}/page/new`, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
})
|
...defaults
|
||||||
|
}).then((res) => res.json())
|
||||||
|
.then((data) => data.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchPageList() {
|
export async function fetchPageList() {
|
||||||
return shoofetch(`${apiUrl}/pages`, {method: 'GET'});
|
return fetch(`${apiUrl}/pages`, {
|
||||||
|
method: 'GET',
|
||||||
|
...defaults
|
||||||
|
}).then((res) => res.json())
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function fetchPage(id) {
|
export async function fetchPage(id) {
|
||||||
|
@ -17,10 +17,10 @@ function Landing() {
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
|
||||||
const makeNewPage = useMutation({ // for changing the value when we're done with it
|
const makeNewPage = useMutation({ // for changing the value when we're done with it
|
||||||
mutationFn: () => postNewPage(),
|
mutationFn: () => postNewPage()
|
||||||
|
.catch((error) => { console.log("got an error", error.json()) }),
|
||||||
onSettled: async (data, error, variables) => {
|
onSettled: async (data, error, variables) => {
|
||||||
// Invalidate and navigate to the new page
|
// Invalidate and navigate to the new page
|
||||||
console.log(data, error, variables);
|
|
||||||
await queryClient.invalidateQueries({ queryKey: ['pages'] });
|
await queryClient.invalidateQueries({ queryKey: ['pages'] });
|
||||||
navigate(`/${data}/edit`);
|
navigate(`/${data}/edit`);
|
||||||
},
|
},
|
||||||
|
@ -14,9 +14,9 @@ export default function PageList({pages, ...props}) {
|
|||||||
else if (error) outputContents = `Error encountered: ${error}`;
|
else if (error) outputContents = `Error encountered: ${error}`;
|
||||||
else outputContents = (
|
else outputContents = (
|
||||||
<ol {...props}>
|
<ol {...props}>
|
||||||
{ data.map(({number, title}) =>
|
{ data.map(({id, title}) =>
|
||||||
<li key={number} >
|
<li key={id} >
|
||||||
<a href={`/${number}`} {...noLoad} >{title}</a>
|
<a href={`/${id}`} {...noLoad} >{title}</a>
|
||||||
</li>
|
</li>
|
||||||
)}
|
)}
|
||||||
</ol>
|
</ol>
|
||||||
|
@ -16,9 +16,9 @@ function Profile() {
|
|||||||
retry: 1
|
retry: 1
|
||||||
});
|
});
|
||||||
|
|
||||||
useEffect(() => { if (!loggedIn) navigate('/'); }, [loggedIn]);
|
//useEffect(() => { if (!loggedIn) navigate('/'); }, [loggedIn]);
|
||||||
|
|
||||||
const { id, name, favoriteColor, leastFavoriteColor } = (data || {});
|
const { name, favoriteColor, leastFavoriteColor } = (data || {});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="main-column">
|
<div className="main-column">
|
||||||
@ -27,10 +27,6 @@ function Profile() {
|
|||||||
<p>there {isError ? "is" : "isn't"} an error</p>
|
<p>there {isError ? "is" : "isn't"} an error</p>
|
||||||
<p>error is {error?.message}</p>
|
<p>error is {error?.message}</p>
|
||||||
<form onSubmit={handleSubmit(() => {})}>
|
<form onSubmit={handleSubmit(() => {})}>
|
||||||
<label>
|
|
||||||
Id:
|
|
||||||
<input {...register("id")} value={id} disabled/>
|
|
||||||
</label>
|
|
||||||
<label>
|
<label>
|
||||||
User name:
|
User name:
|
||||||
<input {...register("name")} value={name}/>
|
<input {...register("name")} value={name}/>
|
||||||
|
58
db/initialize_db.js
Normal file
58
db/initialize_db.js
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
const libsql = require("@libsql/client");
|
||||||
|
const showdown = require("showdown");
|
||||||
|
|
||||||
|
const createPages = `
|
||||||
|
create table if not exists pages (
|
||||||
|
id integer primary key,
|
||||||
|
title varchar(255),
|
||||||
|
description text,
|
||||||
|
html text
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
const createUsers = `
|
||||||
|
create table if not exists users (
|
||||||
|
name varchar(64) primary key,
|
||||||
|
password varchar(128)
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
const createTokens = `
|
||||||
|
create table if not exists tokens (
|
||||||
|
)
|
||||||
|
`;
|
||||||
|
|
||||||
|
async function initDb() {
|
||||||
|
const config = {
|
||||||
|
url: "http://127.0.0.1:8000"
|
||||||
|
};
|
||||||
|
|
||||||
|
const db = libsql.createClient(config);
|
||||||
|
|
||||||
|
const converter = new showdown.Converter();
|
||||||
|
|
||||||
|
console.log("creating page table")
|
||||||
|
console.log(await db.execute(createPages));
|
||||||
|
|
||||||
|
console.log("finding pages that havent been rendered");
|
||||||
|
const rows = (await db.execute(`select * from pages where html is null`)).rows;
|
||||||
|
console.log(rows);
|
||||||
|
|
||||||
|
rows.forEach(async ({id, title, description, html}) => {
|
||||||
|
console.log(`rendering page number ${id}`)
|
||||||
|
console.log(`${id}. ${title}: ${description} ( ${html} )`);
|
||||||
|
|
||||||
|
const renderedPage = converter.makeHtml(description);
|
||||||
|
|
||||||
|
await db.execute({
|
||||||
|
sql: `replace into pages (id, title, description, html) values (?, ?, ?, ?)`,
|
||||||
|
args: [id, title, description, renderedPage]
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log("creating user table");
|
||||||
|
console.log(await db.execute(createUsers));
|
||||||
|
}
|
||||||
|
|
||||||
|
initDb();
|
348
db/package-lock.json
generated
Normal file
348
db/package-lock.json
generated
Normal file
@ -0,0 +1,348 @@
|
|||||||
|
{
|
||||||
|
"name": "forest-db",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"lockfileVersion": 3,
|
||||||
|
"requires": true,
|
||||||
|
"packages": {
|
||||||
|
"": {
|
||||||
|
"name": "forest-db",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@libsql/client": "^0.12.0",
|
||||||
|
"showdown": "^2.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/client": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/client/-/client-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-Jt9ijfzlmswZzxRRksEv8Igbw7ER9IX/RSrwzEIRyzwwQLcpeZGGrnDQP9S7UPCJ90uFDiaICFiyhvwO+60DmA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@libsql/core": "^0.12.0",
|
||||||
|
"@libsql/hrana-client": "^0.7.0",
|
||||||
|
"js-base64": "^3.7.5",
|
||||||
|
"libsql": "^0.4.4",
|
||||||
|
"promise-limit": "^2.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/core": {
|
||||||
|
"version": "0.12.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/core/-/core-0.12.0.tgz",
|
||||||
|
"integrity": "sha512-PZJF4qvPbDWZfXk0Tr+O5xaMhFoetA1gIVPgYLH6Bc6gAeyYxhGw268p+95SkADZDjB5CYPcVLvfQEjSVeR3Zw==",
|
||||||
|
"dependencies": {
|
||||||
|
"js-base64": "^3.7.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/darwin-arm64": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/darwin-arm64/-/darwin-arm64-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-xLdnn0NrgSk6OMi716FFs/27Hs33jtSd2fkKi/72Ey/qBtPWcB1BMurDQekzi0yAcfQTjGqIz7tpOibyjiEPyQ==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/darwin-x64": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/darwin-x64/-/darwin-x64-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-rZsEWj0H7oCqd5Y2pe0RzKmuQXC2OB1RbnFy4CvjeAjT6MP6mFp+Vx9mTCAUuJMhuoSVMsFPUJRpAQznl9E3Tg==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/hrana-client": {
|
||||||
|
"version": "0.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/hrana-client/-/hrana-client-0.7.0.tgz",
|
||||||
|
"integrity": "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@libsql/isomorphic-fetch": "^0.3.1",
|
||||||
|
"@libsql/isomorphic-ws": "^0.1.5",
|
||||||
|
"js-base64": "^3.7.5",
|
||||||
|
"node-fetch": "^3.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/isomorphic-fetch": {
|
||||||
|
"version": "0.3.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/isomorphic-fetch/-/isomorphic-fetch-0.3.1.tgz",
|
||||||
|
"integrity": "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=18.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/isomorphic-ws": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/isomorphic-ws/-/isomorphic-ws-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-DtLWIH29onUYR00i0GlQ3UdcTRC6EP4u9w/h9LxpUZJWRMARk6dQwZ6Jkd+QdwVpuAOrdxt18v0K2uIYR3fwFg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/ws": "^8.5.4",
|
||||||
|
"ws": "^8.13.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/linux-arm64-gnu": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/linux-arm64-gnu/-/linux-arm64-gnu-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-VR09iu6KWGJ6fauCn59u/jJ9OA+/A2yQ0dr2HDN2zkRueLC6D2oGYt4gPfLZPFKf+WJpVMtIhNfd+Ru9MMaFkA==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/linux-arm64-musl": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/linux-arm64-musl/-/linux-arm64-musl-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-74hvD5ej4rBshhxFGNYU16a3m8B/NjIPvhlZ/flG1Oeydfo6AuUXSSNFi+H5+zi9/uWuzyz5TLVeQcraoUV10A==",
|
||||||
|
"cpu": [
|
||||||
|
"arm64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/linux-x64-gnu": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/linux-x64-gnu/-/linux-x64-gnu-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-gb5WObGO3+rbuG8h9font1N02iF+zgYAgY0wNa8BNiZ5A9UolZKFxiqGFS7eHaAYfemHJKKTT+aAt3X2p5TibA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/linux-x64-musl": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/linux-x64-musl/-/linux-x64-musl-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-JfyE6OVC5X4Nr4cFF77VhB1o+hBRxAqYT9YdeqnWdAQSYc/ASi5HnRALLAQEsGacFPZZ32pixfraQmPE3iJFfw==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"linux"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@libsql/win32-x64-msvc": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@libsql/win32-x64-msvc/-/win32-x64-msvc-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-57GGurNJhOhq3XIopLdGnCoQ4kQAcmbmzzFoC4tpvDE/KSbwZ/13zqJWhQA41nMGk/PKM1XKfKmbIybKx1+eqA==",
|
||||||
|
"cpu": [
|
||||||
|
"x64"
|
||||||
|
],
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"win32"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"node_modules/@neon-rs/load": {
|
||||||
|
"version": "0.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.4.tgz",
|
||||||
|
"integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="
|
||||||
|
},
|
||||||
|
"node_modules/@types/node": {
|
||||||
|
"version": "22.5.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.5.5.tgz",
|
||||||
|
"integrity": "sha512-Xjs4y5UPO/CLdzpgR6GirZJx36yScjh73+2NlLlkFRSoQN8B0DpfXPdZGnvVmLRLOsqDpOfTNv7D9trgGhmOIA==",
|
||||||
|
"dependencies": {
|
||||||
|
"undici-types": "~6.19.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/ws": {
|
||||||
|
"version": "8.5.12",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
|
||||||
|
"integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/commander": {
|
||||||
|
"version": "9.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz",
|
||||||
|
"integrity": "sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/data-uri-to-buffer": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 12"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/detect-libc": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/fetch-blob": {
|
||||||
|
"version": "3.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz",
|
||||||
|
"integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jimmywarting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "paypal",
|
||||||
|
"url": "https://paypal.me/jimmywarting"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"node-domexception": "^1.0.0",
|
||||||
|
"web-streams-polyfill": "^3.0.3"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20 || >= 14.13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/formdata-polyfill": {
|
||||||
|
"version": "4.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
|
||||||
|
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
|
||||||
|
"dependencies": {
|
||||||
|
"fetch-blob": "^3.1.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12.20.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/js-base64": {
|
||||||
|
"version": "3.7.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.7.tgz",
|
||||||
|
"integrity": "sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw=="
|
||||||
|
},
|
||||||
|
"node_modules/libsql": {
|
||||||
|
"version": "0.4.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/libsql/-/libsql-0.4.5.tgz",
|
||||||
|
"integrity": "sha512-sorTJV6PNt94Wap27Sai5gtVLIea4Otb2LUiAUyr3p6BPOScGMKGt5F1b5X/XgkNtcsDKeX5qfeBDj+PdShclQ==",
|
||||||
|
"cpu": [
|
||||||
|
"x64",
|
||||||
|
"arm64",
|
||||||
|
"wasm32"
|
||||||
|
],
|
||||||
|
"os": [
|
||||||
|
"darwin",
|
||||||
|
"linux",
|
||||||
|
"win32"
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@neon-rs/load": "^0.0.4",
|
||||||
|
"detect-libc": "2.0.2"
|
||||||
|
},
|
||||||
|
"optionalDependencies": {
|
||||||
|
"@libsql/darwin-arm64": "0.4.5",
|
||||||
|
"@libsql/darwin-x64": "0.4.5",
|
||||||
|
"@libsql/linux-arm64-gnu": "0.4.5",
|
||||||
|
"@libsql/linux-arm64-musl": "0.4.5",
|
||||||
|
"@libsql/linux-x64-gnu": "0.4.5",
|
||||||
|
"@libsql/linux-x64-musl": "0.4.5",
|
||||||
|
"@libsql/win32-x64-msvc": "0.4.5"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-domexception": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/jimmywarting"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://paypal.me/jimmywarting"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.5.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
|
||||||
|
"dependencies": {
|
||||||
|
"data-uri-to-buffer": "^4.0.0",
|
||||||
|
"fetch-blob": "^3.1.4",
|
||||||
|
"formdata-polyfill": "^4.0.10"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/node-fetch"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/promise-limit": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/promise-limit/-/promise-limit-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-7nJ6v5lnJsXwGprnGXga4wx6d1POjvi5Qmf1ivTRxTjH4Z/9Czja/UCMLVmB9N93GeWOU93XaFaEt6jbuoagNw=="
|
||||||
|
},
|
||||||
|
"node_modules/showdown": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/showdown/-/showdown-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"commander": "^9.0.0"
|
||||||
|
},
|
||||||
|
"bin": {
|
||||||
|
"showdown": "bin/showdown.js"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.paypal.me/tiviesantos"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/undici-types": {
|
||||||
|
"version": "6.19.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
||||||
|
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
||||||
|
},
|
||||||
|
"node_modules/web-streams-polyfill": {
|
||||||
|
"version": "3.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz",
|
||||||
|
"integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/ws": {
|
||||||
|
"version": "8.18.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
|
||||||
|
"integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"bufferutil": "^4.0.1",
|
||||||
|
"utf-8-validate": ">=5.0.2"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"bufferutil": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"utf-8-validate": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
db/package.json
Normal file
20
db/package.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"name": "forest-db",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "database tools for the forest",
|
||||||
|
"main": "db.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "sqld -d the_big_db.db --http-listen-addr=127.0.0.1:8000",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://git.shoofle.net/shoofle/the-forest"
|
||||||
|
},
|
||||||
|
"author": "shoofle",
|
||||||
|
"license": "ISC",
|
||||||
|
"dependencies": {
|
||||||
|
"@libsql/client": "^0.12.0",
|
||||||
|
"showdown": "^2.1.0"
|
||||||
|
}
|
||||||
|
}
|
@ -1,79 +1,48 @@
|
|||||||
// this is a horrible script i use and edit for db revisions and migrations. i hate it.
|
|
||||||
// i should have a db migration plan but this is not, and probably never will be, big
|
|
||||||
// enough of a project to really warrant it.
|
|
||||||
|
|
||||||
const sqlite = require("better-sqlite3");
|
const sqlite = require("better-sqlite3");
|
||||||
const showdown = require("showdown");
|
const showdown = require("showdown");
|
||||||
const db = new sqlite('the_big_db.db', { verbose: console.log });
|
const db = new sqlite('./the_big_db.db', { verbose: console.log });
|
||||||
|
|
||||||
const converter = new showdown.Converter();
|
const converter = new showdown.Converter();
|
||||||
|
|
||||||
const createPages = db.prepare(`
|
const createPages = db.prepare(`
|
||||||
create table if not exists pages (
|
create table if not exists pages (
|
||||||
id integer primary key,
|
id integer primary key,
|
||||||
number integer autoincrement,
|
|
||||||
|
|
||||||
title varchar(255),
|
title varchar(255),
|
||||||
|
|
||||||
description text,
|
description text,
|
||||||
html text,
|
html text
|
||||||
|
|
||||||
time timestamp default current_timestamp,
|
|
||||||
author integer
|
|
||||||
)
|
)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
const createUsers = db.prepare(`
|
const createUsers = db.prepare(`
|
||||||
create table if not exists users (
|
create table if not exists users (
|
||||||
id integer primary key,
|
name varchar(64) primary key,
|
||||||
|
|
||||||
name varchar(64) unique,
|
|
||||||
password varchar(128)
|
password varchar(128)
|
||||||
)
|
)
|
||||||
`);
|
`);
|
||||||
|
|
||||||
|
|
||||||
function migratePages() {
|
function initDb() {
|
||||||
console.log("moving old table to a temporary");
|
console.log("creating page table")
|
||||||
console.log(db.prepare(`alter table pages rename to old_pages`).run())
|
|
||||||
|
|
||||||
console.log("creating new page table")
|
|
||||||
console.log(createPages.run());
|
console.log(createPages.run());
|
||||||
|
|
||||||
console.log('iterating over old pages');
|
console.log("finding pages that havent been rendered");
|
||||||
rows = db.prepare(`select * from old_pages`).all();
|
rows = db.prepare(`select * from pages where html is null`).all();
|
||||||
|
console.log(rows);
|
||||||
|
|
||||||
const insertPage = db.prepare(`insert into pages (number, title, description, html) values (:id, :title, :description, :html)`);
|
const insertPage = db.prepare(`replace into pages (id, title, description, html) values (:id, :title, :description, :html)`);
|
||||||
|
|
||||||
rows.forEach((pageData) => {
|
rows.forEach((pageData) => {
|
||||||
const {id, title, description, html} = pageData;
|
const {id, title, description, html} = pageData;
|
||||||
console.log(`rendering page number ${id}`)
|
console.log(`rendering page number ${id}`)
|
||||||
|
console.log(`${id}. ${title}: ${description} ( ${html} )`);
|
||||||
|
|
||||||
const renderedPage = converter.makeHtml(description);
|
const renderedPage = converter.makeHtml(description);
|
||||||
|
|
||||||
insertPage.run({...pageData, html: renderedPage});
|
insertPage.run({...pageData, html: renderedPage});
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log("getting rid of old table");
|
console.log("creating user table");
|
||||||
console.log(db.prepare("drop table old_pages").run());
|
|
||||||
}
|
|
||||||
|
|
||||||
db.transaction(migratePages)();
|
|
||||||
|
|
||||||
function migrateUsers() {
|
|
||||||
console.log("moving old users");
|
|
||||||
console.log(db.prepare("alter table users rename to old_users").run());
|
|
||||||
|
|
||||||
console.log("creating new users table");
|
|
||||||
console.log(createUsers.run());
|
console.log(createUsers.run());
|
||||||
|
|
||||||
const insertUser = db.prepare("insert into users (name, password) values (:name, :password)")
|
|
||||||
db.prepare("select * from old_users").all().forEach((user) => {
|
|
||||||
console.log(insertUser.run(user));
|
|
||||||
});
|
|
||||||
|
|
||||||
console.log("clearing old table");
|
|
||||||
console.log(db.prepare("drop table old_users").run());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
db.transaction(migrateUsers)();
|
initDb();
|
@ -4,16 +4,17 @@ const { circular } = require('graphology-layout');
|
|||||||
|
|
||||||
function graphFromList(allTheStuff) {
|
function graphFromList(allTheStuff) {
|
||||||
const graph = new graphology.Graph();
|
const graph = new graphology.Graph();
|
||||||
for (const {number, html} of allTheStuff) {
|
for (const {id, html} of allTheStuff) {
|
||||||
if (!graph.hasNode(number)) graph.addNode(number);
|
|
||||||
|
graph.addNode(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const {number, html} of allTheStuff) {
|
for (const {id, html} of allTheStuff) {
|
||||||
const { document } = (new JSDOM(html)).window;
|
const { document } = (new JSDOM(html)).window;
|
||||||
const links = document.querySelectorAll('a');
|
const links = document.querySelectorAll('a');
|
||||||
links.forEach((link) => {
|
links.forEach((link) => {
|
||||||
const referent = link.href.replace("/","");
|
const referent = link.href.replace("/","");
|
||||||
graph.mergeEdge(number, referent);
|
graph.mergeEdge(id, referent);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ app.use(user_routes);
|
|||||||
|
|
||||||
app.get('/graph', (req, res) => {
|
app.get('/graph', (req, res) => {
|
||||||
try {
|
try {
|
||||||
const rows = db.prepare('select number, html from pages').all();
|
const rows = db.prepare('select id, html from pages').all();
|
||||||
const graph = graphFromList(rows);
|
const graph = graphFromList(rows);
|
||||||
res.status(200).json(graph);
|
res.status(200).json(graph);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -2,26 +2,16 @@ const express = require('express');
|
|||||||
const app = express.Router();
|
const app = express.Router();
|
||||||
|
|
||||||
const sqlite = require('better-sqlite3');
|
const sqlite = require('better-sqlite3');
|
||||||
const db = new sqlite('the_big_db.db', { verbose: console.log });
|
const db = new sqlite('../the_big_db.db', { verbose: console.log });
|
||||||
|
|
||||||
const { loginRequired } = require('../authStuff.js');
|
const { loginRequired } = require('../authStuff.js');
|
||||||
|
|
||||||
const showdown = require('showdown');
|
const showdown = require('showdown');
|
||||||
const converter = new showdown.Converter();
|
const converter = new showdown.Converter();
|
||||||
|
|
||||||
const pageListQuery = db.prepare(`
|
|
||||||
select p.number, p.title, p.time
|
|
||||||
from pages p
|
|
||||||
where time >= (
|
|
||||||
select max(s.time)
|
|
||||||
from pages s
|
|
||||||
where s.number = p.number
|
|
||||||
)
|
|
||||||
order by p.time desc
|
|
||||||
`);
|
|
||||||
app.get('/pages', (req, res) => {
|
app.get('/pages', (req, res) => {
|
||||||
try {
|
try {
|
||||||
const pages = pageListQuery.all();
|
const pages = db.prepare('select id, title from pages').all();
|
||||||
res.status(200).json(pages);
|
res.status(200).json(pages);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({"error": error});
|
res.status(500).json({"error": error});
|
||||||
@ -30,19 +20,17 @@ app.get('/pages', (req, res) => {
|
|||||||
|
|
||||||
app.post('/page/new', loginRequired, (req, res) => {
|
app.post('/page/new', loginRequired, (req, res) => {
|
||||||
try {
|
try {
|
||||||
const maxPageNumber = db.prepare('select max(number) as maximum from pages').get()
|
const newPage = db.prepare('insert into pages (title, description) values (?, ?) returning id')
|
||||||
const newPageNumber = maxPageNumber.maximum + 1;
|
.get("new page", "this page is new!");
|
||||||
const newPage = db.prepare('insert into pages (number, title, description, author) values (?, ?, ?, ?) returning number')
|
res.status(200).json(newPage);
|
||||||
.get(newPageNumber, "new page", "this page is new!", req.session.userId);
|
|
||||||
res.status(200).json(newPageNumber);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({"error": error});
|
res.status(500).json({"error": error});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/page/:number', (req, res) => {
|
app.get('/page/:id', (req, res) => {
|
||||||
try {
|
try {
|
||||||
const page = db.prepare('select * from pages where number=:number order by time desc').get(req.params);
|
const page = db.prepare('select * from pages where id=:id').get(req.params);
|
||||||
if (page === undefined) res.status(404).json({"error": "page not found"});
|
if (page === undefined) res.status(404).json({"error": "page not found"});
|
||||||
else res.status(200).json(page);
|
else res.status(200).json(page);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -50,11 +38,11 @@ app.get('/page/:number', (req, res) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/page/:number', loginRequired, (req, res) => {
|
app.post('/page/:id', loginRequired, (req, res) => {
|
||||||
try {
|
try {
|
||||||
const html = converter.makeHtml(req.body.description);
|
const html = converter.makeHtml(req.body.description);
|
||||||
const changes = db.prepare('insert into pages (number, title, description, html, author) values (?, ?, ?, ?, ?)')
|
const changes = db.prepare('replace into pages (id, title, description, html) values (?, ?, ?, ?)')
|
||||||
.run(req.params.number, req.body.title, req.body.description, html, req.session.userId);
|
.run(req.params.id, req.body.title, req.body.description, html);
|
||||||
res.status(200).json(changes);
|
res.status(200).json(changes);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({"error": error});
|
res.status(500).json({"error": error});
|
||||||
@ -63,29 +51,12 @@ app.post('/page/:number', loginRequired, (req, res) => {
|
|||||||
|
|
||||||
app.delete('/page/:id', loginRequired, (req, res) => {
|
app.delete('/page/:id', loginRequired, (req, res) => {
|
||||||
try {
|
try {
|
||||||
const changes = db.prepare('delete from pages where number = ?').run(req.params.id);
|
const changes = db.prepare('delete from pages where id = ?').run(req.params.id);
|
||||||
res.status(200).json({id: req.params.id});
|
res.status(200).json({id: req.params.id});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
res.status(500).json({"error": error});
|
res.status(500).json({"error": error});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/page/:number/history', (req, res) => {
|
|
||||||
try {
|
|
||||||
const all = db.prepare('select number, id, time, author from pages where number=:number order by time desc').all(req.params);
|
|
||||||
res.status(200).json(all);
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({"error": error});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
app.get('/page/:number/:id', (req, res) => {
|
|
||||||
try {
|
|
||||||
const page = db.prepare('select * from pages where number=:number and id=:id').get(req.params);
|
|
||||||
if (page === undefined) res.status(404).json({"error": "page not found"});
|
|
||||||
else res.status(200).json(page);
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({"error": error});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
module.exports = app;
|
module.exports = app;
|
@ -2,7 +2,7 @@ const express = require('express');
|
|||||||
const app = express.Router();
|
const app = express.Router();
|
||||||
|
|
||||||
const sqlite = require('better-sqlite3');
|
const sqlite = require('better-sqlite3');
|
||||||
const db = new sqlite('the_big_db.db', { verbose: console.log });
|
const db = new sqlite('../the_big_db.db', { verbose: console.log });
|
||||||
|
|
||||||
const argon2 = require('argon2');
|
const argon2 = require('argon2');
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ app.post('/login', async (req, res) => {
|
|||||||
const {name, password} = req.body;
|
const {name, password} = req.body;
|
||||||
|
|
||||||
// fetch username and passswords from the db
|
// fetch username and passswords from the db
|
||||||
const storedUser = db.prepare('select * from users where name = ?').get(name);
|
const storedUser = db.prepare('select name, password from users where name = ?').get(name);
|
||||||
if (!storedUser) {
|
if (!storedUser) {
|
||||||
return res.status(401).json({"error": "password/username combo not found in database"});
|
return res.status(401).json({"error": "password/username combo not found in database"});
|
||||||
}
|
}
|
||||||
@ -48,9 +48,8 @@ app.post('/login', async (req, res) => {
|
|||||||
|
|
||||||
// set the session cookie and rreturn 200!
|
// set the session cookie and rreturn 200!
|
||||||
req.session.name = name;
|
req.session.name = name;
|
||||||
req.session.userId = storedUser.id;
|
|
||||||
console.log('setting req.session.name! : ', req.session);
|
console.log('setting req.session.name! : ', req.session);
|
||||||
return res.status(200).json({message: "successfully logged in!", id: storedUser.id, name: name});
|
return res.status(200).json({message: "successfully logged in!", name: name});
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/logout', (req, res) => {
|
app.post('/logout', (req, res) => {
|
||||||
@ -60,7 +59,6 @@ app.post('/logout', (req, res) => {
|
|||||||
|
|
||||||
app.get('/user', loginRequired, (req, res) => {
|
app.get('/user', loginRequired, (req, res) => {
|
||||||
res.status(200).json({
|
res.status(200).json({
|
||||||
"id": req.session.userId,
|
|
||||||
"name": req.session.name,
|
"name": req.session.name,
|
||||||
"favoriteColor": "red",
|
"favoriteColor": "red",
|
||||||
"leastFavoriteColor": "also red"
|
"leastFavoriteColor": "also red"
|
||||||
|
Loading…
Reference in New Issue
Block a user