tetratto/crates/app/src/routes/pages/littleweb.rs

294 lines
7.9 KiB
Rust
Raw Normal View History

2025-07-08 13:35:23 -04:00
use super::render_error;
2025-07-08 17:38:24 -04:00
use crate::{
assets::initial_context, get_lang, get_user_from_token,
routes::pages::misc::NotificationsProps, State,
};
2025-07-08 13:35:23 -04:00
use axum::{
response::{Html, IntoResponse},
extract::{Query, Path},
Extension,
};
use axum_extra::extract::CookieJar;
2025-07-08 17:38:24 -04:00
use tetratto_core::model::{littleweb::TLDS_VEC, permissions::SecondaryPermission, Error};
2025-07-08 13:35:23 -04:00
use serde::Deserialize;
use tetratto_shared::hash::salt;
2025-07-08 13:35:23 -04:00
/// `/services`
pub async fn services_request(
jar: CookieJar,
Extension(data): Extension<State>,
2025-07-08 17:38:24 -04:00
Query(props): Query<NotificationsProps>,
2025-07-08 13:35:23 -04:00
) -> impl IntoResponse {
let data = data.read().await;
let user = match get_user_from_token!(jar, data.0) {
Some(ua) => ua,
None => {
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
};
2025-07-08 17:38:24 -04:00
let profile = if props.id != 0 {
match data.0.get_user_by_id(props.id).await {
Ok(x) => x,
Err(e) => return Err(Html(render_error(e, &jar, &data, &None).await)),
}
} else {
user.clone()
};
if profile.id != user.id
&& !user
.secondary_permissions
.check(SecondaryPermission::MANAGE_SERVICES)
{
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
let list = match data.0.get_services_by_user(profile.id).await {
2025-07-08 13:35:23 -04:00
Ok(x) => x,
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
};
let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
context.insert("list", &list);
2025-07-08 17:38:24 -04:00
context.insert("profile", &profile);
2025-07-08 13:35:23 -04:00
// return
Ok(Html(
data.1.render("littleweb/services.html", &context).unwrap(),
))
}
/// `/domains`
pub async fn domains_request(
jar: CookieJar,
Extension(data): Extension<State>,
2025-07-08 17:38:24 -04:00
Query(props): Query<NotificationsProps>,
2025-07-08 13:35:23 -04:00
) -> impl IntoResponse {
let data = data.read().await;
let user = match get_user_from_token!(jar, data.0) {
Some(ua) => ua,
None => {
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
};
2025-07-08 17:38:24 -04:00
let profile = if props.id != 0 {
match data.0.get_user_by_id(props.id).await {
Ok(x) => x,
Err(e) => return Err(Html(render_error(e, &jar, &data, &None).await)),
}
} else {
user.clone()
};
if profile.id != user.id
&& !user
.secondary_permissions
.check(SecondaryPermission::MANAGE_DOMAINS)
{
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
2025-07-08 17:44:49 -04:00
let list = match data.0.get_domains_by_user(profile.id).await {
2025-07-08 13:35:23 -04:00
Ok(x) => x,
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
};
let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
context.insert("list", &list);
context.insert("tlds", &*TLDS_VEC);
2025-07-08 17:38:24 -04:00
context.insert("profile", &profile);
2025-07-08 13:35:23 -04:00
// return
Ok(Html(
data.1.render("littleweb/domains.html", &context).unwrap(),
))
}
#[derive(Deserialize)]
pub struct FileBrowserProps {
#[serde(default)]
path: String,
}
/// `/services/{id}`
pub async fn service_request(
jar: CookieJar,
Path(id): Path<usize>,
Extension(data): Extension<State>,
Query(props): Query<FileBrowserProps>,
) -> impl IntoResponse {
let data = data.read().await;
let user = match get_user_from_token!(jar, data.0) {
Some(ua) => ua,
None => {
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
};
let service = match data.0.get_service_by_id(id).await {
Ok(x) => x,
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
};
2025-07-08 17:38:24 -04:00
if user.id != service.owner
&& !user
.secondary_permissions
.check(SecondaryPermission::MANAGE_SERVICES)
{
2025-07-08 13:35:23 -04:00
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
context.insert("service", &service);
match service.file(&props.path.replacen("/", "", 1)) {
Some((x, p)) => {
context.insert("id_path", &p);
context.insert("file", &x);
context.insert("files", &x.children);
}
None => {
context.insert("id_path", &Vec::<()>::new());
context.insert("files", &service.files);
}
}
let path_segments: Vec<&str> = props.path.split("/").collect();
context.insert("path_segments", &path_segments);
context.insert("path", &props.path);
// return
Ok(Html(
data.1.render("littleweb/service.html", &context).unwrap(),
))
}
/// `/domains/{id}`
pub async fn domain_request(
jar: CookieJar,
Path(id): Path<usize>,
Extension(data): Extension<State>,
) -> impl IntoResponse {
let data = data.read().await;
let user = match get_user_from_token!(jar, data.0) {
Some(ua) => ua,
None => {
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
};
let domain = match data.0.get_domain_by_id(id).await {
Ok(x) => x,
Err(e) => return Err(Html(render_error(e, &jar, &data, &Some(user)).await)),
};
2025-07-08 17:38:24 -04:00
if user.id != domain.owner
&& !user
.secondary_permissions
.check(SecondaryPermission::MANAGE_DOMAINS)
{
2025-07-08 13:35:23 -04:00
return Err(Html(
render_error(Error::NotAllowed, &jar, &data, &None).await,
));
}
let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0.0, lang, &Some(user)).await;
context.insert("domain", &domain);
// return
Ok(Html(
data.1.render("littleweb/domain.html", &context).unwrap(),
))
}
/// `/net`
pub async fn browser_home_request(
jar: CookieJar,
Extension(data): Extension<State>,
) -> impl IntoResponse {
let data = data.read().await;
let user = get_user_from_token!(jar, data.0);
// update session
let session = salt();
if let Some(ref ua) = user {
if let Err(e) = data.0.update_user_browser_session(ua.id, &session).await {
return Err(Html(render_error(e.into(), &jar, &data, &None).await));
}
}
// ...
2025-07-08 13:35:23 -04:00
let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0.0, lang, &user).await;
2025-07-08 13:35:23 -04:00
context.insert("path", &"");
context.insert("session", &session);
2025-07-08 13:35:23 -04:00
// return
Ok(Html(
data.1.render("littleweb/browser.html", &context).unwrap(),
))
2025-07-08 13:35:23 -04:00
}
/// `/net/{uri}`
pub async fn browser_request(
jar: CookieJar,
Path(mut uri): Path<String>,
Extension(data): Extension<State>,
) -> impl IntoResponse {
let data = data.read().await;
let user = get_user_from_token!(jar, data.0);
if !uri.contains("/") {
uri = format!("{uri}/index.html");
}
if !uri.starts_with("atto://") {
uri = format!("atto://{uri}");
}
// update session
let session = salt();
if let Some(ref ua) = user {
if let Err(e) = data.0.update_user_browser_session(ua.id, &session).await {
return Err(Html(render_error(e.into(), &jar, &data, &None).await));
}
}
// ...
2025-07-08 13:35:23 -04:00
let lang = get_lang!(jar, data.0);
let mut context = initial_context(&data.0.0.0, lang, &user).await;
context.insert("session", &session);
2025-07-08 17:38:24 -04:00
context.insert("path", &uri.replace("atto://", ""));
2025-07-08 13:35:23 -04:00
// return
Ok(Html(
data.1.render("littleweb/browser.html", &context).unwrap(),
))
2025-07-08 13:35:23 -04:00
}