add: littleweb base

This commit is contained in:
trisua 2025-07-07 14:45:30 -04:00
parent 07a23f505b
commit c4de17058b
20 changed files with 457 additions and 8 deletions

View file

@ -113,9 +113,22 @@ async fn main() {
tera.register_filter("emojis", render_emojis);
let client = Client::new();
let mut app = Router::new();
let app = Router::new()
.merge(routes::routes(&config))
// add correct routes
if var("LITTLEWEB").is_ok() {
app = app.merge(routes::lw_routes());
} else {
app = app
.merge(routes::routes(&config))
.layer(SetResponseHeaderLayer::if_not_present(
HeaderName::from_static("content-security-policy"),
HeaderValue::from_static("default-src 'self' *.spotify.com musicbrainz.org; img-src * data:; media-src *; font-src *; style-src 'unsafe-inline' 'self' *; script-src 'self' 'unsafe-inline' *; object-src 'self' *; upgrade-insecure-requests; connect-src * localhost; frame-src 'self' *.cloudflare.com; frame-ancestors 'self'"),
));
}
// add junk
app = app
.layer(Extension(Arc::new(RwLock::new((database, tera, client)))))
.layer(axum::extract::DefaultBodyLimit::max(
var("BODY_LIMIT")
@ -128,12 +141,9 @@ async fn main() {
.make_span_with(trace::DefaultMakeSpan::new().level(Level::INFO))
.on_response(trace::DefaultOnResponse::new().level(Level::INFO)),
)
.layer(SetResponseHeaderLayer::if_not_present(
HeaderName::from_static("content-security-policy"),
HeaderValue::from_static("default-src 'self' *.spotify.com musicbrainz.org; img-src * data:; media-src *; font-src *; style-src 'unsafe-inline' 'self' *; script-src 'self' 'unsafe-inline' *; object-src 'self' *; upgrade-insecure-requests; connect-src * localhost; frame-src 'self' *.cloudflare.com; frame-ancestors 'self'"),
))
.layer(CatchPanicLayer::new());
// ...
let listener = tokio::net::TcpListener::bind(format!("0.0.0.0:{}", config.port))
.await
.unwrap();

View file

@ -1277,11 +1277,22 @@ ${option.input_element_type === "textarea" ? `${option.value}</textarea>` : ""}
}
if (
text.includes(`!<!-- observer_disconnect_${window.BUILD_CODE} -->`)
text.includes(
`!<!-- observer_disconnect_${window.BUILD_CODE} -->`,
) ||
document.documentElement.innerHTML.includes("observer_disconnect")
) {
console.log("io_data_end; disconnect");
self.IO_DATA_OBSERVER.disconnect();
self.IO_DATA_ELEMENT.innerHTML += text;
if (
!document.documentElement.innerHTML.includes(
"observer_disconnect",
)
) {
self.IO_DATA_ELEMENT.innerHTML += text;
}
self.IO_DATA_DISCONNECTED = true;
return;
}

View file

@ -207,6 +207,58 @@ pub async fn stripe_webhook(
return Json(e.into());
}
}
EventType::InvoicePaymentFailed => {
// payment failed
let subscription = match req.data.object {
EventObject::Subscription(c) => c,
_ => unreachable!("cannot be this"),
};
let customer_id = subscription.customer.id();
let user = match data.get_user_by_stripe_id(customer_id.as_str()).await {
Ok(ua) => ua,
Err(e) => return Json(e.into()),
};
tracing::info!(
"unsubscribe (pay fail) {} (stripe: {})",
user.id,
customer_id
);
let new_user_permissions = user.permissions - FinePermission::SUPPORTER;
if let Err(e) = data
.update_user_role(user.id, new_user_permissions, user.clone(), true)
.await
{
return Json(e.into());
}
if data.0.0.security.enable_invite_codes && user.was_purchased && user.invite_code == 0
{
// user doesn't come from an invite code, and is a purchased account
// this means their account must be locked if they stop paying
if let Err(e) = data
.update_user_awaiting_purchased_status(user.id, true, user.clone(), false)
.await
{
return Json(e.into());
}
}
if let Err(e) = data
.create_notification(Notification::new(
"It seems your recent payment has failed :(".to_string(),
"No worries! Your subscription is still active and will be retried. Your supporter status will resume when you have a successful payment."
.to_string(),
user.id,
))
.await
{
return Json(e.into());
}
}
_ => return Json(Error::Unknown.into()),
}

View file

@ -635,6 +635,10 @@ pub fn routes() -> Router {
.route("/layouts/{id}/pages", post(layouts::update_pages_request))
}
pub fn lw_routes() -> Router {
Router::new()
}
#[derive(Deserialize)]
pub struct LoginProps {
pub username: String,

View file

@ -46,3 +46,14 @@ pub fn routes(config: &Config) -> Router {
// pages
.merge(pages::routes())
}
/// These routes are only used when you provide the `LITTLEWEB` environment variable.
///
/// These routes are NOT for editing. These routes are only for viewing littleweb sites.
pub fn lw_routes() -> Router {
Router::new()
// api
.nest("/api/v1", api::v1::lw_routes())
// pages
.merge(pages::lw_routes())
}

View file

@ -141,6 +141,10 @@ pub fn routes() -> Router {
.route("/x/{note}", get(journals::global_view_request))
}
pub fn lw_routes() -> Router {
Router::new()
}
pub async fn render_error(
e: Error,
jar: &CookieJar,