A lot of stuff
This commit is contained in:
parent
98b2c285f4
commit
a1c9b30cf6
9 changed files with 439 additions and 421 deletions
|
@ -20,7 +20,8 @@
|
|||
#header {
|
||||
font-weight: bold;
|
||||
|
||||
font-size: 2rem;
|
||||
font-size: 1rem;
|
||||
overflow-x: auto;
|
||||
|
||||
width: 100%;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
#logo {
|
||||
|
||||
width: calc(100vw + 50px);
|
||||
width: calc(100vw - 10px);
|
||||
|
||||
background: var(--dark-1);
|
||||
|
||||
|
|
|
@ -55,8 +55,11 @@
|
|||
font-weight: bold;
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
.vote-area {
|
||||
margin-right: 30px;
|
||||
|
||||
|
||||
#header-area {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -70,7 +73,6 @@
|
|||
}
|
||||
|
||||
.date {
|
||||
margin-left: 1rem;
|
||||
font-size: 0.8rem;
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
|
@ -93,12 +95,14 @@
|
|||
<Area>
|
||||
<span slot="header" id='header'>
|
||||
<img class='pfp' src='/pfp/{username}.png'/>
|
||||
<a href='/users/{username}'>
|
||||
<div class='header-area'>
|
||||
<div><a href='/users/{username}'>
|
||||
{username}
|
||||
</a>
|
||||
<span class='date'>
|
||||
</a></div>
|
||||
<div class='date'>
|
||||
{date}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<span slot="main">
|
||||
<PostBody content={content} />
|
||||
|
|
420
src/lib/db/db.js
420
src/lib/db/db.js
|
@ -1,4 +1,4 @@
|
|||
const ROW_COUNT = 5;
|
||||
import { backend } from './handlers.js';
|
||||
|
||||
const AUTH_ACTIONS = [
|
||||
'postCreate',
|
||||
|
@ -9,32 +9,11 @@ const AUTH_ACTIONS = [
|
|||
'follow'
|
||||
];
|
||||
|
||||
const LEGAL_SORTS = {
|
||||
'time': 'time',
|
||||
'rating': 'rating',
|
||||
'hot': `rating / (%d - time + 24000)`
|
||||
}
|
||||
|
||||
const roles = [
|
||||
'Owner',
|
||||
'Admin',
|
||||
'Veteran'
|
||||
]
|
||||
|
||||
const FILE_SIZE_LIMIT = 1024*1024*16;
|
||||
|
||||
const VALID_EXTENSIONS = ['png','jpg','jpeg','gif','svg', 'mp4'];
|
||||
|
||||
var ridArray = {};
|
||||
|
||||
import sqlite3 from 'sqlite3'
|
||||
import { open } from 'sqlite'
|
||||
import { hash, compare } from 'bcrypt'
|
||||
import { randomBytes, createHash } from 'node:crypto';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { calcVote, checkLength, checkRegex, safePath, formatPost } from '../util.js';
|
||||
|
||||
var db;
|
||||
|
||||
async function initDb() {
|
||||
db = await open({
|
||||
filename: `${process.cwd()}/db/main.db`,
|
||||
|
@ -53,392 +32,25 @@ async function initDb() {
|
|||
let backendProxy = async ({route, backendParams}) => {
|
||||
if (!db) await initDb();
|
||||
|
||||
var user = ((await backend.token({cookies: backendParams.cookies})) || {}).data;
|
||||
let extraParams = {};
|
||||
|
||||
extraParams['db'] = db;
|
||||
|
||||
let user = (await backend.token({cookies: backendParams.cookies},extraParams)) || {};
|
||||
|
||||
user = user.data;
|
||||
|
||||
if ((!user || user == '') && AUTH_ACTIONS.indexOf(route) != -1) return {'success': 'Not authorized.' };
|
||||
3
|
||||
var isAdmin = false;
|
||||
if (user && user != '') isAdmin = ((await userRoles({user})) || []).indexOf('Admin') != -1;
|
||||
let isAdmin = false;
|
||||
if (user && user != '') isAdmin = ((await backend.userRoles({}, {user, db})) || []).indexOf('Admin') != -1;
|
||||
|
||||
backendParams['admin'] = isAdmin;
|
||||
extraParams['admin'] = isAdmin;
|
||||
extraParams['user'] = user;
|
||||
|
||||
if (AUTH_ACTIONS.indexOf(route) != -1) backendParams['user'] = user;
|
||||
|
||||
return backend[route](backendParams);
|
||||
return backend[route](backendParams, extraParams) || {};
|
||||
}
|
||||
|
||||
var backend = {};
|
||||
|
||||
let updateUser = async ({user}) => {
|
||||
let allPosts = await db.all('SELECT * from post WHERE username = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
let upvotes = 0;
|
||||
let downvotes = 0;
|
||||
allPosts.forEach(post => {
|
||||
upvotes += post.upvotes || 0;
|
||||
downvotes += post.downvotes || 0;
|
||||
});
|
||||
|
||||
await db.run('DELETE FROM user WHERE username = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
await db.run('INSERT INTO user (username,followers,following,upvotes,downvotes,reputation) VALUES (?,?,?,?,?,?)', [
|
||||
user,
|
||||
0,
|
||||
0,
|
||||
upvotes,
|
||||
downvotes,
|
||||
calcVote(upvotes,downvotes,'user')
|
||||
]);
|
||||
}
|
||||
|
||||
backend.register = async ({user, pass, pass2}) => {
|
||||
var lengthCheck = false;
|
||||
|
||||
lengthCheck =
|
||||
checkLength(pass,'Password',4,1024) ||
|
||||
checkLength(user,'Username',1,64) ||
|
||||
checkRegex(user,'Username',/[^A-Za-z0-9\-\_]/g);
|
||||
|
||||
if (lengthCheck) return lengthCheck;
|
||||
|
||||
if (pass != pass2) return {'success': 'Passwords don\'t match.'};
|
||||
|
||||
var existingAccounts = await db.all('SELECT username FROM auth WHERE username = ?',[
|
||||
user
|
||||
]);
|
||||
|
||||
if (existingAccounts && existingAccounts.length > 0)
|
||||
return { success: 'Account already exists.' };
|
||||
|
||||
var passHash = await hash(pass,10);
|
||||
|
||||
await db.run('INSERT INTO auth (username, password) VALUES (?, ?)', [
|
||||
user,
|
||||
passHash
|
||||
])
|
||||
|
||||
await updateUser({user: user});
|
||||
|
||||
return { success: 'Successfully created account.', location: '/'};
|
||||
}
|
||||
|
||||
backend.login = async ({user, pass, cookies}) => {
|
||||
var existingAccounts = await db.all('SELECT username, password FROM auth WHERE username = ?',[
|
||||
user
|
||||
]);
|
||||
|
||||
if (!existingAccounts || existingAccounts.length < 1)
|
||||
return { success: 'Account does not exist.' };
|
||||
|
||||
var passHash = await compare(pass,existingAccounts[0].password);
|
||||
|
||||
if (!passHash)
|
||||
return { success: 'Incorrect password.' };
|
||||
|
||||
var token = randomBytes(256).toString('hex');
|
||||
|
||||
await db.run('INSERT INTO token (username, token) VALUES (?, ?)', [
|
||||
user,
|
||||
token
|
||||
])
|
||||
|
||||
if (token) {
|
||||
cookies.set('token',token, {
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
path: '/'
|
||||
});
|
||||
};
|
||||
|
||||
return { success: 'Successfully logged into account.', data: token, location: '/'};
|
||||
}
|
||||
|
||||
backend.postCreate = async ({content, user}) => {
|
||||
if (!content) return {'success': 'No post provided.'}
|
||||
|
||||
var lengthCheck = checkLength(content,'Post content',1,10240);
|
||||
|
||||
if (lengthCheck)
|
||||
return lengthCheck;
|
||||
|
||||
if (!content) return {'success': 'There is no post!' };
|
||||
|
||||
var id = randomBytes(10).toString('hex');
|
||||
|
||||
var postFlatten = formatPost(content).flat();
|
||||
var reply = postFlatten[postFlatten.findIndex(x => x.subtype == 'post')];
|
||||
|
||||
if (reply)
|
||||
reply = reply.url.split('/').pop();
|
||||
|
||||
await db.run('INSERT INTO post (username, id, content, rating, reply, time) VALUES (?, ?, ?, ?, ?, ?)', [
|
||||
user,
|
||||
id,
|
||||
content,
|
||||
calcVote(0,0),
|
||||
reply || '',
|
||||
Math.floor(new Date() * 1000)
|
||||
])
|
||||
|
||||
return {'success': 'Your post has been broadcasted!', 'href': `/post/${id}` };
|
||||
}
|
||||
|
||||
backend.postDelete = async ({id, user, admin}) => {
|
||||
if (admin) {
|
||||
await db.run('DELETE FROM post WHERE id = ?', [
|
||||
id
|
||||
])
|
||||
} else {
|
||||
await db.run('DELETE FROM post WHERE username = ? AND id = ?', [
|
||||
user,
|
||||
id
|
||||
])
|
||||
}
|
||||
|
||||
return {'success': 'Your post has been deleted!', 'href': `/post/${id}` };
|
||||
}
|
||||
|
||||
let userRoles = async ({user}) => {
|
||||
var rolesLocal = await db.all('SELECT roles from bio WHERE username = ?', [
|
||||
user
|
||||
] );
|
||||
|
||||
if (rolesLocal.length == 0) rolesLocal = [{}];
|
||||
|
||||
let rolesLocalList = rolesLocal[0].roles;
|
||||
|
||||
return roles.filter((elem,i) => ((rolesLocalList % (1<<(i+1))) > ((1<<i) - 1)) );
|
||||
};
|
||||
|
||||
backend.userGet = async ({user}) => {
|
||||
var posts = await db.all('SELECT * from user WHERE username = ?', [
|
||||
user
|
||||
])
|
||||
|
||||
if (!posts || posts.length < 1) {
|
||||
return {'success': 'User does not exist.'}
|
||||
}
|
||||
|
||||
var following = await db.all('SELECT * from follow WHERE username = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
var followers = await db.all('SELECT * from follow WHERE following = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
if (!following) following = [];
|
||||
|
||||
if (!followers) followers = [];
|
||||
|
||||
return {data: posts[0], following, followers};
|
||||
}
|
||||
|
||||
backend.userBio = async ({user}) => {
|
||||
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]};
|
||||
}
|
||||
|
||||
backend.postBulk = async ({page, id, user, cookies, sort, type, admin}) => {
|
||||
var posts;
|
||||
|
||||
var userAuth = (await backend.token({cookies})).data || '';
|
||||
|
||||
sort = (LEGAL_SORTS[sort]) || 'rating';
|
||||
|
||||
if (sort + '' != sort) sort = 'rating';
|
||||
|
||||
sort = sort.replaceAll('%d',Math.floor(new Date() * 1000));
|
||||
|
||||
|
||||
if (type == 'all') {
|
||||
posts = await db.all('SELECT * from post ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||
page*ROW_COUNT,
|
||||
ROW_COUNT
|
||||
])
|
||||
} else if (type == 'post') {
|
||||
posts = await db.all('SELECT * from post WHERE id = ?', [
|
||||
id
|
||||
]);
|
||||
|
||||
if (posts.length == 0) posts.push({});
|
||||
|
||||
posts.push(...(await db.all('SELECT * from post WHERE reply = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||
id,
|
||||
page*ROW_COUNT,
|
||||
ROW_COUNT
|
||||
])))
|
||||
|
||||
} else if (type == 'user') {
|
||||
posts = await db.all('SELECT * from post WHERE username = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||
user,
|
||||
page*ROW_COUNT,
|
||||
ROW_COUNT
|
||||
])
|
||||
} 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
|
||||
])
|
||||
}
|
||||
|
||||
posts = posts.map(post => {
|
||||
return {...post, isAuthor: userAuth == post.username || admin};
|
||||
})
|
||||
|
||||
return {data: posts};
|
||||
}
|
||||
|
||||
backend.vote = async ({id, vote, user}) => {
|
||||
if (!id || (vote != 'down' && vote != 'up')) return {success: 'fail' };
|
||||
|
||||
var isCreator = (await db.all('SELECT * from post WHERE id = ?', [
|
||||
id
|
||||
]))[0].username == user;
|
||||
|
||||
if (isCreator)
|
||||
return {success: 'fail' };
|
||||
|
||||
await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [
|
||||
user,
|
||||
id
|
||||
]);
|
||||
|
||||
await db.run('INSERT INTO vote (id, username, type) VALUES (?,?,?)', [
|
||||
id,
|
||||
user,
|
||||
vote == 'up' ? 1 : 2
|
||||
]);
|
||||
|
||||
var votes = await db.all('SELECT type from vote WHERE id = ?', [
|
||||
id
|
||||
]) || [];
|
||||
|
||||
var up = votes.filter(x => x.type == 1).length;
|
||||
var down = votes.filter(x => x.type == 2).length;
|
||||
|
||||
await db.run('UPDATE post SET upvotes = ?, downvotes = ?, rating = ? WHERE id = ?', [
|
||||
up,
|
||||
down,
|
||||
calcVote(up,down),
|
||||
id
|
||||
]);
|
||||
|
||||
var user = await db.all('SELECT * from post WHERE id = ?', [
|
||||
id
|
||||
]) || [];
|
||||
|
||||
if (!user[0])
|
||||
return {success: 'fail' };
|
||||
|
||||
await updateUser({user: user[0].username});
|
||||
|
||||
return {data: {up,down}};
|
||||
}
|
||||
|
||||
backend.token = async ({cookies}) => {
|
||||
var tokenIn = cookies.get('token');
|
||||
|
||||
var existingAccounts = await db.all('SELECT username from token WHERE token = ?',[
|
||||
tokenIn
|
||||
]);
|
||||
|
||||
if (!existingAccounts || existingAccounts.length < 1)
|
||||
return false;
|
||||
|
||||
return {data: existingAccounts[0].username};
|
||||
}
|
||||
|
||||
backend.follow = async ({target, user}) => {
|
||||
var isFollowing = await db.all('SELECT * FROM follow WHERE username = ? AND following = ?',[
|
||||
user,
|
||||
target
|
||||
]);
|
||||
|
||||
if (isFollowing && isFollowing.length > 0) {
|
||||
await db.run('DELETE FROM follow WHERE username = ? AND following = ?',[
|
||||
user,
|
||||
target
|
||||
]);
|
||||
} else {
|
||||
await db.run('INSERT INTO follow (username, following) VALUES (?, ?)',[
|
||||
user,
|
||||
target
|
||||
]);
|
||||
}
|
||||
|
||||
var following = await db.all('SELECT * from follow WHERE username = ?', [
|
||||
target
|
||||
]);
|
||||
|
||||
var followers = await db.all('SELECT * from follow WHERE following = ?', [
|
||||
target
|
||||
]);
|
||||
|
||||
return {'success': 'User followed/unfollowed.', 'data': {following, followers}};
|
||||
};
|
||||
|
||||
let fileCreate = (type) => {
|
||||
return async ({img, extension,id, last, user }) => {
|
||||
let validExtensions = VALID_EXTENSIONS;
|
||||
|
||||
if (type == 'pfp') validExtensions = ['png'];
|
||||
|
||||
if (ridArray[id] !== '' && !(ridArray[id])) {
|
||||
ridArray[id] = img;
|
||||
} else {
|
||||
ridArray[id] += img;
|
||||
}
|
||||
|
||||
const imgData = ridArray[id];
|
||||
|
||||
if (last != 'true') {
|
||||
return {'success': 'Image still proccessing...'}
|
||||
} else {
|
||||
ridArray[id] = false;
|
||||
}
|
||||
|
||||
const imgHash = createHash('md5').update(imgData).digest('hex');
|
||||
|
||||
if (!imgHash)
|
||||
return {'success': 'Image not provided.'}
|
||||
|
||||
if (imgHash.length > FILE_SIZE_LIMIT)
|
||||
return {'success': 'Image too big.'}
|
||||
|
||||
const extensionSafe = safePath(extension);
|
||||
|
||||
if (validExtensions.indexOf(extensionSafe) == -1)
|
||||
return { success: 'Illegal file extension. Permitted file extensions are: ' + validExtensions.join(', ') };
|
||||
|
||||
if (type == 'post') {
|
||||
writeFile(`${process.cwd()}/db/post-${imgHash}.${extensionSafe}`,imgData,{encoding: 'base64'});
|
||||
} else {
|
||||
writeFile(`${process.cwd()}/db/pfp-${user}.png`,imgData,{encoding: 'base64'});
|
||||
}
|
||||
|
||||
return { success: 'Successfully uploaded file.', 'href': `/img/${imgHash}.${extensionSafe}`};
|
||||
}
|
||||
}
|
||||
backend.fileCreate = fileCreate('post');
|
||||
backend.pfp = fileCreate('pfp');
|
||||
|
||||
|
||||
export {
|
||||
backendProxy,
|
||||
backend,
|
||||
VALID_EXTENSIONS
|
||||
}
|
||||
backendProxy
|
||||
};
|
401
src/lib/db/handlers.js
Normal file
401
src/lib/db/handlers.js
Normal file
|
@ -0,0 +1,401 @@
|
|||
const ROW_COUNT = 5;
|
||||
|
||||
const LEGAL_SORTS = {
|
||||
'time': 'time',
|
||||
'rating': 'rating',
|
||||
'hot': `rating / (%d - time + 24000)`
|
||||
}
|
||||
|
||||
const roles = [
|
||||
'Owner',
|
||||
'Admin',
|
||||
'Veteran'
|
||||
]
|
||||
|
||||
const FILE_SIZE_LIMIT = 1024*1024*16;
|
||||
|
||||
const VALID_EXTENSIONS = ['png','jpg','jpeg','gif','svg', 'mp4'];
|
||||
|
||||
|
||||
import { hash, compare } from 'bcrypt'
|
||||
import { randomBytes, createHash } from 'node:crypto';
|
||||
import { writeFile } from 'node:fs/promises';
|
||||
import { calcVote, checkLength, checkRegex, safePath, formatPost } from '../util.js';
|
||||
|
||||
var ridArray = {};
|
||||
|
||||
let updateUser = async ({user},{db}) => {
|
||||
let allPosts = await db.all('SELECT * from post WHERE username = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
let upvotes = 0;
|
||||
let downvotes = 0;
|
||||
|
||||
allPosts.forEach(post => {
|
||||
upvotes += post.upvotes || 0;
|
||||
downvotes += post.downvotes || 0;
|
||||
});
|
||||
|
||||
await db.run('DELETE FROM user WHERE username = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
await db.run('INSERT INTO user (username,followers,following,upvotes,downvotes,reputation) VALUES (?,?,?,?,?,?)', [
|
||||
user,
|
||||
0,
|
||||
0,
|
||||
upvotes,
|
||||
downvotes,
|
||||
calcVote(upvotes,downvotes,'user')
|
||||
]);
|
||||
}
|
||||
|
||||
let fileCreate = (type) => {
|
||||
return async ({img, extension,id, last}, {user}) => {
|
||||
let validExtensions = VALID_EXTENSIONS;
|
||||
|
||||
if (type == 'pfp') validExtensions = ['png'];
|
||||
|
||||
if (ridArray[id] !== '' && !(ridArray[id])) {
|
||||
ridArray[id] = img;
|
||||
} else {
|
||||
ridArray[id] += img;
|
||||
}
|
||||
|
||||
const imgData = ridArray[id];
|
||||
|
||||
if (last != 'true') {
|
||||
return {'success': 'Image still proccessing...'}
|
||||
} else {
|
||||
ridArray[id] = false;
|
||||
}
|
||||
|
||||
const imgHash = createHash('md5').update(imgData).digest('hex');
|
||||
|
||||
if (!imgHash)
|
||||
return {'success': 'Image not provided.'}
|
||||
|
||||
if (imgHash.length > FILE_SIZE_LIMIT)
|
||||
return {'success': 'Image too big.'}
|
||||
|
||||
const extensionSafe = safePath(extension);
|
||||
|
||||
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`
|
||||
|
||||
writeFile(`${process.cwd()}/db/${fileName}`,imgData,{encoding: 'base64'});
|
||||
|
||||
return { success: 'Successfully uploaded file.', 'href': `/img/${imgHash}.${extensionSafe}`};
|
||||
}
|
||||
}
|
||||
|
||||
var backend = {};
|
||||
|
||||
backend.fileCreate = fileCreate('post');
|
||||
backend.pfp = fileCreate('pfp');
|
||||
|
||||
backend.userRoles = async ({user},{db}) => {
|
||||
var rolesLocal = await db.all('SELECT roles from bio WHERE username = ?', [
|
||||
user
|
||||
] );
|
||||
|
||||
if (rolesLocal.length == 0) rolesLocal = [{}];
|
||||
|
||||
let rolesLocalList = rolesLocal[0].roles;
|
||||
|
||||
return roles.filter((elem,i) => ((rolesLocalList % (1<<(i+1))) > ((1<<i) - 1)) );
|
||||
};
|
||||
|
||||
backend.register = async ({user, pass, pass2},{db}) => {
|
||||
var lengthCheck = false;
|
||||
|
||||
lengthCheck =
|
||||
checkLength(pass,'Password',4,1024) ||
|
||||
checkLength(user,'Username',1,64) ||
|
||||
checkRegex(user,'Username',/[^A-Za-z0-9\-\_]/g);
|
||||
|
||||
if (lengthCheck) return lengthCheck;
|
||||
|
||||
if (pass != pass2) return {'success': 'Passwords don\'t match.'};
|
||||
|
||||
var existingAccounts = await db.all('SELECT username FROM auth WHERE username = ?',[
|
||||
user
|
||||
]);
|
||||
|
||||
if (existingAccounts && existingAccounts.length > 0)
|
||||
return { success: 'Account already exists.' };
|
||||
|
||||
var passHash = await hash(pass,10);
|
||||
|
||||
await db.run('INSERT INTO auth (username, password) VALUES (?, ?)', [
|
||||
user,
|
||||
passHash
|
||||
])
|
||||
|
||||
await updateUser({user: user});
|
||||
|
||||
return { success: 'Successfully created account.', location: '/'};
|
||||
}
|
||||
|
||||
backend.login = async ({user, pass, cookies},{db}) => {
|
||||
var existingAccounts = await db.all('SELECT username, password FROM auth WHERE username = ?',[
|
||||
user
|
||||
]);
|
||||
|
||||
if (!existingAccounts || existingAccounts.length < 1)
|
||||
return { success: 'Account does not exist.' };
|
||||
|
||||
var passHash = await compare(pass,existingAccounts[0].password);
|
||||
|
||||
if (!passHash)
|
||||
return { success: 'Incorrect password.' };
|
||||
|
||||
var token = randomBytes(256).toString('hex');
|
||||
|
||||
await db.run('INSERT INTO token (username, token) VALUES (?, ?)', [
|
||||
user,
|
||||
token
|
||||
])
|
||||
|
||||
if (token) {
|
||||
cookies.set('token',token, {
|
||||
maxAge: 60 * 60 * 24 * 7,
|
||||
path: '/'
|
||||
});
|
||||
};
|
||||
|
||||
return { success: 'Successfully logged into account.', data: token, location: '/'};
|
||||
}
|
||||
|
||||
backend.postCreate = async ({content}, {user,db}) => {
|
||||
if (!content) return {'success': 'No post provided.'}
|
||||
|
||||
var lengthCheck = checkLength(content,'Post content',1,10240);
|
||||
|
||||
if (lengthCheck)
|
||||
return lengthCheck;
|
||||
|
||||
if (!content) return {'success': 'There is no post!' };
|
||||
|
||||
var id = randomBytes(10).toString('hex');
|
||||
|
||||
var postFlatten = formatPost(content).flat();
|
||||
var reply = postFlatten[postFlatten.findIndex(x => x.subtype == 'post')];
|
||||
|
||||
if (reply)
|
||||
reply = reply.url.split('/').pop();
|
||||
|
||||
await db.run('INSERT INTO post (username, id, content, rating, reply, time) VALUES (?, ?, ?, ?, ?, ?)', [
|
||||
user,
|
||||
id,
|
||||
content,
|
||||
calcVote(0,0),
|
||||
reply || '',
|
||||
Math.floor(new Date() * 1000)
|
||||
])
|
||||
|
||||
return {'success': 'Your post has been broadcasted!', 'href': `/post/${id}` };
|
||||
}
|
||||
|
||||
backend.postDelete = async ({id}, {user, admin, db}) => {
|
||||
if (admin) {
|
||||
await db.run('DELETE FROM post WHERE id = ?', [
|
||||
id
|
||||
])
|
||||
} else {
|
||||
await db.run('DELETE FROM post WHERE username = ? AND id = ?', [
|
||||
user,
|
||||
id
|
||||
])
|
||||
}
|
||||
|
||||
return {'success': 'Your post has been deleted!', 'href': `/post/${id}` };
|
||||
}
|
||||
|
||||
backend.userGet = async ({user},{db}) => {
|
||||
var posts = await db.all('SELECT * from user WHERE username = ?', [
|
||||
user
|
||||
])
|
||||
|
||||
if (!posts || posts.length < 1) {
|
||||
return {'success': 'User does not exist.'}
|
||||
}
|
||||
|
||||
var following = await db.all('SELECT * from follow WHERE username = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
var followers = await db.all('SELECT * from follow WHERE following = ?', [
|
||||
user
|
||||
]);
|
||||
|
||||
if (!following) following = [];
|
||||
|
||||
if (!followers) followers = [];
|
||||
|
||||
return {data: posts[0], following, followers};
|
||||
}
|
||||
|
||||
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]};
|
||||
}
|
||||
|
||||
backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => {
|
||||
var posts;
|
||||
|
||||
var userAuth = (await backend.token({cookies}, {db})).data || '';
|
||||
|
||||
sort = (LEGAL_SORTS[sort]) || 'rating';
|
||||
|
||||
if (sort + '' != sort) sort = 'rating';
|
||||
|
||||
sort = sort.replaceAll('%d',Math.floor(new Date() * 1000));
|
||||
|
||||
|
||||
if (type == 'all') {
|
||||
posts = await db.all('SELECT * from post ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||
page*ROW_COUNT,
|
||||
ROW_COUNT
|
||||
])
|
||||
} else if (type == 'post') {
|
||||
posts = await db.all('SELECT * from post WHERE id = ?', [
|
||||
id
|
||||
]);
|
||||
|
||||
if (posts.length == 0) posts.push({});
|
||||
|
||||
posts.push(...(await db.all('SELECT * from post WHERE reply = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||
id,
|
||||
page*ROW_COUNT,
|
||||
ROW_COUNT
|
||||
])))
|
||||
|
||||
} else if (type == 'user') {
|
||||
posts = await db.all('SELECT * from post WHERE username = ? ORDER BY '+sort+' DESC LIMIT ?, ?', [
|
||||
user,
|
||||
page*ROW_COUNT,
|
||||
ROW_COUNT
|
||||
])
|
||||
} 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
|
||||
])
|
||||
}
|
||||
|
||||
posts = posts.map(post => {
|
||||
return {...post, isAuthor: userAuth == post.username || admin};
|
||||
})
|
||||
|
||||
return {data: posts};
|
||||
}
|
||||
|
||||
backend.vote = async ({id, vote}, {user, db}) => {
|
||||
if (!id || (vote != 'down' && vote != 'up')) return {success: 'fail' };
|
||||
|
||||
var isCreator = (await db.all('SELECT * from post WHERE id = ?', [
|
||||
id
|
||||
]))[0].username == user;
|
||||
|
||||
if (isCreator)
|
||||
return {success: 'fail' };
|
||||
|
||||
await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [
|
||||
user,
|
||||
id
|
||||
]);
|
||||
|
||||
await db.run('INSERT INTO vote (id, username, type) VALUES (?,?,?)', [
|
||||
id,
|
||||
user,
|
||||
vote == 'up' ? 1 : 2
|
||||
]);
|
||||
|
||||
var votes = await db.all('SELECT type from vote WHERE id = ?', [
|
||||
id
|
||||
]) || [];
|
||||
|
||||
var up = votes.filter(x => x.type == 1).length;
|
||||
var down = votes.filter(x => x.type == 2).length;
|
||||
|
||||
await db.run('UPDATE post SET upvotes = ?, downvotes = ?, rating = ? WHERE id = ?', [
|
||||
up,
|
||||
down,
|
||||
calcVote(up,down),
|
||||
id
|
||||
]);
|
||||
|
||||
var user = await db.all('SELECT * from post WHERE id = ?', [
|
||||
id
|
||||
]) || [];
|
||||
|
||||
if (!user[0])
|
||||
return {success: 'fail' };
|
||||
|
||||
await updateUser({user: user[0].username});
|
||||
|
||||
return {data: {up,down}};
|
||||
}
|
||||
|
||||
backend.token = async ({cookies}, {db}) => {
|
||||
var tokenIn = cookies.get('token');
|
||||
|
||||
var existingAccounts = await db.all('SELECT username from token WHERE token = ?',[
|
||||
tokenIn
|
||||
]);
|
||||
|
||||
if (!existingAccounts || existingAccounts.length < 1)
|
||||
return false;
|
||||
|
||||
return {data: existingAccounts[0].username};
|
||||
}
|
||||
|
||||
backend.follow = async ({target}, {user, db}) => {
|
||||
var isFollowing = await db.all('SELECT * FROM follow WHERE username = ? AND following = ?',[
|
||||
user,
|
||||
target
|
||||
]);
|
||||
|
||||
if (isFollowing && isFollowing.length > 0) {
|
||||
await db.run('DELETE FROM follow WHERE username = ? AND following = ?',[
|
||||
user,
|
||||
target
|
||||
]);
|
||||
} else {
|
||||
await db.run('INSERT INTO follow (username, following) VALUES (?, ?)',[
|
||||
user,
|
||||
target
|
||||
]);
|
||||
}
|
||||
|
||||
var following = await db.all('SELECT * from follow WHERE username = ?', [
|
||||
target
|
||||
]);
|
||||
|
||||
var followers = await db.all('SELECT * from follow WHERE following = ?', [
|
||||
target
|
||||
]);
|
||||
|
||||
return {'success': 'User followed/unfollowed.', 'data': {following, followers}};
|
||||
};
|
||||
|
||||
|
||||
|
||||
export {
|
||||
backend,
|
||||
VALID_EXTENSIONS
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
padding: 25px;
|
||||
padding-top: 0px;
|
||||
|
||||
display: flex;
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
</script>
|
||||
|
||||
<Area handleSubmit=''>
|
||||
<p slot="header">
|
||||
<span slot="header">
|
||||
Log in
|
||||
</p>
|
||||
</span>
|
||||
|
||||
<span slot='main'>
|
||||
<h2>Login</h2>
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
</script>
|
||||
|
||||
<Area handleSubmit=''>
|
||||
<p slot="header">
|
||||
<span slot="header">
|
||||
Register
|
||||
</p>
|
||||
</span>
|
||||
|
||||
<span slot='main'>
|
||||
<h2>Register</h2>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import { backend, backendProxy } from '../../../lib/db/db.js';
|
||||
import { backend } from '../../../lib/db/handlers.js';
|
||||
import { backendProxy } from '../../../lib/db/db.js';
|
||||
|
||||
|
||||
/** @type {import('./$types').RequestHandler} */
|
||||
|
|
Loading…
Reference in a new issue