no mass rerendering html plus logging fix

This commit is contained in:
Tyler Murphy 2023-01-29 00:35:06 -05:00
parent 9cbeee4b67
commit 7805c730e8
10 changed files with 142 additions and 89 deletions

View file

@ -2,7 +2,7 @@ body {
background-color: #f0f2f5;
}
#posts {
#posts, #create {
display: flex;
flex-direction: column;
align-items: center;
@ -172,7 +172,7 @@ body {
flex-direction: row;
}
#comments input {
.comments input {
all: unset;
padding: 10px;
border-radius: 10px;

View file

@ -20,6 +20,5 @@ function header(home, people) {
</div>
<div class="spacer"></div>
`
add(html, 'header')
append(html)
}

View file

@ -41,19 +41,19 @@ function parsePost(post) {
</span>
<div class="fullline nb"></div>
<div class="postbuttons">
<span onclick="like(this)">
<i class="icons like ${post.likes.includes(data.user.user_id) ? 'blue' : ''}"></i>
<span class="bold ${post.likes.includes(data.user.user_id) ? 'blue' : ''}">Like</span>
<span class="likeclicky" onclick="like(this)">
<i class="liketoggle icons like ${post.likes.includes(data.user.user_id) ? 'blue' : ''}"></i>
<span class="liketoggle bold ${post.likes.includes(data.user.user_id) ? 'blue' : ''}">Like</span>
</span>
<span onclick="this.parentElement.parentElement.getElementsByClassName('newcomment')[0].focus()">
<i class="icons comm"></i>
<span class="bold">Comment</span>
</span>
</div>
<div id="comments">
<div class="comments">
<div class="fullline" style="margin-top: 0"></div>
${post.comments.map(parseComment).join('')}
<div class="comment">
${post.comments.map(parseComment).join('')}
<div class="comment commentsubmit">
<a class="pfp" href="profile">
</a>
@ -64,7 +64,6 @@ function parsePost(post) {
</div>
</div>
`
return html
}
@ -78,7 +77,8 @@ function getPost(post_id) {
}
async function like(span) {
const id = parseInt(span.parentElement.parentElement.getAttribute('postid'))
const container = span.parentElement.parentElement;
const id = parseInt(container.getAttribute('postid'))
const post = data.posts[getPost(id)]
const index = post.likes.indexOf(data.user.user_id)
const current = index !== -1
@ -89,26 +89,40 @@ async function like(span) {
} else {
post.likes.push(data.user.user_id)
}
render()
const buttons = container
.getElementsByClassName("postbuttons")[0]
.getElementsByClassName("likeclicky")[0]
.getElementsByClassName("liketoggle")
if (current) {
buttons[0].classList.remove("blue")
buttons[1].classList.remove("blue")
} else {
buttons[0].classList.add("blue")
buttons[1].classList.add("blue")
}
}
async function comment(event) {
event.preventDefault();
const text = event.target.elements.text.value.trim();
if (text.length < 1) return;
const id = parseInt(event.target.parentElement.parentElement.parentElement.getAttribute('postid'))
var index = getPost(id);
const container = event.target.parentElement.parentElement.parentElement;
const post_id = parseInt(container.getAttribute('postid'))
var index = getPost(post_id);
if (index === -1) return;
const response = await postcomment(id, text)
const response = await postcomment(post_id, text)
if (response.status != 200) return;
event.target.elements.text.value = '';
data.posts[index].comments.push([data.user.user_id, text])
render()
let new_comment = [data.user.user_id, text]
data.posts[index].comments.push(new_comment)
let comments = container.getElementsByClassName("comments")[0]
prepend(parseComment(new_comment), comments, comments.getElementsByClassName("commentsubmit")[0])
}
async function post() {
const text = document.getElementById("text").value.trim()
const error = document.getElementsByClassName('error')[0]
const posts_block = document.getElementById("posts")
if (text.length < 1) return;
const response = await createpost(text);
if (response.status != 201) {
@ -116,20 +130,32 @@ async function post() {
return;
}
error.innerHTML = '';
data.posts.unshift({
let post = {
post_id: response.json.post_id,
user_id: data.user.user_id,
date: Date.now(),
content: text,
likes: [],
comments: []
})
render()
}
data.posts.unshift(post)
let html = parsePost(post)
prepend(html, posts_block)
document.getElementById('popup').classList.add('hidden')
}
async function loadMore() {
const posts = await load()
data.posts.push(... posts)
const posts_block = document.getElementById("posts")
for (p of posts) {
append(parsePost(p), posts_block)
}
}
function render() {
const html = `
<div id="posts">
<div id="create">
<div class="create">
<a class="pfp" href="profile">
@ -140,11 +166,13 @@ function render() {
</p>
</button>
</div>
</div>
<div id="posts">
${data.posts.map(p => parsePost(p)).join('')}
</div>
`
add(html, 'posts')
append(html)
const popup = `
<div id="popup" class="hidden">
@ -168,19 +196,15 @@ function render() {
</div>
`
add(popup, 'popup')
append(popup)
const load = `
<div id="load">
<a class="bold gtext" onclick="load()">Load more posts</a>
<a class="bold gtext" onclick="loadMore()">Load more posts</a>
</div>
`
if (page !== -1) {
add(load, 'load')
} else {
remove('load')
}
append(load)
}
var page = 0
@ -194,10 +218,11 @@ async function load() {
const posts = (await loadpostspage(page)).json
if (posts.length === 0) {
page = -1
remove('load')
return []
} else {
page++
}
data.posts.push(... posts)
const batch = []
for (const post of posts) {
for(const comment of post.comments) {
@ -209,17 +234,18 @@ async function load() {
if (batch.includes(post.user_id)) continue
batch.push(post.user_id)
}
const users = (await loadusers(batch)).json
const users = batch.length == 0 ? [] : (await loadusers(batch)).json
for (const user of users) {
data.users[user.user_id] = user
}
render()
return posts
}
async function init() {
header(true, false)
data.user = (await loadself()).json
data.users[data.user.user_id] = data.user
load()
const posts = await load()
data.posts.push(... posts)
render()
}

View file

@ -1,15 +1,26 @@
var range;
function prepend(html, container, before) {
if (container === undefined) {
container = document.body
}
if (before === undefined) {
before = container.firstChild
}
console.log(html, container, before)
var range = document.createRange()
range.setStart(container, 0);
container.insertBefore(
range.createContextualFragment(html),
before
)
}
function add(html, id) {
const old = document.getElementById(id)
if (old !== null) {
old.remove()
function append(html, container) {
if (container === undefined) {
container = document.body
}
if (range === undefined) {
var range = document.createRange()
range.setStart(document.body, 0)
}
document.body.appendChild(
var range = document.createRange()
range.setStart(container, 0);
container.appendChild(
range.createContextualFragment(html)
)
}

View file

@ -23,19 +23,15 @@ function render() {
</div>
`
add(html, 'users')
append(html)
const load = `
<div id="load">
<a class="bold gtext" onclick="load()">Load more users</a>
<a class="bold gtext" onclick="loadMore()">Load more users</a>
</div>
`
if (page !== -1) {
add(load, 'load')
} else {
remove('load')
}
append(load)
}
var page = 0
@ -43,16 +39,30 @@ var data = {
users: []
}
async function loadMore() {
let users = await load()
const users_block = document.getElementById("users")
for (user of users) {
append(parseUser(user), users_block)
}
}
async function load() {
const users = (await loaduserspage(page)).json
if (users.length === 0) {
page = -1
remove('load')
} else {
page++
}
return users
}
async function init() {
let users = await load()
data.users.push(... users)
render()
}
header(false, true)
load()
init()

View file

@ -1,3 +1,21 @@
function swap(value) {
let postsb = document.getElementById("profilepostbutton");
let aboutb = document.getElementById("profileaboutbutton");
let posts = document.getElementById("posts");
let about = document.getElementById("about");
if (value) {
postsb.classList.add("selected")
aboutb.classList.remove("selected")
about.classList.add("hidden")
posts.classList.remove("hidden")
} else {
postsb.classList.remove("selected")
aboutb.classList.add("selected")
about.classList.remove("hidden")
posts.classList.add("hidden")
}
}
function render() {
const html = `
<div id="top">
@ -17,10 +35,10 @@ function render() {
</div>
<div class="fullline" style="width: 80em; margin-bottom: 0;"></div>
<div class="profilebuttons">
<button class="${posts ? 'selected' : ''}" onclick="posts = true; render()">
<button id="profilepostbutton" class="${posts ? 'selected' : ''}" onclick="swap(true)">
Posts
</button>
<button class="${posts ? '' : 'selected'}" onclick="posts = false; render()">
<button id="profileaboutbutton" class="${posts ? '' : 'selected'}" onclick="swap(false)">
About
</button>
<div style="flex: 20"></div>
@ -29,7 +47,7 @@ function render() {
</div>
`
add(html, 'top')
append(html)
const postsh = `
<div id="posts" class="${posts ? '' : 'hidden'}">
@ -37,7 +55,7 @@ function render() {
</div>
`
add(postsh, 'posts')
append(postsh)
const about = `
<div id="about" class="post ${posts ? 'hidden' : ''}">
@ -52,7 +70,7 @@ function render() {
</div>
`
add(about, 'about')
append(about)
}
async function logout_button() {
@ -72,21 +90,22 @@ async function load() {
params[key] = value
}
let self = (await loadself()).json;
data.user = (await loadself()).json;
data.users[data.user.user_id] = data.user
let id;
if (params.id !== undefined && !isNaN(params.id)) {
id = parseInt(params.id);
} else {
id = self.user_id
id = data.user.user_id
}
isself = id === self.user_id
isself = id === data.user.user_id
const posts = (await loadusersposts(id)).json
data.posts.push(... posts)
const batch = [id]
const batch = []
for (const post of posts) {
for(const comment of post.comments) {
if (data.users[comment[0]] !== undefined) continue
@ -97,11 +116,10 @@ async function load() {
if (batch.includes(post.user_id)) continue
batch.push(post.user_id)
}
const users = (await loadusers(batch)).json
const users = batch.length == 0 ? [] : (await loadusers(batch)).json
for (const user of users) {
data.users[user.user_id] = user
}
data.user = data.users[id]
render()
}

View file

@ -6,10 +6,10 @@ use axum::{
use crate::{
console,
types::{extract::AuthorizedUser, http::ResponseCode},
types::{extract::{AuthorizedUser, Log}, http::ResponseCode},
};
async fn root(user: Option<AuthorizedUser>) -> Response {
async fn root(user: Option<AuthorizedUser>, _: Log) -> Response {
if user.is_some() {
Redirect::to("/home").into_response()
} else {
@ -17,7 +17,7 @@ async fn root(user: Option<AuthorizedUser>) -> Response {
}
}
async fn login(user: Option<AuthorizedUser>) -> Response {
async fn login(user: Option<AuthorizedUser>, _: Log) -> Response {
if user.is_some() {
Redirect::to("/home").into_response()
} else {
@ -25,7 +25,7 @@ async fn login(user: Option<AuthorizedUser>) -> Response {
}
}
async fn home(user: Option<AuthorizedUser>) -> Response {
async fn home(user: Option<AuthorizedUser>, _: Log) -> Response {
if user.is_none() {
Redirect::to("/login").into_response()
} else {
@ -33,7 +33,7 @@ async fn home(user: Option<AuthorizedUser>) -> Response {
}
}
async fn people(user: Option<AuthorizedUser>) -> Response {
async fn people(user: Option<AuthorizedUser>, _: Log) -> Response {
if user.is_none() {
Redirect::to("/login").into_response()
} else {
@ -41,7 +41,7 @@ async fn people(user: Option<AuthorizedUser>) -> Response {
}
}
async fn profile(user: Option<AuthorizedUser>) -> Response {
async fn profile(user: Option<AuthorizedUser>, _: Log) -> Response {
if user.is_none() {
Redirect::to("/login").into_response()
} else {
@ -53,7 +53,7 @@ async fn console() -> Response {
console::generate().await
}
async fn wordpress() -> Response {
async fn wordpress(_: Log) -> Response {
ResponseCode::ImATeapot.text("Hello i am a teapot owo")
}

View file

@ -45,10 +45,7 @@ lazy_static! {
}
pub async fn log(ip: IpAddr, method: Method, uri: Uri, path: Option<String>, body: Option<String>) {
if uri.to_string().starts_with("/console") {
return;
}
let path = path.unwrap_or_default();
let body = body.unwrap_or_default();

View file

@ -1,11 +1,11 @@
use axum::{
body::HttpBody,
extract::ConnectInfo,
http::{Request, StatusCode},
middleware::{self, Next},
response::Response,
Extension, RequestExt, Router,
};
use axum_client_ip::ClientIp;
use std::{net::SocketAddr, process::exit};
use tower_cookies::CookieManagerLayer;
use tracing::{error, info, metadata::LevelFilter};
@ -40,18 +40,11 @@ async fn log<B>(mut req: Request<B>, next: Next<B>) -> Response
where
B: Send + Sync + 'static + HttpBody,
{
let Ok(ConnectInfo(info)) = req.extract_parts::<ConnectInfo<SocketAddr>>().await else {
let Ok(ClientIp(ip)) = req.extract_parts::<ClientIp>().await else {
return next.run(req).await
};
console::log(
info.ip(),
req.method().clone(),
req.uri().clone(),
None,
None,
)
.await;
console::log(ip, req.method().clone(), req.uri().clone(), None, None).await;
next.run(req).await
}
@ -80,9 +73,9 @@ async fn main() {
let app = Router::new()
.fallback(not_found)
.nest("/", pages::router())
.layer(middleware::from_fn(log))
.layer(middleware::from_fn(serve))
.nest("/", pages::router())
.nest(
"/api/auth",
auth::router().layer(Extension(RouterURI("/api/auth"))),

View file

@ -85,10 +85,9 @@ where
type Rejection = Response;
async fn from_request(req: Request<B>, state: &S) -> Result<Self> {
let body = match parse_body(req, state).await {
Ok(body) => body,
Err(err) => return Err(err)
Err(err) => return Err(err),
};
let Ok(value) = serde_json::from_str::<T>(&body) else {
@ -128,7 +127,7 @@ where
B: HttpBody + Sync + Send + 'static,
B::Data: Send,
B::Error: Into<BoxError>,
S: Send + Sync
S: Send + Sync,
{
let Ok(ClientIp(ip)) = req.extract_parts::<ClientIp>().await else {
tracing::error!("Failed to read client ip");