feat: add users endpoint and add me and uuid under it
Some checks failed
ci/woodpecker/push/build-and-publish Pipeline failed
Some checks failed
ci/woodpecker/push/build-and-publish Pipeline failed
Adds a users endpoint that returns all users on the server, will require instance permissions in future. Place previous user requests under users to avoid having multiple endpoints.
This commit is contained in:
parent
cc07d78325
commit
1d7cdf343b
5 changed files with 149 additions and 18 deletions
|
@ -23,7 +23,7 @@ simple_logger = "5.0.0"
|
||||||
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-native-tls", "postgres"] }
|
sqlx = { version = "0.8", features = ["runtime-tokio", "tls-native-tls", "postgres"] }
|
||||||
toml = "0.8"
|
toml = "0.8"
|
||||||
url = { version = "2.5", features = ["serde"] }
|
url = { version = "2.5", features = ["serde"] }
|
||||||
uuid = { version = "1.16", features = ["v7"] }
|
uuid = { version = "1.16", features = ["serde", "v7"] }
|
||||||
|
|
||||||
[dependencies.tokio]
|
[dependencies.tokio]
|
||||||
version = "1.44"
|
version = "1.44"
|
||||||
|
|
|
@ -2,11 +2,11 @@ use actix_web::{Scope, web};
|
||||||
|
|
||||||
mod auth;
|
mod auth;
|
||||||
mod stats;
|
mod stats;
|
||||||
mod user;
|
mod users;
|
||||||
|
|
||||||
pub fn web() -> Scope {
|
pub fn web() -> Scope {
|
||||||
web::scope("/v1")
|
web::scope("/v1")
|
||||||
.service(stats::res)
|
.service(stats::res)
|
||||||
.service(auth::web())
|
.service(auth::web())
|
||||||
.service(user::res)
|
.service(users::web())
|
||||||
}
|
}
|
||||||
|
|
66
src/api/v1/users/me.rs
Normal file
66
src/api/v1/users/me.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
use actix_web::{Error, HttpResponse, error, post, web};
|
||||||
|
use futures::StreamExt;
|
||||||
|
use log::error;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::{Data, api::v1::auth::check_access_token};
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct AuthenticationRequest {
|
||||||
|
access_token: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct Response {
|
||||||
|
uuid: String,
|
||||||
|
username: String,
|
||||||
|
display_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_SIZE: usize = 262_144;
|
||||||
|
|
||||||
|
#[post("/me")]
|
||||||
|
pub async fn res(
|
||||||
|
mut payload: web::Payload,
|
||||||
|
data: web::Data<Data>,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
let mut body = web::BytesMut::new();
|
||||||
|
while let Some(chunk) = payload.next().await {
|
||||||
|
let chunk = chunk?;
|
||||||
|
// limit max size of in-memory payload
|
||||||
|
if (body.len() + chunk.len()) > MAX_SIZE {
|
||||||
|
return Err(error::ErrorBadRequest("overflow"));
|
||||||
|
}
|
||||||
|
body.extend_from_slice(&chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
let authentication_request = serde_json::from_slice::<AuthenticationRequest>(&body)?;
|
||||||
|
|
||||||
|
let authorized = check_access_token(authentication_request.access_token, &data.pool).await;
|
||||||
|
|
||||||
|
if let Err(error) = authorized {
|
||||||
|
return Ok(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
let uuid = authorized.unwrap();
|
||||||
|
|
||||||
|
let row = sqlx::query_as(&format!(
|
||||||
|
"SELECT username, display_name FROM users WHERE uuid = '{}'",
|
||||||
|
uuid
|
||||||
|
))
|
||||||
|
.fetch_one(&data.pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(error) = row {
|
||||||
|
error!("{}", error);
|
||||||
|
return Ok(HttpResponse::InternalServerError().finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
let (username, display_name): (String, Option<String>) = row.unwrap();
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().json(Response {
|
||||||
|
uuid: uuid.to_string(),
|
||||||
|
username,
|
||||||
|
display_name: display_name.unwrap_or_default(),
|
||||||
|
}))
|
||||||
|
}
|
77
src/api/v1/users/mod.rs
Normal file
77
src/api/v1/users/mod.rs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
use actix_web::{error, post, web, Error, HttpResponse, Scope};
|
||||||
|
use futures::StreamExt;
|
||||||
|
use log::error;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use sqlx::prelude::FromRow;
|
||||||
|
use crate::{Data, api::v1::auth::check_access_token};
|
||||||
|
|
||||||
|
mod me;
|
||||||
|
mod uuid;
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct Request {
|
||||||
|
access_token: String,
|
||||||
|
start: i32,
|
||||||
|
amount: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, FromRow)]
|
||||||
|
struct Response {
|
||||||
|
uuid: String,
|
||||||
|
username: String,
|
||||||
|
display_name: Option<String>,
|
||||||
|
email: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
const MAX_SIZE: usize = 262_144;
|
||||||
|
|
||||||
|
pub fn web() -> Scope {
|
||||||
|
web::scope("/users")
|
||||||
|
.service(res)
|
||||||
|
.service(me::res)
|
||||||
|
.service(uuid::res)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[post("")]
|
||||||
|
pub async fn res(
|
||||||
|
mut payload: web::Payload,
|
||||||
|
data: web::Data<Data>,
|
||||||
|
) -> Result<HttpResponse, Error> {
|
||||||
|
let mut body = web::BytesMut::new();
|
||||||
|
while let Some(chunk) = payload.next().await {
|
||||||
|
let chunk = chunk?;
|
||||||
|
// limit max size of in-memory payload
|
||||||
|
if (body.len() + chunk.len()) > MAX_SIZE {
|
||||||
|
return Err(error::ErrorBadRequest("overflow"));
|
||||||
|
}
|
||||||
|
body.extend_from_slice(&chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
let request = serde_json::from_slice::<Request>(&body)?;
|
||||||
|
|
||||||
|
if request.amount > 100 {
|
||||||
|
return Ok(HttpResponse::BadRequest().finish())
|
||||||
|
}
|
||||||
|
|
||||||
|
let authorized = check_access_token(request.access_token, &data.pool).await;
|
||||||
|
|
||||||
|
if let Err(error) = authorized {
|
||||||
|
return Ok(error);
|
||||||
|
}
|
||||||
|
|
||||||
|
let row = sqlx::query_as("SELECT CAST(uuid AS VARCHAR), username, display_name, email FROM users ORDER BY username LIMIT $1 OFFSET $2")
|
||||||
|
.bind(request.amount)
|
||||||
|
.bind(request.start)
|
||||||
|
.fetch_all(&data.pool)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Err(error) = row {
|
||||||
|
error!("{}", error);
|
||||||
|
return Ok(HttpResponse::InternalServerError().finish());
|
||||||
|
}
|
||||||
|
|
||||||
|
let accounts: Vec<Response> = row.unwrap();
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().json(accounts))
|
||||||
|
}
|
||||||
|
|
|
@ -20,10 +20,10 @@ struct Response {
|
||||||
|
|
||||||
const MAX_SIZE: usize = 262_144;
|
const MAX_SIZE: usize = 262_144;
|
||||||
|
|
||||||
#[post("/user/{uuid}")]
|
#[post("/{uuid}")]
|
||||||
pub async fn res(
|
pub async fn res(
|
||||||
mut payload: web::Payload,
|
mut payload: web::Payload,
|
||||||
path: web::Path<(String,)>,
|
path: web::Path<(Uuid,)>,
|
||||||
data: web::Data<Data>,
|
data: web::Data<Data>,
|
||||||
) -> Result<HttpResponse, Error> {
|
) -> Result<HttpResponse, Error> {
|
||||||
let mut body = web::BytesMut::new();
|
let mut body = web::BytesMut::new();
|
||||||
|
@ -36,7 +36,7 @@ pub async fn res(
|
||||||
body.extend_from_slice(&chunk);
|
body.extend_from_slice(&chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
let request = path.into_inner().0;
|
let uuid = path.into_inner().0;
|
||||||
|
|
||||||
let authentication_request = serde_json::from_slice::<AuthenticationRequest>(&body)?;
|
let authentication_request = serde_json::from_slice::<AuthenticationRequest>(&body)?;
|
||||||
|
|
||||||
|
@ -46,18 +46,6 @@ pub async fn res(
|
||||||
return Ok(error);
|
return Ok(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut uuid = authorized.unwrap();
|
|
||||||
|
|
||||||
if request != "me" {
|
|
||||||
let requested_uuid = Uuid::parse_str(&request);
|
|
||||||
|
|
||||||
if requested_uuid.is_err() {
|
|
||||||
return Ok(HttpResponse::BadRequest().json(r#"{ "error": "UUID is invalid!" }"#));
|
|
||||||
}
|
|
||||||
|
|
||||||
uuid = requested_uuid.unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
let row = sqlx::query_as(&format!(
|
let row = sqlx::query_as(&format!(
|
||||||
"SELECT username, display_name FROM users WHERE uuid = '{}'",
|
"SELECT username, display_name FROM users WHERE uuid = '{}'",
|
||||||
uuid
|
uuid
|
Loading…
Add table
Add a link
Reference in a new issue