Skip to content

Commit

Permalink
add(mod): ipbans page
Browse files Browse the repository at this point in the history
add: only load PartialComponents when visible by default
add: finish app themes
chore: remove turbo
  • Loading branch information
trisuaso committed Nov 1, 2024
1 parent 665d9f5 commit 136f60a
Show file tree
Hide file tree
Showing 9 changed files with 351 additions and 58 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.

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.12.5"
version = "1.13.0"
edition = "2021"
authors = ["trisuaso", "swmff"]
description = "Ask, share, socialize!"
Expand Down
63 changes: 62 additions & 1 deletion crates/rainbeam/src/routing/pages/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use axum_extra::extract::CookieJar;

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

use crate::config::Config;
use crate::database::Database;
Expand Down Expand Up @@ -1784,6 +1784,66 @@ pub async fn audit_log_request(
)
}

#[derive(Template)]
#[template(path = "ipbans.html")]
struct IpbansTemplate {
config: Config,
profile: Option<Profile>,
unread: usize,
bans: Vec<IpBan>,
}

/// GET /inbox/audit/ipbans
pub async fn ipbans_request(jar: CookieJar, State(database): State<Database>) -> impl IntoResponse {
let auth_user = match jar.get("__Secure-Token") {
Some(c) => match database
.auth
.get_profile_by_unhashed(c.value_trimmed().to_string())
.await
{
Ok(ua) => ua,
Err(_) => return Html(DatabaseError::NotAllowed.to_html(database)),
},
None => return Html(DatabaseError::NotAllowed.to_html(database)),
};

// check permission
let group = match database.auth.get_group_by_id(auth_user.group).await {
Ok(g) => g,
Err(_) => return Html(DatabaseError::NotFound.to_html(database)),
};

if !group.permissions.contains(&Permission::Helper) {
// we must be a manager to do this
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 bans = match database.auth.get_ipbans(auth_user.clone()).await {
Ok(r) => r,
Err(_) => return Html(DatabaseError::Other.to_html(database)),
};

Html(
IpbansTemplate {
config: database.server_options.clone(),
profile: Some(auth_user),
unread,
bans,
}
.render()
.unwrap(),
)
}

#[derive(Template)]
#[template(path = "report.html")]
struct ReportTemplate {
Expand Down Expand Up @@ -1856,6 +1916,7 @@ pub async fn routes(database: Database) -> Router {
.route("/inbox/notifications", get(notifications_request))
.route("/inbox/reports", get(reports_request)) // staff
.route("/inbox/audit", get(audit_log_request)) // staff
.route("/inbox/audit/ipbans", get(ipbans_request)) // staff
// assets
.route("/question/:id", get(question_request))
.route("/response/:id", get(response_request))
Expand Down
100 changes: 65 additions & 35 deletions crates/rainbeam/static/js/classes/PartialComponent.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
const observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
if (!entry.isIntersecting) {
continue;
}

if (!entry.target.loaded) {
entry.target.fetch_src(entry.target.getAttribute("src"));
}
}
},
{
root: document.body,
rootMargin: "0px",
threshold: 1.0,
},
);

