Skip to content

Commit

Permalink
add: compose post modal
Browse files Browse the repository at this point in the history
add: maximum setting value length
  • Loading branch information
trisuaso committed Oct 27, 2024
1 parent b23749d commit b98ee3c
Show file tree
Hide file tree
Showing 15 changed files with 310 additions and 259 deletions.
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions crates/authbeam/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,10 @@ impl Database {
}
}

if !metadata.check() {
return Err(AuthError::TooLong);
}

// update user
let query: &str = if (self.base.db.r#type == "sqlite") | (self.base.db.r#type == "mysql") {
"UPDATE \"xprofiles\" SET \"metadata\" = ? WHERE \"username\" = ?"
Expand Down
26 changes: 26 additions & 0 deletions crates/authbeam/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,30 @@ impl ProfileMetadata {

self.kv.get(key).unwrap() == "true"
}

/// Check `kv` lengths
///
/// # Returns
/// * `true`: ok
/// * `false`: invalid
pub fn check(&self) -> bool {
for field in &self.kv {
if field.0 == "sparkler:custom_css" {
// custom_css gets an extra long value
if field.1.len() > 64 * 128 {
return false;
}

continue;
}

if field.1.len() > 64 * 64 {
return false;
}
}

true
}
}

impl Default for ProfileMetadata {
Expand Down Expand Up @@ -387,6 +411,7 @@ pub enum AuthError {
NotAllowed,
ValueError,
NotFound,
TooLong,
Other,
}

Expand All @@ -398,6 +423,7 @@ impl AuthError {
NotAllowed => String::from("You are not allowed to access this resource."),
ValueError => String::from("One of the field values given is invalid."),
NotFound => String::from("No asset with this ID could be found."),
TooLong => String::from("Given data is too long."),
_ => String::from("An unspecified error has occured"),
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/rainbeam/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "rainbeam"
version = "1.11.5"
version = "1.12.0"
edition = "2021"
authors = ["trisuaso", "swmff"]
description = "Ask, share, socialize!"
Expand Down
16 changes: 12 additions & 4 deletions crates/rainbeam/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -319,7 +319,7 @@ impl Database {
None
},
followers: if options.followers | options.all {
match self.auth.get_following(user.clone()).await {
match self.auth.get_followers(user.clone()).await {
Ok(r) => Some(r),
Err(_) => return Err(DatabaseError::Other),
}
Expand Down Expand Up @@ -2322,7 +2322,11 @@ impl Database {
/// # Arguments
/// * `props` - [`ResponseCreate`]
/// * `author` - the ID of the user creating the response
pub async fn create_response(&self, props: ResponseCreate, author: String) -> Result<()> {
pub async fn create_response(
&self,
props: ResponseCreate,
author: String,
) -> Result<QuestionResponse> {
// make sure the question exists
let mut question = if props.question != "0" {
// get question from database
Expand Down Expand Up @@ -2557,7 +2561,7 @@ impl Database {
.incr(format!("rbeam.app.response_count:{}", response.author.id))
.await;

return Ok(());
return Ok(response);
} else {
// change recipient so it doesn't show up in inbox
let query: String =
Expand Down Expand Up @@ -2602,7 +2606,7 @@ impl Database {
}

// return
Ok(())
Ok(response)
}
Err(_) => Err(DatabaseError::Other),
}
Expand Down Expand Up @@ -4718,6 +4722,10 @@ impl Database {
}
}

if !metadata.check() {
return Err(DatabaseError::ContentTooLong);
}

// update circle
let query: String = if (self.base.db.r#type == "sqlite") | (self.base.db.r#type == "mysql")
{
Expand Down
24 changes: 24 additions & 0 deletions crates/rainbeam/src/model.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,30 @@ impl CircleMetadata {

self.kv.get(key).unwrap() == "true"
}

/// Check `kv` lengths
///
/// # Returns
/// * `true`: ok
/// * `false`: invalid
pub fn check(&self) -> bool {
for field in &self.kv {
if field.0 == "sparkler:custom_css" {
// custom_css gets an extra long value
if field.1.len() > 64 * 128 {
return false;
}

continue;
}

if field.1.len() > 64 * 64 {
return false;
}
}

true
}
}

/// An export of a user's entire history
Expand Down
44 changes: 11 additions & 33 deletions crates/rainbeam/src/routing/pages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ use axum_extra::extract::CookieJar;

use ammonia::Builder;
use serde::{Deserialize, Serialize};
use authbeam::model::{
Notification, Permission, Profile, ProfileMetadata, RelationshipStatus, UserFollow,
};
use authbeam::model::{Notification, Permission, Profile, ProfileMetadata, RelationshipStatus};

use crate::config::Config;
use crate::database::Database;
Expand Down Expand Up @@ -201,7 +199,7 @@ struct PartialTimelineTemplate {
is_helper: bool,
}

/// GET /_app/timeline.html
/// GET /_app/timelines/timeline.html
pub async fn partial_timeline_request(
jar: CookieJar,
State(database): State<Database>,
Expand Down Expand Up @@ -761,7 +759,7 @@ struct PartialPostsTemplate {
is_helper: bool,
}

/// GET /_app/posts.html
/// GET /_app/timelines/posts.html
pub async fn partial_posts_request(
jar: CookieJar,
State(database): State<Database>,
Expand Down Expand Up @@ -1471,16 +1469,13 @@ pub async fn public_global_timeline_request(
}

#[derive(Template)]
#[template(path = "compose.html")]
#[template(path = "partials/components/compose.html")]
struct ComposeTemplate {
config: Config,
profile: Option<Profile>,
unread: usize,
notifs: usize,
following: Vec<(UserFollow, Profile, Profile)>,
}

/// GET /inbox/compose
/// GET /_app/components/compose.html
pub async fn compose_request(
jar: CookieJar,
State(database): State<Database>,
Expand All @@ -1497,30 +1492,10 @@ pub async fn compose_request(
None => return Html(DatabaseError::NotAllowed.to_html(database)),
};

let unread = match database
.get_questions_by_recipient(auth_user.id.to_owned())
.await
{
Ok(unread) => unread.len(),
Err(_) => 0,
};

let notifs = database
.auth
.get_notification_count_by_recipient(auth_user.id.to_owned())
.await;

Html(
ComposeTemplate {
config: database.server_options,
following: database
.auth
.get_following(auth_user.id.clone())
.await
.unwrap_or(Vec::new()),
profile: Some(auth_user),
unread,
notifs,
}
.render()
.unwrap(),
Expand Down Expand Up @@ -1810,7 +1785,6 @@ pub async fn routes(database: Database) -> Router {
)
.route("/inbox/global", get(public_global_timeline_request))
.route("/inbox/global/following", get(global_timeline_request))
.route("/inbox/compose", get(compose_request))
.route("/inbox/notifications", get(notifications_request))
.route("/inbox/reports", get(reports_request)) // staff
.route("/inbox/audit", get(audit_log_request)) // staff
Expand Down Expand Up @@ -1893,8 +1867,12 @@ pub async fn routes(database: Database) -> Router {
.route("/+i/:ip", get(api::profiles::expand_ip_request))
.route("/+p/:id", get(api::pages::expand_request))
// partials
.route("/_app/timeline.html", get(partial_timeline_request))
.route("/_app/posts.html", get(partial_posts_request))
.route("/_app/components/compose.html", get(compose_request))
.route(
"/_app/timelines/timeline.html",
get(partial_timeline_request),
)
.route("/_app/timelines/posts.html", get(partial_posts_request))
// ...
.with_state(database)
}
54 changes: 54 additions & 0 deletions crates/rainbeam/static/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,10 @@
$.clean_date_codes();
$.link_filter();
$["hook.alt"]();

if (globalThis._app_base.ns_store.$questions) {
trigger("questions:carp");
}
})
.catch(() => {
// done scrolling, no more pages (http error)
Expand Down Expand Up @@ -534,6 +538,56 @@
},
);

app.define("hook.autosize", function (_) {
for (const textarea of Array.from(
document.querySelectorAll("textarea[autosize]"),
)) {
if (textarea.getAttribute("data-link")) {
// already linked
continue;
}

const id = window.crypto.randomUUID();

textarea.style.overflow = "hidden";
textarea.setAttribute("data-link", id);

const pseudo = document.createElement("div");
pseudo.setAttribute("aria-hidden", "true");
pseudo.classList.add("hook_autosize_pseudo");
pseudo.id = id;

pseudo.style.visibility = "hidden";
pseudo.style.position = "absolute";
pseudo.style.pointerEvents = "none";
pseudo.style.top = "0";

const computed = window.getComputedStyle(textarea); // we need to match styles on pseudo
const copy_styles = [
"width",
"padding-top",
"padding-left",
"padding-right",
"padding-bottom",
];

for (const style of copy_styles) {
pseudo.style[style] = computed.getPropertyValue(style);
}

function resize() {
const box = pseudo.getBoundingClientRect();

pseudo.innerText = textarea.value; // pseudo will auto size naturally
textarea.style.height = `${box.height + 10}px`;
}

textarea.addEventListener("input", resize);
textarea.addEventListener("keydown", resize);
document.body.appendChild(pseudo);
}
});

// adomonition
app.define("shout", function (_, type, content) {
if (document.getElementById("admonition")) {
Expand Down
39 changes: 39 additions & 0 deletions crates/rainbeam/static/js/classes/PartialComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
class PartialComponent extends HTMLElement {
static observedAttributes = ["src", "uses"];

constructor() {
const self = super();
self.style.display = "contents";
}

attributeChangedCallback(name, _, value) {
switch (name) {
case "src":
fetch(value)
.then((res) => res.text())
.then((res) => {
this.innerHTML = res;
})
.catch((err) => {
this.innerHTML = err;
});

break;

case "uses":
setTimeout(() => {
for (const hook of value.split(",")) {
trigger(hook);
}
}, 500);

break;

default:
return;
}
}
}

customElements.define("include-partial", PartialComponent);
define("PartialComponent", PartialComponent);
Loading

0 comments on commit b98ee3c

Please sign in to comment.