More refactoring!

This commit is contained in:
Xodrium 2023-02-12 01:53:13 -05:00
parent e368b99775
commit baa669db8b
11 changed files with 173 additions and 180 deletions

View file

@ -0,0 +1,58 @@
<script>
export let data = '';
</script>
<style>
#logo {
width: calc(100vw - 20px);
background: var(--dark-1);
padding: 5px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
position: sticky;
top: 0;
}
#logo a {
padding: 10px;
color: var(--light-1);
font-weight: bold;
}
#logo img {
height: 30px;
width: auto;
display: block;
}
</style>
<div id='logo'>
<a href='/'>
<img src='/icon_sanifae.svg' alt='Sanifae Logo'>
</a>
{#if data.username && data.username != 'false'}
<a href='/user/{data.username}'>
{data.username}
</a>
<a href='/logout'>
Log out
</a>
<a href='/new_post'>
Create
</a>
{:else}
<a href='/account'>
Log in / Register
</a>
{/if}
</div>

View file

@ -0,0 +1,25 @@
<script>
import Post from '$lib/components/Post.svelte';
import Button from '$lib/components/Button.svelte'
export let data;
</script>
{#if data && data.postJson && data.postJson.data}
{#each data.postJson.data as post}
<Post
success={post.success}
username={post.username}
content={post.content}
upvotes={post.upvotes}
downvotes={post.downvotes}
id={post.id}
isAuthor={post.isAuthor}
></Post>
{/each}
{/if}
<p>
<Button clickFunc={() => { window.location.search = 'page=' + ((data.id)-1) }}>Previous page</Button>
<Button clickFunc={() => { window.location.search = 'page=' + ((data.id)+1) }}>Next page</Button>
</p>

View file

@ -1,4 +1,4 @@
const rowCount = 5; const ROW_COUNT = 5;
const AUTH_ACTIONS = [ const AUTH_ACTIONS = [
'postCreate', 'postCreate',
@ -7,7 +7,9 @@ const AUTH_ACTIONS = [
'postDelete' 'postDelete'
]; ];
const fileSizeLimit = 1024*1024*16; const FILE_SIZE_LIMIT = 1024*1024*16;
const VALID_EXTENSIONS = ['png','jpg','jpeg','gif','svg']
var ridArray = {}; var ridArray = {};
@ -15,8 +17,8 @@ import sqlite3 from 'sqlite3'
import { open } from 'sqlite' import { open } from 'sqlite'
import { hash, compare } from 'bcrypt' import { hash, compare } from 'bcrypt'
import { randomBytes, createHash } from 'node:crypto'; import { randomBytes, createHash } from 'node:crypto';
import { readFile, writeFile } from 'node:fs/promises'; import { writeFile } from 'node:fs/promises';
import { calcVote, calcVoteUser, checkLength, checkRegex } from '../util.js'; import { calcVote, checkLength, checkRegex, safePath } from '../util.js';
var db; var db;
async function initDb() { async function initDb() {
@ -55,8 +57,6 @@ let updateUser = async ({user}) => {
let upvotes = 0; let upvotes = 0;
let downvotes = 0; let downvotes = 0;
let reputation = 0;
allPosts.forEach(post => { allPosts.forEach(post => {
upvotes += post.upvotes || 0; upvotes += post.upvotes || 0;
downvotes += post.downvotes || 0; downvotes += post.downvotes || 0;
@ -72,7 +72,7 @@ let updateUser = async ({user}) => {
0, 0,
upvotes, upvotes,
downvotes, downvotes,
calcVoteUser(upvotes,downvotes) calcVote(upvotes,downvotes,'user')
]); ]);
} }
@ -169,21 +169,6 @@ backend.postDelete = async ({id, user}) => {
return {'success': 'Your post has been deleted!', 'href': `/post/${id}` }; return {'success': 'Your post has been deleted!', 'href': `/post/${id}` };
} }
backend.postGet = async ({id, cookies }) => {
var posts = await db.all('SELECT * from post WHERE id = ?', [
id
])
if (!posts || posts.length < 1) {
return {'success': 'Post does not exist.'}
}
var user = (await backend.token({cookies})).data;
return {data: posts[0], isAuthor: posts[0].username == user};
}
backend.userGet = async ({user}) => { backend.userGet = async ({user}) => {
var posts = await db.all('SELECT * from user WHERE username = ?', [ var posts = await db.all('SELECT * from user WHERE username = ?', [
user user
@ -208,26 +193,36 @@ backend.userBio = async ({user}) => {
return {data: posts[0]}; return {data: posts[0]};
} }
backend.postBulk = async ({page,user}) => { backend.postBulk = async ({page, id, user, cookies}) => {
var posts; var posts;
if (!user) { var userAuth = (await backend.token({cookies})).data;
if (!user && !id) {
posts = await db.all('SELECT * from post ORDER BY rating DESC LIMIT ?, ?', [ posts = await db.all('SELECT * from post ORDER BY rating DESC LIMIT ?, ?', [
page*rowCount, page*ROW_COUNT,
rowCount ROW_COUNT
])
} else if (id) {
posts = await db.all('SELECT * from post WHERE id = ?', [
id
]) ])
} else { } else {
posts = await db.all('SELECT * from post WHERE username = ? ORDER BY rating DESC LIMIT ?, ?', [ posts = await db.all('SELECT * from post WHERE username = ? ORDER BY rating DESC LIMIT ?, ?', [
user, user,
page*rowCount, page*ROW_COUNT,
rowCount ROW_COUNT
]) ])
} }
posts = posts.map(post => {
return {...post, isAuthor: userAuth == post.username};
})
return {data: posts}; return {data: posts};
} }
backend.vote = async ({cookies, id, vote, user}) => { backend.vote = async ({id, vote, user}) => {
if (!id || (vote != 'down' && vote != 'up')) return {success: 'fail' }; if (!id || (vote != 'down' && vote != 'up')) return {success: 'fail' };
await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [ await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [
@ -300,12 +295,12 @@ backend.fileCreate = async({img, extension,id, last }) => {
if (!imgHash) if (!imgHash)
return {'success': 'Image not provided.'} return {'success': 'Image not provided.'}
if (imgHash.length > fileSizeLimit) if (imgHash.length > FILE_SIZE_LIMIT)
return {'success': 'Image too big.'} return {'success': 'Image too big.'}
const extensionSafe = extension.replace(/[^a-zA-Z]+/g, '\\$1'); const extensionSafe = safePath(extension);
if (extensionSafe != 'png' && extensionSafe != 'jpg' && extensionSafe != 'svg' && extensionSafe != 'gif') if (VALID_EXTENSIONS.indexOf(extensionSafe) == -1)
return { success: 'Illegal file extension.' }; return { success: 'Illegal file extension.' };
writeFile(`${process.cwd()}/db/post-${imgHash}.${extensionSafe}`,imgData,{encoding: 'base64'}); writeFile(`${process.cwd()}/db/post-${imgHash}.${extensionSafe}`,imgData,{encoding: 'base64'});

View file

@ -20,7 +20,7 @@ let checkRegex = function(string, field, regex) {
return false; return false;
} }
let calcVote = function(up,down) { let calcVote = function(up,down, type) {
var upPadded = up + 3; var upPadded = up + 3;
var downPadded = down + 3; var downPadded = down + 3;
var totalPadded = Math.max(up + down, 3); var totalPadded = Math.max(up + down, 3);
@ -28,26 +28,20 @@ let calcVote = function(up,down) {
var rating = -Math.log((1 / ((((upPadded - downPadded) / (upPadded + downPadded)) + 1) / 2)) - 1) / Math.log(Math.E); var rating = -Math.log((1 / ((((upPadded - downPadded) / (upPadded + downPadded)) + 1) / 2)) - 1) / Math.log(Math.E);
rating = Math.min(rating,10); rating = Math.min(rating,10);
rating = Math.max(rating,-1);
rating = (rating + 11) / 1.1; if (type != 'user') {
rating = Math.max(rating,-1);
rating = (rating + 11) / 1.1;
rating = rating * Math.log(totalPadded);
} else {
rating = Math.round(rating * Math.log(totalPadded) * 10);
}
return rating * Math.log(totalPadded); return rating * Math.log(totalPadded);
} }
let calcVoteUser = function(up,down) {
var upPadded = up + 3;
var downPadded = down + 3;
var totalPadded = Math.max(up + down, 3);
var rating = -Math.log((1 / ((((upPadded - downPadded) / (upPadded + downPadded)) + 1) / 2)) - 1) / Math.log(Math.E);
rating = Math.min(rating,10);
rating = Math.max(rating,-10);
return Math.round(rating * Math.log(totalPadded) * 10);
}
let handleSubmit = async e => { let handleSubmit = async e => {
const ACTION_URL = e.target.action const ACTION_URL = e.target.action
@ -59,6 +53,10 @@ let handleSubmit = async e => {
}).then(x => x.text()); }).then(x => x.text());
} }
let safeName = function (text) {
return text.replaceAll(/[^A-Za-z0-9\-\_]/g, '');
}
let formatPost = function(post) { let formatPost = function(post) {
post = post.split('\n'); post = post.split('\n');
@ -70,28 +68,25 @@ let formatPost = function(post) {
line = line.map(subPost => { line = line.map(subPost => {
var splitPost = subPost.split('||'); var splitPost = subPost.split('||');
if (splitPost.length > 1) { if (splitPost.length > 1) {
var cap1 = splitPost[0]; var cap1 = splitPost[0];
if (cap1 == 'img') { if (cap1 == 'img') {
var matchCleaned = splitPost[1].replace(/(\s+)/g, '\\$1'); var matchCleaned = safeName(subPost[1]);
splitPost = {'type': 'img', 'url': `/img/${matchCleaned}`}; splitPost = {'type': 'img', 'url': `/img/${matchCleaned}`};
return splitPost; return splitPost;
} }
} else if (subPost[0] == '@') { } else if (subPost[0] == '@' || subPost[0] == '#') {
var subPostIn = subPost.substring(0).replaceAll(/[^A-Za-z0-9\-\_]/g, ''); var subPostIn = safeName(subPost.substring(0));
splitPost = {'type': 'link', 'display': subPost, 'url': `/user/${subPostIn}`}; var type = (subPost[0] == '@') ? 'user' : 'post';
splitPost = {'type': 'link', 'display': subPost, 'url': `/${type}/${subPostIn}`};
return splitPost; return splitPost;
} else if (subPost[0] == '#') {
var subPostIn = subPost.substring(0).replaceAll(/[^A-Za-z0-9]/g, '');
splitPost = {'type': 'link', 'display': subPost, 'url': `/post/${subPostIn}`};
return splitPost;
} }
return subPost; return subPost;
@ -102,16 +97,20 @@ let formatPost = function(post) {
return post; return post;
} }
function block(bool) { let block = function(bool) {
return (bool) ? 'block' : 'inline'; return (bool) ? 'block' : 'inline';
} }
let safePath = function(path) {
return path.replace(/[^a-zA-Z]+/g, '\\$1')
}
export { export {
checkLength, checkLength,
checkRegex, checkRegex,
calcVote, calcVote,
handleSubmit, handleSubmit,
calcVoteUser,
formatPost, formatPost,
block block,
safePath
}; };

View file

@ -1,4 +1,19 @@
<style> <style>
#content {
background: var(--light-2);
height: 100vh;
width: calc(100vw - 50px);
padding: 25px;
padding-top: 0px;
display: flex;
flex-direction: column;
align-items: center;
overflow-y: scroll;
}
:global(:root) { :global(:root) {
--dark-1: #2b2f36; --dark-1: #2b2f36;
--dark-2: #d8d8d8; --dark-2: #d8d8d8;
@ -23,78 +38,17 @@
box-shadow: 0px 2px 2.5px 0px var(--dark-2); box-shadow: 0px 2px 2.5px 0px var(--dark-2);
} }
#content {
background: var(--light-2);
height: 100vh;
width: calc(100vw - 50px);
padding: 25px;
padding-top: 0px;
display: flex;
flex-direction: column;
align-items: center;
overflow-y: scroll;
}
#logo {
width: calc(100vw - 20px);
background: var(--dark-1);
padding: 5px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
position: sticky;
top: 0;
}
#logo a {
padding: 10px;
color: var(--light-1);
font-weight: bold;
}
#logo img {
height: 30px;
width: auto;
display: block;
}
</style> </style>
<script> <script>
/** @type {import('./$types').PageData} */ /** @type {import('./$types').PageData} */
export let data; export let data;
import Header from '$lib/components/Header.svelte';
</script> </script>
<div id='content'> <div id='content'>
<div id='logo'> <Header data={data} />
<a href='/'> <slot />
<img src='/icon_sanifae.svg' alt='Sanifae Logo'>
</a>
{#if data.username && data.username != 'false'}
<a href='/user/{data.username}'>
{data.username}
</a>
<a href='/logout'>
Log out
</a>
<a href='/new_post'>
Create
</a>
{:else}
<a href='/account'>
Log in / Register
</a>
{/if}
</div>
<slot></slot>
</div> </div>

View file

@ -1,23 +1,8 @@
<script> <script>
import Post from '$lib/components/Post.svelte'; import PostList from '$lib/components/PostList.svelte';
import Button from '$lib/components/Button.svelte'
/** @type {import('./$types').PageData} */ /** @type {import('./$types').PageData} */
export let data; export let data;
</script> </script>
{#each data.postJson.data as post} <PostList data={data} />
<Post
success={post.success}
username={post.username}
content={post.content}
upvotes={post.upvotes}
downvotes={post.downvotes}
id={post.id}
></Post>
{/each}
<p>
<Button clickFunc={() => { window.location.search = 'page=' + ((data.id)-1) }}>Previous page</Button>
<Button clickFunc={() => { window.location.search = 'page=' + ((data.id)+1) }}>Next page</Button>
</p>

View file

@ -7,10 +7,8 @@ export async function load({ fetch, params, url }) {
await new Promise(resolve => setTimeout(resolve, 100)); await new Promise(resolve => setTimeout(resolve, 100));
const res = await fetch(`/api/postGet?id=${id}`); const res = await fetch(`/api/postBulk?id=${id}`);
const postJson = (await res.json()); const postJson = (await res.json());
console.log(postJson); return {postJson};
return postJson;
} }

View file

@ -1,15 +1,8 @@
<script> <script>
import Post from '$lib/components/Post.svelte'; import PostList from '$lib/components/PostList.svelte';
/** @type {import('./$types').PageData} */ /** @type {import('./$types').PageData} */
export let data; export let data;
</script> </script>
<Post
success={data.data.success} <PostList data={data} />
username={data.data.username}
content={data.data.content}
upvotes={data.data.upvotes}
downvotes={data.data.downvotes}
id={data.data.id}
isAuthor={data.isAuthor}
></Post>

View file

@ -16,5 +16,5 @@ export async function load({ fetch, params, url }) {
const resUser = await fetch(`/api/userGet?user=${user}`); const resUser = await fetch(`/api/userGet?user=${user}`);
const postJsonUser = (await resUser.json()) || {}; const postJsonUser = (await resUser.json()) || {};
return { postJson, id, postJsonUser }; return { postJson, id, postJsonUser, user };
} }

View file

@ -1,6 +1,7 @@
<script> <script>
import Post from '$lib/components/Post.svelte'; import Button from '$lib/components/Button.svelte'
import Area from '$lib/components/Area.svelte'; import Area from '$lib/components/Area.svelte';
import PostList from '$lib/components/PostList.svelte';
/** @type {import('./$types').PageData} */ /** @type {import('./$types').PageData} */
export let data; export let data;
@ -33,33 +34,18 @@
{:else} {:else}
<Area> <Area>
<span slot="header"> <span slot="header">
<b> <a href='/users/{data.user}'>
Error {data.user}
</b> </a>
</span> </span>
<span slot="main"> <span slot="main">
</span> </span>
<span slot="footer"> <span slot="footer">
This user does not exist. This user does not have any statistics available.
</span> </span>
</Area> </Area>
{/if} {/if}
<h2>Posts</h2> <h2>Posts</h2>
{#each data.postJson as data} <PostList data={data} />
<Post
success={data.data.success}
username={data.data.username}
content={data.data.content}
upvotes={data.data.upvotes}
downvotes={data.data.downvotes}
id={data.data.id}
isAuthor={data.isAuthor}
></Post>
{/each}
<p>
<a data-sveltekit-reload href='?page={data.id+1}'>Next page</a>
</p>
<p></p>