{#each line as elem}
- {#if elem && elem.type == 'img'}
- {#if line.filter(x => x.type == 'img').length < 2}
-
- {:else}
-
+
+ {#if elem && elem.type == 'img'}
+ {#if line.filter(x => x.type == 'img').length < 2}
+
+ {:else}
+
+ {/if}
+ {:else if elem.type == 'video'}
+ {#if line.filter(x => x.type == 'video').length < 2}
+
+ {:else}
+
+ {/if}
+ {:else if elem.type == 'link'}
+ {elem.display}
+ {:else if elem.type == 'text'}
+ {elem.content}
{/if}
- {:else if elem.type == 'video'}
- {#if line.filter(x => x.type == 'video').length < 2}
-
- {:else}
-
- {/if}
- {:else if elem.type == 'link'}
- {elem.display + ' '}
- {:else if !elem.type}
- {elem + ' '}
- {/if}
+
{/each}
- - - + {#if !noRatings} + + + + {/if}
{#if data && data.postJson && data.postJson.data} diff --git a/src/lib/db/db.js b/src/lib/db/db.js index 2e46a0f..bf57f07 100644 --- a/src/lib/db/db.js +++ b/src/lib/db/db.js @@ -83,6 +83,13 @@ async function initDb() { username CHAR(64), \ following CHAR(64) \ )'); + + await db.run('CREATE TABLE IF NOT EXISTS messages (\ + username CHAR(64), \ + content CHAR(10240), \ + time INTEGER, \ + read INTEGER \ + )'); } let backendProxy = async ({route, backendParams}) => { @@ -99,7 +106,7 @@ let backendProxy = async ({route, backendParams}) => { console.log(user); if ((!user || user == '') && AUTH_ACTIONS.indexOf(route) != -1) return {'success': 'Not authorized.' }; -3 + let isAdmin = false; if (user && user != '') isAdmin = ((await backend.userRoles({user}, {db})) || []).indexOf('Admin') != -1; diff --git a/src/lib/db/handlers.js b/src/lib/db/handlers.js index 5217a89..5c8d74c 100644 --- a/src/lib/db/handlers.js +++ b/src/lib/db/handlers.js @@ -202,9 +202,23 @@ backend.postCreate = async ({content}, {user,db}) => { backend.postDelete = async ({id}, {user, admin, db}) => { if (admin) { + let postUser = await db.all('SELECT * from post where id = ?',[ + id + ]) || {}; + + postUser = postUser[0].username; + await db.run('DELETE FROM post WHERE id = ?', [ id ]) + + await db.run('INSERT INTO messages (username, content, time,read) VALUES (?, ?, ?, ?)', [ + postUser, + `#${id} was deleted by an admin for rule violations.`, + Math.floor(new Date() * 1000), + 0 + ]); + } else { await db.run('DELETE FROM post WHERE username = ? AND id = ?', [ user, @@ -248,7 +262,7 @@ backend.postBulk = async ({page, id, user, cookies, sort, type}, {admin, db}) => sort = (LEGAL_SORTS[sort]) || 'rating'; - if (sort + '' != sort) sort = 'rating'; + if (sort + '' !== sort) sort = 'rating'; sort = sort.replaceAll('%d',Math.floor(new Date() * 1000)); @@ -297,9 +311,9 @@ backend.vote = async ({id, vote}, {user, db}) => { var isCreator = (await db.all('SELECT * from post WHERE id = ?', [ id - ]))[0].username == user; + ]))[0].username; - if (isCreator) + if (isCreator == user) return {success: 'fail' }; await db.run('DELETE FROM vote WHERE username = ? AND id = ?', [ @@ -327,6 +341,13 @@ backend.vote = async ({id, vote}, {user, db}) => { id ]); + await db.run('INSERT INTO messages (username, content, time,read) VALUES (?, ?, ?, ?)', [ + isCreator, + `@${user} ${vote == 'up' ? 'upvoted' : 'downvoted'} #${id}`, + Math.floor(new Date() * 1000), + 0 + ]); + var user = await db.all('SELECT * from post WHERE id = ?', [ id ]) || []; @@ -353,12 +374,20 @@ backend.token = async ({cookies}, {db}) => { } backend.follow = async ({target}, {user, db}) => { + var userExists = ((await db.all('SELECT * FROM user WHERE username = ?',[ + target + ])) || []).length; + + if (userExists < 1) return; + var isFollowing = await db.all('SELECT * FROM follow WHERE username = ? AND following = ?',[ user, target ]); - if (isFollowing && isFollowing.length > 0) { + let unfollowed = (isFollowing && isFollowing.length > 0); + + if (unfollowed) { await db.run('DELETE FROM follow WHERE username = ? AND following = ?',[ user, target @@ -378,9 +407,31 @@ backend.follow = async ({target}, {user, db}) => { target ]); + await db.run('INSERT INTO messages (username, content, time,read) VALUES (?, ?, ?, ?)', [ + target, + `@${user} ${unfollowed ? 'is now following' : 'unfollowed'} you`, + Math.floor(new Date() * 1000), + 0 + ]); + return {'success': 'User followed/unfollowed.', 'data': {following, followers}}; }; +backend.messages = async ({isRead}, {user, db}) => { + var msg = await db.all('SELECT * FROM messages WHERE username = ? ORDER BY time DESC', [ + user + ]) || []; + + if (isRead) { + await db.run('UPDATE messages SET read = 1 WHERE username = ?', [ + user + ]); + } + + let read = msg.filter(x => !x.read).length; + + return {'data': {msg, read}}; +}; export { diff --git a/src/lib/util.js b/src/lib/util.js index 249c136..efd709b 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -7,6 +7,12 @@ const EXTENSION_MAP = { 'mp4': 'video' } +const formats = [ + 'italic', + 'bold', + 'bolditalic' +]; + let checkLength = function(string, field, lowerBound, upperBound) { if (string.length < lowerBound) { if (string.length == 0) { @@ -66,11 +72,49 @@ let safeName = function (text) { return text.replaceAll(/[^A-Za-z0-9\-\_]/g, ''); } -let formatPost = function(post) { +let formatPostText = function(post) { + post = post.map(x => (x === x + '') ? x.split(/(\*)/).filter(x => x != '') : x).flat(); + + let inc = false; + let formatType = -1; + let wasInc = false; + let dir = 1; + + let newArr = []; + + for (var i = 0; i < post.length; i++) { + inc = (post[i] == '*'); + + if (inc) { + formatType += dir; + } else { + if (wasInc) dir = !dir + 0; + if (dir) formatType = -1; + + let formatTypeStr = formats[formatType] || 'default'; + + if (post[i] === post[i] + '') { + newArr.push({'type': 'text', 'format': formatTypeStr, 'content': post[i]}) + } else { + let content = post[i]; + content.format = formatTypeStr; + newArr.push(content); + } + } + + wasInc = inc; + } + + console.log(newArr); + + return newArr; +} + +let formatPost = function(post, ignoreImg) { post = post.split('\n'); post = post.map(subPost => { - return subPost.split(' '); + return subPost.split(/( )/); }); post = post.map(line => { @@ -78,7 +122,7 @@ let formatPost = function(post) { var splitPost = subPost.split('||'); - if (splitPost.length > 1) { + if (splitPost.length > 1 && !ignoreImg) { var cap1 = splitPost[0]; if (cap1 == 'img') { @@ -94,7 +138,7 @@ let formatPost = function(post) { } else if (subPost[0] == '@' || subPost[0] == '#') { var subPostIn = safeName(subPost.substring(0)); - var type = (subPost[0] == '@') ? 'user' : 'post'; + var type = (subPost[0] == '@') ? 'users' : 'post'; splitPost = {'type': 'link', 'display': subPost, 'subtype': type, 'url': `/${type}/${subPostIn}`}; @@ -103,7 +147,7 @@ let formatPost = function(post) { var url; var extension = subPost.split('.').pop().toLowerCase(); - if (EXTENSION_MAP[extension]) { + if (EXTENSION_MAP[extension] && !ignoreImg) { url = `/embed?url=${encodeURIComponent(subPost)}`; splitPost = [ {'type': 'link', 'display': subPost, 'url': url}, @@ -119,7 +163,7 @@ let formatPost = function(post) { return subPost; }) - return line.flat(); + return formatPostText(line.flat()); }); return post; diff --git a/src/routes/+layout.js b/src/routes/+layout.js index a0c8ba5..80a8ef8 100644 --- a/src/routes/+layout.js +++ b/src/routes/+layout.js @@ -4,5 +4,8 @@ export async function load({ fetch }) { const username = await res.json(); - return { username: username.data }; + const res2 = await fetch(`/api/messages`); + const read = (await res2.json()).data.read; + + return { username: username.data, read }; } \ No newline at end of file diff --git a/src/routes/messages/+page.js b/src/routes/messages/+page.js new file mode 100644 index 0000000..ee99af0 --- /dev/null +++ b/src/routes/messages/+page.js @@ -0,0 +1,12 @@ +import { redirect } from '@sveltejs/kit'; + +/** @type {import('./$types').PageLoad} */ +export async function load({ fetch, url }) { + var page = url.searchParams.get('page') * 1; + + await new Promise(resolve => setTimeout(resolve, 100)); + + const res = await fetch(`/api/messages?isRead=1`); + const postJson = (await res.json()).data.msg; + return {postJson, id: page}; +} \ No newline at end of file diff --git a/src/routes/messages/+page.svelte b/src/routes/messages/+page.svelte new file mode 100644 index 0000000..4f2d6cc --- /dev/null +++ b/src/routes/messages/+page.svelte @@ -0,0 +1,44 @@ + + + + + + + Messages + + + + {#if data && data.postJson} + {#each data.postJson as post} ++ Any messages and notifications sent to your profile. +
+ + ++ {#if data.id > 0} + { window.location.search = setLocation(window.location,'page',((data.id)-1)) }} href='#'>← Page {(data.id)-1} + {/if} + Page {(data.id)} + { window.location.search = setLocation(window.location,'page',((data.id)+1)) }} href='#'>Page {(data.id)+1} → +
\ No newline at end of file diff --git a/src/routes/new_post/+page.svelte b/src/routes/new_post/+page.svelte index d4b7077..2919b30 100644 --- a/src/routes/new_post/+page.svelte +++ b/src/routes/new_post/+page.svelte @@ -82,7 +82,7 @@Create a post for the world to see.
- img||filename.blah embeds a user-uploaded file in this site + img||file.name embeds a user-uploaded file in this site
@user mentions a user @@ -90,5 +90,11 @@
#post replies to a post by ID
++ *x* produces italic text +
++ **x** produces bolded text +
\ No newline at end of file diff --git a/static/read.svg b/static/read.svg new file mode 100644 index 0000000..b5c2bbe --- /dev/null +++ b/static/read.svg @@ -0,0 +1,66 @@ + + + + diff --git a/static/unread.svg b/static/unread.svg new file mode 100644 index 0000000..d758d91 --- /dev/null +++ b/static/unread.svg @@ -0,0 +1,66 @@ + + + +