feat(api): implemented /project/delete
This commit is contained in:
parent
e93d8675c4
commit
4bccfeef96
|
@ -26,7 +26,7 @@ __(ND)__ -> Not designed yet.
|
|||
- [ ] `/projects`
|
||||
- `/project`
|
||||
- [X] `/create`
|
||||
- [ ] `/delete`
|
||||
- [X] `/delete`
|
||||
- [X] `/info`
|
||||
- [ ] `/join`
|
||||
- `/vault`
|
||||
|
|
|
@ -23,4 +23,6 @@ The request was malformed.
|
|||
### 401 - Error: Unauthorized
|
||||
The provided access token doesn't allow you to perform this operation.
|
||||
### 403 - Error: Forbidden
|
||||
Blocked for security reasons.
|
||||
Blocked for security reasons.
|
||||
### 404 - Error: Not Found
|
||||
The project wasn't found.
|
|
@ -95,6 +95,7 @@ pub async fn start(port: u16, pool: PgPool) -> Result<()> {
|
|||
.service(account::calls::tokens_get)
|
||||
.service(project::calls::create)
|
||||
.service(project::calls::info)
|
||||
.service(project::calls::delete)
|
||||
.app_data(web::Data::new(ApiState { pool: pool.clone() }))
|
||||
})
|
||||
.bind(("0.0.0.0", port))?
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::api::ApiState;
|
||||
use crate::api::project::{data, handlers};
|
||||
use actix_web::{get, post, web, HttpResponse, Responder};
|
||||
use actix_web::{get, post, web, HttpResponse, Responder, delete};
|
||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||
use log::error;
|
||||
|
||||
|
@ -21,7 +21,7 @@ async fn create(data: web::Data<ApiState>, auth: BearerAuth, body: web::Json<dat
|
|||
}
|
||||
|
||||
#[get("/project/info")]
|
||||
async fn info(data: web::Data<ApiState>, query: web::Query<data::InfoQuery>) -> impl Responder {
|
||||
async fn info(data: web::Data<ApiState>, query: web::Query<data::ProjectIdQuery>) -> impl Responder {
|
||||
|
||||
let request = if query.id.is_none() || query.name.is_none() {
|
||||
if let Some(id) = query.id {
|
||||
|
@ -49,3 +49,34 @@ async fn info(data: web::Data<ApiState>, query: web::Query<data::InfoQuery>) ->
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[delete("/project/delete")]
|
||||
async fn delete(data: web::Data<ApiState>, auth: BearerAuth, query: web::Query<data::ProjectIdQuery>) -> impl Responder {
|
||||
|
||||
let request = if query.id.is_none() || query.name.is_none() {
|
||||
if let Some(id) = query.id {
|
||||
data::DeleteRequest::Id(id)
|
||||
} else if let Some(name) = query.into_inner().name {
|
||||
data::DeleteRequest::Name(name)
|
||||
} else {
|
||||
// No parameters were supplied
|
||||
return HttpResponse::BadRequest().finish();
|
||||
}
|
||||
} else {
|
||||
// Too many parameters were supplied
|
||||
return HttpResponse::BadRequest().finish();
|
||||
};
|
||||
|
||||
match handlers::delete(&data.pool, auth.token().to_string(), request).await {
|
||||
Ok(resp) => match resp {
|
||||
data::DeleteResponse::Success => HttpResponse::Ok().finish(),
|
||||
data::DeleteResponse::Unauthorized => HttpResponse::Unauthorized().finish(),
|
||||
data::DeleteResponse::Blocked => HttpResponse::Forbidden().finish(),
|
||||
data::DeleteResponse::NotFound => HttpResponse::NotFound().finish(),
|
||||
},
|
||||
Err(e) => {
|
||||
error!("While handling info request: {e}");
|
||||
HttpResponse::InternalServerError().finish()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct ProjectIdQuery {
|
||||
pub name: Option<String>,
|
||||
pub id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct CreateRequest {
|
||||
pub name: String,
|
||||
|
@ -19,12 +26,6 @@ pub enum CreateResponse {
|
|||
Conflict,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
pub struct InfoQuery {
|
||||
pub name: Option<String>,
|
||||
pub id: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum InfoRequest {
|
||||
Name(String),
|
||||
|
@ -45,4 +46,18 @@ pub enum InfoResponse {
|
|||
Success(InfoSuccess),
|
||||
Blocked,
|
||||
NotFound,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DeleteRequest {
|
||||
Name(String),
|
||||
Id(i64),
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum DeleteResponse {
|
||||
Success,
|
||||
Unauthorized,
|
||||
Blocked,
|
||||
NotFound,
|
||||
}
|
|
@ -7,6 +7,7 @@ use crate::{
|
|||
use anyhow::{Error, Result};
|
||||
use sqlx::PgPool;
|
||||
use crate::accounts::Account;
|
||||
use crate::projects::ProjectMemberFlags;
|
||||
|
||||
pub async fn create(
|
||||
pool: &PgPool,
|
||||
|
@ -70,4 +71,41 @@ pub async fn info(pool: &PgPool, request: data::InfoRequest) -> Result<data::Inf
|
|||
created: project.created.timestamp(),
|
||||
members,
|
||||
}))
|
||||
}
|
||||
|
||||
pub async fn delete(
|
||||
pool: &PgPool,
|
||||
auth: String,
|
||||
request: data::DeleteRequest,
|
||||
) -> Result<data::DeleteResponse> {
|
||||
if !auth.is_alpha() {
|
||||
return Ok(data::DeleteResponse::Blocked);
|
||||
}
|
||||
|
||||
let token = match AuthToken::check(pool, &auth).await? {
|
||||
Some(t) => t,
|
||||
None => return Ok(data::DeleteResponse::Unauthorized),
|
||||
};
|
||||
|
||||
let project = match match request {
|
||||
data::DeleteRequest::Name(name) => {
|
||||
if is_sql_injection(&name) {
|
||||
return Ok(data::DeleteResponse::Blocked);
|
||||
}
|
||||
Project::from_name(pool, &name).await?
|
||||
}
|
||||
data::DeleteRequest::Id(id) => Project::from_id(pool, id).await?
|
||||
}
|
||||
{
|
||||
Some(p) => p,
|
||||
None => return Ok(data::DeleteResponse::NotFound)
|
||||
};
|
||||
|
||||
if !project.member_has_flag(&token.account, ProjectMemberFlags::Owner).await {
|
||||
return Ok(data::DeleteResponse::Unauthorized);
|
||||
}
|
||||
|
||||
project.delete(pool).await?;
|
||||
|
||||
Ok(data::DeleteResponse::Success)
|
||||
}
|
|
@ -85,4 +85,27 @@ impl Project {
|
|||
Err(e) => Err(Error::new(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn member_has_flag(&self, member: &ID, flag: ProjectMemberFlags) -> bool {
|
||||
let account_id = member.id();
|
||||
let flag_mask: u16 = flag.into();
|
||||
|
||||
for &id in self.members.iter() {
|
||||
if id.id() == account_id && (id.flags() & flag_mask) > 0 {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub async fn delete(&self, pool: &PgPool) -> Result<()> {
|
||||
sqlx::query!(
|
||||
r#"DELETE FROM Projects WHERE id = $1;"#,
|
||||
self.id
|
||||
)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue