add: anonymous questions

This commit is contained in:
trisua 2025-04-19 18:59:55 -04:00
parent 2266afde01
commit 3db7f2699c
34 changed files with 473 additions and 98 deletions

View file

@ -4,7 +4,7 @@ use crate::{
};
use axum::{Extension, Json, extract::Path, response::IntoResponse};
use axum_extra::extract::CookieJar;
use tetratto_core::model::auth::{FollowResult, Notification, UserBlock, UserFollow};
use tetratto_core::model::auth::{FollowResult, IpBlock, Notification, UserBlock, UserFollow};
/// Toggle following on the given user.
pub async fn follow_request(
@ -197,3 +197,38 @@ pub async fn block_request(
}
}
}
/// Toggle IP blocking on the given IP.
pub async fn ip_block_request(
jar: CookieJar,
Path(ip): Path<String>,
Extension(data): Extension<State>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data) {
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
if let Ok(ipblock) = data.get_ipblock_by_initiator_receiver(user.id, &ip).await {
// delete
match data.delete_ipblock(ipblock.id, user).await {
Ok(_) => Json(ApiReturn {
ok: true,
message: "IP unblocked".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
} else {
// create
match data.create_ipblock(IpBlock::new(user.id, ip)).await {
Ok(_) => Json(ApiReturn {
ok: true,
message: "IP blocked".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}
}

View file

@ -1,27 +1,49 @@
use axum::{Extension, Json, extract::Path, response::IntoResponse};
use axum::{
extract::Path,
http::{HeaderMap, HeaderValue},
response::IntoResponse,
Extension, Json,
};
use axum_extra::extract::CookieJar;
use tetratto_core::model::{communities::Question, ApiReturn, Error};
use tetratto_core::model::{auth::IpBlock, communities::Question, ApiReturn, Error};
use crate::{get_user_from_token, routes::api::v1::CreateQuestion, State};
pub async fn create_request(
jar: CookieJar,
headers: HeaderMap,
Extension(data): Extension<State>,
Json(req): Json<CreateQuestion>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data) {
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
let user = get_user_from_token!(jar, data);
if req.is_global && user.is_none() {
return Json(Error::NotAllowed.into());
}
// get real ip
let real_ip = headers
.get(data.0.security.real_ip_header.to_owned())
.unwrap_or(&HeaderValue::from_static(""))
.to_str()
.unwrap_or("")
.to_string();
// check for ip ban
if data.get_ipban_by_ip(&real_ip).await.is_ok() {
return Json(Error::NotAllowed.into());
}
// ...
let mut props = Question::new(
user.id,
if let Some(ref ua) = user { ua.id } else { 0 },
match req.receiver.parse::<usize>() {
Ok(x) => x,
Err(e) => return Json(Error::MiscError(e.to_string()).into()),
},
req.content,
req.is_global,
real_ip,
);
if !req.community.is_empty() {
@ -63,3 +85,43 @@ pub async fn delete_request(
Err(e) => Json(e.into()),
}
}
pub async fn ip_block_request(
jar: CookieJar,
Extension(data): Extension<State>,
Path(id): Path<usize>,
) -> impl IntoResponse {
let data = &(data.read().await).0;
let user = match get_user_from_token!(jar, data) {
Some(ua) => ua,
None => return Json(Error::NotAllowed.into()),
};
// get question
let question = match data.get_question_by_id(id).await {
Ok(q) => q,
Err(e) => return Json(e.into()),
};
// check for an existing ip block
if data
.get_ipblock_by_initiator_receiver(user.id, &question.ip)
.await
.is_ok()
{
return Json(Error::NotAllowed.into());
}
// create ip block
match data
.create_ipblock(IpBlock::new(user.id, question.ip))
.await
{
Ok(_) => Json(ApiReturn {
ok: true,
message: "IP blocked".to_string(),
payload: (),
}),
Err(e) => Json(e.into()),
}
}

View file

@ -100,6 +100,10 @@ pub fn routes() -> Router {
"/questions/{id}",
delete(communities::questions::delete_request),
)
.route(
"/questions/{id}/block_ip",
post(communities::questions::ip_block_request),
)
// auth
// global
.route("/auth/register", post(auth::register_request))
@ -177,6 +181,7 @@ pub fn routes() -> Router {
"/auth/user/find_by_ip/{ip}",
get(auth::profile::redirect_from_ip),
)
.route("/auth/ip/{ip}/block", post(auth::social::ip_block_request))
// warnings
.route("/warnings/{id}", post(auth::user_warnings::create_request))
.route(

View file

@ -20,6 +20,10 @@ pub fn routes(config: &Config) -> Router {
get_service(tower_http::services::ServeDir::new(&config.dirs.assets)),
)
.route("/public/favicon.svg", get(assets::favicon_request))
.route_service(
"/robots.txt",
tower_http::services::ServeFile::new(format!("{}/robots.txt", config.dirs.assets)),
)
// api
.nest("/api/v1", api::v1::routes())
// pages