class PartialComponent extends HTMLElement {
static observedAttributes = ["src", "uses"];
loaded;
Expand All @@ -12,6 +31,42 @@ class PartialComponent extends HTMLElement {
'<div class="markdown-alert-warning">Could not display component.</div>';
}

fetch_src(value) {
fetch(value)
.then((res) => res.text())
.then((res) => {
if (res.includes("<title>Uh oh!")) {
// neospring error
this.error();
return;
}

this.innerHTML = `<div style="animation: grow 1 0.25s forwards running">${res}</div>`;

if (globalThis[`lib:${value}`]) {
// load finished
globalThis[`lib:${value}`]();
}

this.loaded = true;
this.setAttribute("loaded", this.loaded);

setTimeout(() => {
if (!this.getAttribute("uses")) {
return;
}

for (const hook of this.getAttribute("uses").split(",")) {
trigger(hook);
}
}, 15);
})
.catch((err) => {
this.error();
console.error(err);
});
}

attributeChangedCallback(name, old, value) {
switch (name) {
case "src":
Expand All @@ -25,41 +80,16 @@ class PartialComponent extends HTMLElement {

this.loaded = false;
this.setAttribute("loaded", this.loaded);
fetch(value)
.then((res) => res.text())
.then((res) => {
if (res.includes("<title>Uh oh!")) {
// neospring error
this.error();
return;
}

this.innerHTML = `<div style="animation: grow 1 0.25s forwards running">${res}</div>`;

if (globalThis[`lib:${value}`]) {
// load finished
globalThis[`lib:${value}`]();
}

this.loaded = true;
this.setAttribute("loaded", this.loaded);

setTimeout(() => {
if (!this.getAttribute("uses")) {
return;
}

for (const hook of this.getAttribute("uses").split(
",",
)) {
trigger(hook);
}
}, 15);
})
.catch((err) => {
this.error();
console.error(err);
});

if (!this.getAttribute("instant")) {
// load when in view
observer.observe(this);
} else {
// load after a second
setTimeout(() => {
this.fetch_src(value);
}, 250);
}

break;

Expand Down
94 changes: 81 additions & 13 deletions crates/rainbeam/static/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -1051,16 +1051,6 @@ dialog::backdrop {
dialog .inner:not(.dropdown *) {
min-height: 100dvh !important;
}

/* toast to snackbar */
.toast {
width: 100% !important;
}

#toast_zone {
top: 0.5rem !important;
bottom: unset;
}
}

@keyframes from_bottom {
Expand Down Expand Up @@ -1704,6 +1694,67 @@ canvas {
}
}

table {
border-collapse: collapse;
max-width: 100%;
min-width: auto;
overflow: auto;
}

table th {
min-width: max-content;
padding: 6px 8px;
text-align: left;
background: transparent;
border: none;
}

table td {
border-left: var(--color-super-lowered);
padding: 10px;
text-overflow: ellipsis;
overflow: hidden;
overflow-wrap: normal;
word-break: normal;
width: max-content;
}

table td:first-child {
border-left: 0;
}

table tr {
background: var(--color-lowered);
border-bottom: solid 1px var(--color-super-lowered);
}

table tr:nth-child(even) {
background: var(--color-raised);
}

table tr:hover {
background: var(--color-super-raised);
}

table thead tr {
background: transparent;
border-bottom: solid 5px var(--color-super-lowered);
}

table tbody tr td {
padding: 6px 8px;
}

table td:focus-within {
box-shadow: none;
}

table p,
table ul,
table ol {
margin-bottom: 0;
}

/* app */
.app,
.app * {
Expand All @@ -1718,6 +1769,7 @@ canvas {
--color-primary-raised: hsl(209, 93%, 54%);
--color-shadow: transparent;
--frosted-glass: blur(100px) brightness(110%);
--radius: 0.2rem;
font-family: "Poppins", "Roboto", "Inter", ui-sans-serif, system-ui,
sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol",
"Noto Color Emoji";
Expand Down Expand Up @@ -1746,7 +1798,8 @@ nav:is(.app *) {
transition: backdrop-filter 0.15s;
}

nav:is(.app *):is([data-scroll="0"] *) {
nav:is(.app *):is([data-scroll="0"] *),
nav:is(.app *):is(html:not([data-scroll]) *) {
backdrop-filter: none;
border: none !important;
}
Expand Down Expand Up @@ -1892,6 +1945,16 @@ nav:is(.app *) a.button {
.pillmenu:is(.app *) * {
border-radius: 0 !important;
}

/* toast to snackbar */
.toast:is(.app *) {
width: 100% !important;
}

#toast_zone:is(.app *) {
top: 0.5rem !important;
bottom: unset;
}
}

.pillmenu.convertible:is(.app *) {
Expand All @@ -1900,7 +1963,7 @@ nav:is(.app *) a.button {
}

.pillmenu:is(.app *) a.active {
color: var(--color-primary);
color: var(--color-primary-raised);
background: var(--color-super-raised);
position: relative;
}
Expand All @@ -1912,10 +1975,15 @@ nav:is(.app *) a.button {
bottom: 0px;
width: 50%;
height: 2.5px;
background: var(--color-primary);
background: currentColor;
border-radius: var(--radius);
}

.notification:is(.app *) {
background: transparent;
color: inherit;
}

@keyframes grow {
from {
transform: scale(0.9);
Expand Down
7 changes: 6 additions & 1 deletion crates/rainbeam/templates/audit.html
Original file line number Diff line number Diff line change
Expand Up @@ -63,13 +63,18 @@
<a href="/inbox/reports">Reports</a>
</div>

<div class="pillmenu convertible">
<a href="/inbox/audit" class="active">Mod Actions</a>
<a href="/inbox/audit/ipbans">IP Bans</a>
</div>

{% if logs.len() == 0 %}
<div class="markdown-alert-important">
<span>No results matching this query yet!</span>
</div>
{% endif %}

<!-- notifications -->
<!-- audit logs -->
<!-- prettier-ignore -->
{% for notif in logs %}
{% let show_mark_as_read = false %}
Expand Down
Loading

0 comments on commit 136f60a

Please sign in to comment.