feat(api): implemented /user/info
This commit is contained in:
parent
f9595513e0
commit
7bf9e57010
|
@ -21,7 +21,7 @@ __(ND)__ -> Not designed yet.
|
|||
- [ ] `/deactivate`
|
||||
- [ ] `/activate`
|
||||
- `/user/`
|
||||
- [ ] `/info`
|
||||
- [X] `/info`
|
||||
- [ ] `/follow`
|
||||
- [ ] `/follows`
|
||||
- [ ] `/followers`
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
# `/user/info` - GET
|
||||
Returns information about the project.
|
||||
|
||||
Returns information about the user.
|
||||
|
||||
## Urlencoded Parameters
|
||||
|
||||
You have to set one parameter.
|
||||
Setting none or two parameters will result in a _400 Bad Request_ Response.
|
||||
|
||||
| Parameter | Description |
|
||||
|-----------|--------------------------------------------------------------------|
|
||||
| name | The username of the user on which the operation will be performed. |
|
||||
| id | The userid of the user on which the operation will be performed. |
|
||||
|
||||
|
||||
## Responses
|
||||
|
||||
### 200 - Success
|
||||
|
||||
__Content - JSON:__
|
||||
| Field | Description |
|
||||
|----------|-------------------------------------------------------------------|
|
||||
|
@ -20,9 +23,15 @@ __Content - JSON:__
|
|||
| name | The users unique username. |
|
||||
| joined | The datetime when the user joined. Represented as UNIX timestamp. |
|
||||
| is_admin | A boolean if the user is an admin. |
|
||||
|
||||
### 400 - Error: Bad Request
|
||||
|
||||
The request was malformed.
|
||||
|
||||
### 403 - Error: Forbidden
|
||||
|
||||
Blocked for security reasons.
|
||||
|
||||
### 404 - Error: Not Found
|
||||
|
||||
The user wasn't found.
|
|
@ -13,6 +13,10 @@ pub struct ID {
|
|||
flags: u16,
|
||||
}
|
||||
|
||||
pub enum AccountFlags {
|
||||
Admin,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Account {
|
||||
pub id: ID,
|
||||
|
@ -35,6 +39,14 @@ impl From<i64> for ID {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<AccountFlags> for u16 {
|
||||
fn from(value: AccountFlags) -> Self {
|
||||
match value {
|
||||
AccountFlags::Admin => 0b0000_0000_0000_0001,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ID {
|
||||
pub fn new(id: i64, flags: u16) -> Self {
|
||||
Self {
|
||||
|
@ -200,4 +212,9 @@ impl Account {
|
|||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn has_flag(&self, flag: AccountFlags) -> bool {
|
||||
let mask: u16 = flag.into();
|
||||
(self.flags as u16 & mask) > 0
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
mod account;
|
||||
mod project;
|
||||
mod user;
|
||||
|
||||
use actix_web::{web, App, HttpServer};
|
||||
use anyhow::Result;
|
||||
|
@ -96,6 +97,7 @@ pub async fn start(port: u16, pool: PgPool) -> Result<()> {
|
|||
.service(project::calls::create)
|
||||
.service(project::calls::info)
|
||||
.service(project::calls::delete)
|
||||
.service(user::calls::info)
|
||||
.app_data(web::Data::new(ApiState { pool: pool.clone() }))
|
||||
})
|
||||
.bind(("0.0.0.0", port))?
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
use crate::api::user::{data, handlers};
|
||||
use crate::api::ApiState;
|
||||
use actix_web::{get, web, HttpResponse, Responder};
|
||||
use log::error;
|
||||
|
||||
#[get("/user/info")]
|
||||
async fn info(data: web::Data<ApiState>, query: web::Query<data::UserIdQuery>) -> impl Responder {
|
||||
let request = if query.id.is_none() || query.username.is_none() {
|
||||
if let Some(id) = query.id {
|
||||
data::InfoRequest::Id(id)
|
||||
} else if let Some(name) = query.into_inner().username {
|
||||
data::InfoRequest::Name(name)
|
||||
} else {
|
||||
// No parameters were supplied
|
||||
return HttpResponse::BadRequest().finish();
|
||||
}
|
||||
} else {
|
||||
// Too many parameters were supplied
|
||||
return HttpResponse::BadRequest().finish();
|
||||
};
|
||||
|
||||
match handlers::info(&data.pool, request).await {
|
||||
Ok(resp) => match resp {
|
||||
data::InfoResponse::Success(b) => HttpResponse::Ok().json(web::Json(b)),
|
||||
data::InfoResponse::Blocked => HttpResponse::Forbidden().finish(),
|
||||
data::InfoResponse::NotFound => HttpResponse::NotFound().finish(),
|
||||
},
|
||||
Err(e) => {
|
||||
error!("While handling info request: {e}");
|
||||
HttpResponse::InternalServerError().finish()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct UserIdQuery {
|
||||
pub username: Option<String>,
|
||||
pub id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InfoRequest {
|
||||
Name(String),
|
||||
Id(i64),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct InfoSuccess {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub joined: i64,
|
||||
pub is_admin: bool,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InfoResponse {
|
||||
Success(InfoSuccess),
|
||||
Blocked,
|
||||
NotFound,
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
use crate::{
|
||||
api::user::data,
|
||||
accounts::{Account, AccountFlags},
|
||||
security::is_sql_injection,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use sqlx::PgPool;
|
||||
|
||||
pub async fn info(pool: &PgPool, request: data::InfoRequest) -> Result<data::InfoResponse> {
|
||||
let account = match match request {
|
||||
data::InfoRequest::Name(name) => {
|
||||
if is_sql_injection(&name) {
|
||||
return Ok(data::InfoResponse::Blocked);
|
||||
}
|
||||
Account::from_username(pool, &name).await?
|
||||
}
|
||||
data::InfoRequest::Id(id) => Account::from_id(pool, id).await?,
|
||||
} {
|
||||
Some(p) => p,
|
||||
None => return Ok(data::InfoResponse::NotFound),
|
||||
};
|
||||
|
||||
let is_admin = account.has_flag(AccountFlags::Admin);
|
||||
|
||||
Ok(data::InfoResponse::Success(data::InfoSuccess {
|
||||
id: account.id.id(),
|
||||
name: account.username,
|
||||
joined: account.joined.timestamp(),
|
||||
is_admin,
|
||||
}))
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
pub mod calls;
|
||||
pub mod data;
|
||||
mod handlers;
|
Loading…
Reference in New Issue