diff --git a/.gitignore b/.gitignore index 42e5a50..302c996 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ node_modules vite.config.js.timestamp-* vite.config.ts.timestamp-* /db +/db-old \ No newline at end of file diff --git a/src/lib/components/Area.svelte b/src/lib/components/Area.svelte index 6a857fb..825f7b3 100644 --- a/src/lib/components/Area.svelte +++ b/src/lib/components/Area.svelte @@ -29,7 +29,6 @@ } #header { - border-bottom: var(--dark-2) solid 2px; width: calc(100% - 30px); } diff --git a/src/lib/components/Form.svelte b/src/lib/components/Form.svelte new file mode 100644 index 0000000..3f3241a --- /dev/null +++ b/src/lib/components/Form.svelte @@ -0,0 +1,28 @@ + + + + + {name} + + + +
+ +
+
+

+ {#if form?.success} +

{form?.success}

+ {/if} + By using the Sanifae service, you agree to the Terms of Service. +

+ \ No newline at end of file diff --git a/src/lib/components/Post.svelte b/src/lib/components/Post.svelte index 11069e0..03418a4 100644 --- a/src/lib/components/Post.svelte +++ b/src/lib/components/Post.svelte @@ -70,6 +70,7 @@ width: 50px; height: 50px; margin-right: 10px; + border-radius: 100%; } .date { @@ -94,7 +95,7 @@ {:else} - +
{username} diff --git a/src/lib/db/db.js b/src/lib/db/db.js index 6aae3b7..7526691 100644 --- a/src/lib/db/db.js +++ b/src/lib/db/db.js @@ -1,4 +1,5 @@ import { backend } from './handlers.js'; +import { mkdir, access } from 'node:fs/promises'; const AUTH_ACTIONS = [ 'postCreate', @@ -9,24 +10,79 @@ const AUTH_ACTIONS = [ 'follow' ]; +const FILE_DIRS = [ + '/db', + '/db/files/upload', + '/db/files/pfp' +] + import sqlite3 from 'sqlite3' import { open } from 'sqlite' var db; +async function newDir(dir) { + await access(newDir) + .then(() => {}) + .catch(async () => await mkdir(dir, { recursive: true })); +} + +async function initFolders() { + for (var i = 0; i < FILE_DIRS.length; i++) { + await newDir( `${process.cwd()}/${FILE_DIRS[i]}`); + } +} + async function initDb() { + await initFolders(); + db = await open({ filename: `${process.cwd()}/db/main.db`, driver: sqlite3.Database }); - await db.run('CREATE TABLE IF NOT EXISTS auth (username CHAR(64), password CHAR(1024))'); - await db.run('CREATE TABLE IF NOT EXISTS token (username CHAR(64), token CHAR(1024))'); - await db.run('CREATE TABLE IF NOT EXISTS post (username CHAR(64), id CHAR(64), content CHAR(10240), upvotes INTEGER, downvotes INTEGER, rating REAL, reply CHAR(64), time INTEGER)'); - await db.run('CREATE TABLE IF NOT EXISTS vote (id CHAR(64), username CHAR(64), type INTEGER)'); - await db.run('CREATE TABLE IF NOT EXISTS user (username CHAR(64), followers INTEGER, following INTEGER, upvotes INTEGER, downvotes INTEGER, reputation REAL)'); - await db.run('CREATE TABLE IF NOT EXISTS bio (username CHAR(64), content CHAR(10240), roles INTEGER)'); - await db.run('CREATE TABLE IF NOT EXISTS follow (username CHAR(64), following CHAR(64))'); + await db.run('CREATE TABLE IF NOT EXISTS auth ( \ + username CHAR(64), \ + password CHAR(1024) \ + )'); + + await db.run('CREATE TABLE IF NOT EXISTS token ( \ + username CHAR(64), \ + token CHAR(1024) \ + )'); + + await db.run('CREATE TABLE IF NOT EXISTS post ( \ + username CHAR(64), \ + id CHAR(64), \ + content CHAR(10240), \ + upvotes INTEGER, \ + downvotes INTEGER, \ + rating REAL, \ + reply CHAR(64), \ + time INTEGER \ + )'); + + await db.run('CREATE TABLE IF NOT EXISTS vote ( \ + id CHAR(64), \ + username CHAR(64), \ + type INTEGER \ + )'); + + await db.run('CREATE TABLE IF NOT EXISTS user ( \ + username CHAR(64), \ + followers INTEGER, \ + following INTEGER, \ + upvotes INTEGER, \ + downvotes INTEGER, \ + reputation REAL, \ + roles INTEGER, \ + pinned CHAR(64) \ + )'); + + await db.run('CREATE TABLE IF NOT EXISTS follow (\ + username CHAR(64), \ + following CHAR(64) \ + )'); } let backendProxy = async ({route, backendParams}) => { diff --git a/src/lib/db/handlers.js b/src/lib/db/handlers.js index e398550..5217a89 100644 --- a/src/lib/db/handlers.js +++ b/src/lib/db/handlers.js @@ -84,9 +84,9 @@ let fileCreate = (type) => { if (validExtensions.indexOf(extensionSafe) == -1) return { success: 'Illegal file extension. Permitted file extensions are: ' + validExtensions.join(', ') }; - let fileName = (type == 'post') ? `post-${imgHash}.${extensionSafe}` : `pfp-${user}.png` + let fileName = (type == 'post') ? `upload/${imgHash}.${extensionSafe}` : `pfp/${user}.png` - writeFile(`${process.cwd()}/db/${fileName}`,imgData,{encoding: 'base64'}); + writeFile(`${process.cwd()}/db/files/${fileName}`,imgData,{encoding: 'base64'}); return { success: 'Successfully uploaded file.', 'href': `/img/${imgHash}.${extensionSafe}`}; } @@ -98,7 +98,7 @@ backend.fileCreate = fileCreate('post'); backend.pfp = fileCreate('pfp'); backend.userRoles = async ({user},{db}) => { - var rolesLocal = await db.all('SELECT roles from bio WHERE username = ?', [ + var rolesLocal = await db.all('SELECT roles from user WHERE username = ?', [ user ] ); @@ -135,7 +135,7 @@ backend.register = async ({user, pass, pass2},{db}) => { passHash ]) - await updateUser({user: user}); + await updateUser({user: user}, {db}); return { success: 'Successfully created account.', location: '/'}; } @@ -236,21 +236,9 @@ backend.userGet = async ({user},{db}) => { if (!followers) followers = []; - return {data: posts[0], following, followers}; -} + posts[0].rolesArr = await backend.userRoles({user},{db}); -backend.userBio = async ({user},{db}) => { - var posts = await db.all('SELECT * from bio WHERE username = ?', [ - user - ]) - - if (!posts || posts.length < 1) { - return {'success': 'Bio does not exist.'} - } - - posts[0].rolesArr = (await userRoles({user})) || []; - - return {data: posts[0]}; + return {data: posts[0], following, followers }; } backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => { @@ -264,11 +252,14 @@ backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => sort = sort.replaceAll('%d',Math.floor(new Date() * 1000)); + let pageParams = [ + page*ROW_COUNT, + ROW_COUNT + ] if (type == 'all') { posts = await db.all('SELECT * from post ORDER BY '+sort+' DESC LIMIT ?, ?', [ - page*ROW_COUNT, - ROW_COUNT + ...pageParams ]) } else if (type == 'post') { posts = await db.all('SELECT * from post WHERE id = ?', [ @@ -279,21 +270,18 @@ backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => posts.push(...(await db.all('SELECT * from post WHERE reply = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [ id, - page*ROW_COUNT, - ROW_COUNT + ...pageParams ]))) } else if (type == 'user') { posts = await db.all('SELECT * from post WHERE username = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [ user, - page*ROW_COUNT, - ROW_COUNT + ...pageParams ]) } else if (type == 'follow') { posts = await db.all('SELECT * from post WHERE username IN (SELECT following from follow WHERE username = ?) ORDER BY '+sort+' DESC LIMIT ?, ?', [ userAuth, - page*ROW_COUNT, - ROW_COUNT + ...pageParams ]) } @@ -346,7 +334,7 @@ backend.vote = async ({id, vote}, {user, db}) => { if (!user[0]) return {success: 'fail' }; - await updateUser({user: user[0].username}); + await updateUser({user: user[0].username}, {db}); return {data: {up,down}}; } diff --git a/src/lib/util.js b/src/lib/util.js index 929dadd..249c136 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -87,7 +87,7 @@ let formatPost = function(post) { extension = safeName(extension); - splitPost = {'type': EXTENSION_MAP[extension] || 'none', 'url': `/img/${matchCleaned}`}; + splitPost = {'type': EXTENSION_MAP[extension] || 'none', 'url': `/img/file/${matchCleaned}`}; return splitPost; } diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 9c31f94..7e86b09 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -34,7 +34,10 @@ :global(input, textarea) { border: 0; border-radius: 0.2rem; - box-shadow: 0px 2px 2.5px 0px var(--dark-2); + box-shadow: 0px 0px 2px 2px var(--dark-2); + + font-size: 1rem; + padding: 0.5rem; } diff --git a/src/routes/account/login/+page.svelte b/src/routes/account/login/+page.svelte index 44712e3..912fe94 100644 --- a/src/routes/account/login/+page.svelte +++ b/src/routes/account/login/+page.svelte @@ -1,34 +1,15 @@ - - - Log in - - - -

Login

-
-

- Username: -

-

- Password: -

-

- -

-
-
-

- {#if form?.success} -

{form?.success}

- {/if} +
+

+

- \ No newline at end of file +

+ +

+

+ +

+
\ No newline at end of file diff --git a/src/routes/account/register/+page.svelte b/src/routes/account/register/+page.svelte index dfdce60..af03f2a 100644 --- a/src/routes/account/register/+page.svelte +++ b/src/routes/account/register/+page.svelte @@ -1,38 +1,18 @@ - - - Register - - - -

Register

-
-

- Username: -

-

- Password: -

-

- Confirm Password: -

-

- -

-
-
-

- {#if form?.success} -

{form?.success}

- {/if} - By using the Sanifae service, you agree to the
Terms of Service. +
+

+

- \ No newline at end of file +

+ +

+

+ +

+

+ +

+
\ No newline at end of file diff --git a/src/routes/img/[img]/+server.js b/src/routes/img/[dir]/[img]/+server.js similarity index 64% rename from src/routes/img/[img]/+server.js rename to src/routes/img/[dir]/[img]/+server.js index f315280..d5619ef 100644 --- a/src/routes/img/[img]/+server.js +++ b/src/routes/img/[dir]/[img]/+server.js @@ -1,14 +1,23 @@ -import { backend, backendProxy } from '../../../lib/db/db.js'; +import { backend, backendProxy } from '../../../../lib/db/db.js'; import { readFile, writeFile } from 'node:fs/promises'; +const FILE_DIRS = [ + 'upload', + 'pfp' +] + /** @type {import('./$types').RequestHandler} */ export async function GET({ url, cookies, params }) { var imgName = params['img']; imgName = imgName.replace(/(\s+)/g, '\\$1'); - var res = await readFile(`${process.cwd()}/db/post-${imgName}`); + var dir = params['dir']; + + if (FILE_DIRS.indexOf(dir) == -1) dir = FILE_DIRS[0]; + + var res = await readFile(`${process.cwd()}/db/files/${dir}/${imgName}`); var response = new Response(res); var extension = imgName.split('.').pop(); diff --git a/src/routes/pfp/[img]/+server.js b/src/routes/pfp/[img]/+server.js deleted file mode 100644 index d442b67..0000000 --- a/src/routes/pfp/[img]/+server.js +++ /dev/null @@ -1,24 +0,0 @@ -import { VALID_EXTENSIONS } from '../../../lib/db/db.js'; - -import { readFile } from 'node:fs/promises'; - -/** @type {import('./$types').RequestHandler} */ -export async function GET({ url, cookies, params }) { - var imgName = params['img']; - - imgName = imgName.replace(/(\s+)/g, '\\$1'); - - var res; - - var res = await readFile(`${process.cwd()}/db/pfp-${imgName}`); - - var response = new Response(res); - var extension = imgName.split('.').pop(); - - if (extension == 'svg') { - response = new Response(res, {'headers': { - 'Content-Type': 'image/png' - }}); - } - return response; -} diff --git a/src/routes/users/[user]/+page.svelte b/src/routes/users/[user]/+page.svelte index ab7901c..dfd6b90 100644 --- a/src/routes/users/[user]/+page.svelte +++ b/src/routes/users/[user]/+page.svelte @@ -10,7 +10,6 @@ let uploadForm = {}; let userData = data.postJsonUser.data; - let userBio = data.postJsonUserBio.data; let following = data.postJsonUser.following; let followers = data.postJsonUser.followers; @@ -37,67 +36,106 @@ } .pfp { - width: 50px; - height: 50px; - margin-right: 10px; + width: 100px; + height: 100px; + border-radius: 100%; + } + + .pfp-small { + width: 45px; + height: 45px; + border-radius: 100%; } #header { display: flex; + justify-content: space-between; + width: 100%; + } + + .sections { + display: grid; + grid-template-columns: 1fr 1fr; + } + + .sections div { + text-align: right; + } + + .sections div:nth-child(1) { + text-align: left; + } + + .profile { align-items: center; + flex-direction: column; + display: flex; } {#if userData} - - - {userData.username} - + +
+ +
-
-

- Reputation: {userData.reputation} +

+ + {userData.reputation} Reputation + + + {userData.upvotes} Upvotes + + + {userData.downvotes} Downvotes +

-

- Upvotes: {userData.upvotes} -

-

- Downvotes: {userData.downvotes} -

-

Roles

-

- {#if userBio && userBio.rolesArr} - {#each userBio.rolesArr as role} - {role} + + {#if userData.rolesArr} +

+ {#each userData.rolesArr as role} + {role} {/each} - {/if} -

+

+ {/if} -

Following

- {#each following as user} - - - - {/each} +
+
+

{following.length} followers

+ {#each following as user} + + + + {/each} +
+ +
+

{followers.length} following

+ {#each followers as user} + + + + {/each} +
+
-

Followers

- {#each followers as user} - - - - {/each} {#if data.resAcc.data == userData.username}

Set PFP

{/if}
- + {:else}