summaryrefslogtreecommitdiffstats
path: root/src/routes
diff options
context:
space:
mode:
Diffstat (limited to 'src/routes')
-rw-r--r--src/routes/auth.rs68
-rw-r--r--src/routes/mod.rs28
-rw-r--r--src/routes/model.rs267
-rw-r--r--src/routes/user.rs210
-rw-r--r--src/routes/warning.rs177
5 files changed, 0 insertions, 750 deletions
diff --git a/src/routes/auth.rs b/src/routes/auth.rs
deleted file mode 100644
index 0c459f5..0000000
--- a/src/routes/auth.rs
+++ /dev/null
@@ -1,68 +0,0 @@
-use crate::{
- errors::AppError,
- models::{
- auth::{AuthBody, Claims, LoginCredentials, SignUpForm},
- user::User,
- },
- routes::JsonCreate,
-};
-use axum::{routing::post, Json, Router};
-
-/// Create routes for `/v1/auth/` namespace
-pub fn create_route() -> Router {
- Router::new()
- .route("/login", post(make_login))
- .route("/signup", post(signup))
-}
-
-/// Make login. Check if a user with the email and password passed in request body exists into the
-/// database
-async fn make_login(Json(payload): Json<LoginCredentials>) -> Result<Json<AuthBody>, AppError> {
- let user = User::new(
- String::new(),
- String::new(),
- payload.username,
- payload.password,
- );
- match User::find(user).await {
- Ok(user) => {
- let claims = Claims::new(user.id);
- let token = claims.get_token()?;
- Ok(Json(AuthBody::new(token)))
- }
- Err(_) => Err(AppError::NotFound("User not found".to_string())),
- }
-}
-
-/// Create a new user
-async fn signup(Json(payload): Json<SignUpForm>) -> Result<JsonCreate<AuthBody>, AppError> {
- if payload.password1 != payload.password2 {
- return Err(AppError::BadRequest(
- "The inserted passwords do not match".to_string(),
- ));
- }
-
- if User::email_has_taken(&payload.email).await? {
- return Err(AppError::BadRequest(
- "An user with this email already exists".to_string(),
- ));
- }
-
- if User::username_has_taken(&payload.username).await? {
- return Err(AppError::BadRequest(
- "An user with this username already exists".to_string(),
- ));
- }
-
- let user = User::new(
- payload.name,
- payload.email,
- payload.username,
- payload.password1,
- );
- let user = User::create(user).await?;
-
- let claims = Claims::new(user.id);
- let token = claims.get_token()?;
- Ok(JsonCreate(AuthBody::new(token)))
-}
diff --git a/src/routes/mod.rs b/src/routes/mod.rs
deleted file mode 100644
index a0e8031..0000000
--- a/src/routes/mod.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-pub mod auth;
-pub mod model;
-pub mod user;
-pub mod warning;
-
-use crate::errors::AppError;
-use axum::{
- http::StatusCode,
- response::{IntoResponse, Response},
- Json,
-};
-use serde::Serialize;
-
-pub async fn page_404() -> impl IntoResponse {
- AppError::NotFound("Route not found".to_string())
-}
-
-/// Extension of `Json` which returns the CREATED status code
-pub struct JsonCreate<T>(pub T);
-
-impl<T> IntoResponse for JsonCreate<T>
-where
- T: Serialize,
-{
- fn into_response(self) -> Response {
- (StatusCode::CREATED, Json(self.0)).into_response()
- }
-}
diff --git a/src/routes/model.rs b/src/routes/model.rs
deleted file mode 100644
index 58ec732..0000000
--- a/src/routes/model.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-use crate::{
- errors::AppError,
- files::{delete_upload, upload},
- models::{
- auth::Claims,
- likes::Like,
- model::{Model, ModelCreate, ModelFilter, ModelUpload, ModelUser},
- user::User,
- },
- pagination::{ModelPagination, Pagination},
- routes::JsonCreate,
-};
-use axum::{
- extract::{ContentLengthLimit, Multipart, Path, Query},
- http::StatusCode,
- routing::{delete, get, post},
- Json, Router,
-};
-
-/// Create routes for `/v1/models/` namespace
-pub fn create_route() -> Router {
- Router::new()
- .route("/", get(list_models).post(create_model))
- .route("/filter", post(filter_models))
- .route("/:id", get(get_model).delete(delete_model).put(edit_model))
- .route("/:id/like", post(add_like).delete(delete_like))
- .route("/:id/upload", post(upload_model_file))
- .route("/:id/upload/:uid", delete(delete_model_file))
-}
-
-/// List models.
-async fn list_models(pagination: Query<Pagination>) -> Result<Json<ModelPagination>, AppError> {
- let page = pagination.0.page.unwrap_or_default();
- let results = Model::list(page).await?;
- let count = Model::count().await?;
-
- Ok(Json(ModelPagination { count, results }))
-}
-
-/// Create a model. Checks Authorization token
-async fn create_model(
- Json(payload): Json<ModelCreate>,
- claims: Claims,
-) -> Result<JsonCreate<Model>, AppError> {
- let model = Model::new(
- payload.name,
- payload.description,
- payload.duration,
- payload.height,
- payload.weight,
- payload.printer,
- payload.material,
- claims.user_id,
- );
-
- let model_new = Model::create(model).await?;
-
- Ok(JsonCreate(model_new))
-}
-
-/// Get a model with id = `model_id`
-async fn get_model(Path(model_id): Path<i32>) -> Result<Json<ModelUser>, AppError> {
- match Model::find_by_id(model_id).await {
- Ok(model) => Ok(Json(model)),
- Err(_) => Err(AppError::NotFound("Model not found".to_string())),
- }
-}
-
-/// The owner or a staffer can delete a model
-async fn delete_model(claims: Claims, Path(model_id): Path<i32>) -> Result<StatusCode, AppError> {
- let model = match Model::find_by_id(model_id).await {
- Ok(model) => model,
- Err(_) => {
- return Err(AppError::NotFound("Model not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- let uploads: Vec<String> = model.list_upload_filepaths().await.unwrap_or_default();
-
- if !(model.author_id() == user.id || user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
-
- // If the model has been deleted, remove all old uploads from the file system
- if Model::delete(model_id).await.is_ok() {
- uploads
- .iter()
- .for_each(|path: &String| delete_upload(path).unwrap_or_default());
- }
-
- Ok(StatusCode::NO_CONTENT)
-}
-
-/// The owner or a staffer can edit a model
-async fn edit_model(
- Json(payload): Json<ModelCreate>,
- claims: Claims,
- Path(model_id): Path<i32>,
-) -> Result<Json<ModelUser>, AppError> {
- let model = match Model::find_by_id(model_id).await {
- Ok(model) => model,
- Err(_) => {
- return Err(AppError::NotFound("Model not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- if !(model.author_id() == user.id || user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
-
- let model_body = Model::new(
- payload.name,
- payload.description,
- payload.duration,
- payload.height,
- payload.weight,
- payload.printer,
- payload.material,
- claims.user_id,
- );
-
- // NOTE: can we edit this as same as `user.edit_avatar()`?
- Model::edit(model.id, model_body).await?;
- Ok(Json(model))
-}
-
-/// Upload a file for a model
-async fn upload_model_file(
- claims: Claims,
- Path(model_id): Path<i32>,
- ContentLengthLimit(multipart): ContentLengthLimit<Multipart, { 1024 * 1024 * 40 }>,
-) -> Result<Json<ModelUpload>, AppError> {
- let model = match Model::find_by_id(model_id).await {
- Ok(model) => model,
- Err(_) => {
- return Err(AppError::NotFound("Model not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- if !(model.author_id() == user.id || user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
-
- let allowed_extensions = vec![
- "stl",
- "obj",
- "png",
- "jpg",
- "jpeg",
- "gif",
- "webp",
- "blend",
- "octet-stream",
- "sla",
- ];
-
- match upload(multipart, allowed_extensions, None).await {
- Ok(saved_file) => {
- let model_file = ModelUpload::create(ModelUpload::new(saved_file, model_id)).await?;
-
- Ok(Json(model_file))
- }
- Err(e) => Err(e),
- }
-}
-
-/// The owner or a staffer can delete a model upload
-async fn delete_model_file(
- claims: Claims,
- Path((model_id, upload_id)): Path<(i32, i32)>,
-) -> Result<StatusCode, AppError> {
- let model = match Model::find_by_id(model_id).await {
- Ok(model) => model,
- Err(_) => {
- return Err(AppError::NotFound("Model not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- if !(model.author_id() == user.id || user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
-
- let upload = match ModelUpload::find_by_id(upload_id).await {
- Ok(upload) => upload,
- Err(_) => {
- return Err(AppError::NotFound("Upload not found".to_string()));
- }
- };
-
- if upload.model_id != model.id {
- return Err(AppError::NotFound("Upload not found".to_string()));
- }
-
- let filepath = upload.filepath.clone();
-
- match ModelUpload::delete(upload_id).await {
- Ok(_) => {
- delete_upload(&filepath)?;
-
- Ok(StatusCode::NO_CONTENT)
- }
- Err(e) => Err(e),
- }
-}
-
-/// Assign a like to a model from the Authorization user
-async fn add_like(claims: Claims, Path(model_id): Path<i32>) -> Result<StatusCode, AppError> {
- let model = match Model::find_by_id(model_id).await {
- Ok(model) => model,
- Err(_) => {
- return Err(AppError::NotFound("Model not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- let like = Like::new(user.id, model.id);
-
- match like.save().await {
- Ok(_) => Ok(StatusCode::CREATED),
- Err(e) => {
- return Err(e);
- }
- }
-}
-
-/// Remove a like from a model and an Authorization user
-async fn delete_like(claims: Claims, Path(model_id): Path<i32>) -> Result<StatusCode, AppError> {
- let model = match Model::find_by_id(model_id).await {
- Ok(model) => model,
- Err(_) => {
- return Err(AppError::NotFound("Model not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- let like = Like::new(user.id, model.id);
-
- match like.remove().await {
- Ok(_) => Ok(StatusCode::NO_CONTENT),
- Err(e) => {
- return Err(e);
- }
- }
-}
-
-/// Filter models
-async fn filter_models(
- pagination: Query<Pagination>,
- Json(payload): Json<ModelFilter>,
-) -> Result<Json<ModelPagination>, AppError> {
- let page = pagination.0.page.unwrap_or_default();
-
- let results = Model::filter(page, payload.q.clone()).await?;
- let count = Model::count_filter(payload.q).await?;
-
- Ok(Json(ModelPagination { count, results }))
-}
diff --git a/src/routes/user.rs b/src/routes/user.rs
deleted file mode 100644
index 31366a0..0000000
--- a/src/routes/user.rs
+++ /dev/null
@@ -1,210 +0,0 @@
-use crate::{
- errors::AppError,
- files::{delete_upload, upload},
- models::{
- auth::Claims,
- user::{User, UserEdit, UserList},
- },
- pagination::{ModelPagination, Pagination, UserPagination},
-};
-use axum::{
- extract::{ContentLengthLimit, Multipart, Path, Query},
- routing::{delete, get, put},
- Json, Router,
-};
-
-/// Create routes for `/v1/users/` namespace
-pub fn create_route() -> Router {
- Router::new()
- .route("/", get(list_users))
- .route("/me", get(get_me))
- .route("/me/avatar", put(edit_my_avatar).delete(delete_my_avatar))
- .route("/:id", get(get_user).put(edit_user))
- .route("/:id/avatar", delete(delete_avatar))
- .route("/:id/models", get(get_user_models))
-}
-
-/// List users. Checks Authorization token
-async fn list_users(
- _: Claims,
- pagination: Query<Pagination>,
-) -> Result<Json<UserPagination>, AppError> {
- let page = pagination.0.page.unwrap_or_default();
- let results = User::list(page).await?;
- let count = User::count().await?;
-
- Ok(Json(UserPagination { count, results }))
-}
-
-/// Get info about me
-async fn get_me(claims: Claims) -> Result<Json<UserList>, AppError> {
- match User::find_by_id(claims.user_id).await {
- Ok(user) => Ok(Json(user)),
- Err(_) => Err(AppError::NotFound("User not found".to_string())),
- }
-}
-
-/// Edit the avatar of the user linked to the claims
-async fn edit_my_avatar(
- claims: Claims,
- ContentLengthLimit(multipart): ContentLengthLimit<Multipart, { 1024 * 1024 * 5 }>,
-) -> Result<Json<UserList>, AppError> {
- let mut user = match User::find_by_id(claims.user_id).await {
- Ok(user) => user,
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
-
- if user.avatar.is_some() {
- let avatar_url = user.avatar.as_ref().unwrap();
- delete_upload(avatar_url)?;
- }
-
- match upload(
- multipart,
- vec!["jpg", "jpeg", "png", "webp"],
- Some(format!("avatar-{}", user.id)),
- )
- .await
- {
- Ok(saved_file) => {
- user.edit_avatar(Some(saved_file)).await?;
-
- Ok(Json(user))
- }
- Err(e) => Err(e),
- }
-}
-
-/// A staffer can delete an user `id`'s avatar
-async fn delete_avatar(
- Path(user_id): Path<i32>,
- claims: Claims,
-) -> Result<Json<UserList>, AppError> {
- let mut user = match User::find_by_id(user_id).await {
- Ok(user) => user,
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
-
- // If the user of the access token is different than the user they want to edit, checks if the
- // first user is an admin
- if claims.user_id != user.id {
- match User::find_by_id(claims.user_id).await {
- Ok(user) => {
- if !(user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
- }
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
- }
-
- if user.avatar.is_some() {
- let avatar_url = user.avatar.as_ref().unwrap();
- delete_upload(avatar_url)?;
- }
-
- user.edit_avatar(None).await?;
-
- Ok(Json(user))
-}
-
-/// Delete the avatar of the user linked to the claims
-async fn delete_my_avatar(claims: Claims) -> Result<Json<UserList>, AppError> {
- let mut user = match User::find_by_id(claims.user_id).await {
- Ok(user) => user,
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
-
- if user.avatar.is_some() {
- let avatar_url = user.avatar.as_ref().unwrap();
- delete_upload(avatar_url)?;
- }
-
- user.edit_avatar(None).await?;
-
- Ok(Json(user))
-}
-
-/// Get an user with id = `user_id`
-async fn get_user(Path(user_id): Path<i32>) -> Result<Json<UserList>, AppError> {
- match User::find_by_id(user_id).await {
- Ok(user) => Ok(Json(user)),
- Err(_) => Err(AppError::NotFound("User not found".to_string())),
- }
-}
-
-/// Edit an user with id = `user_id`. Only staffers and owner of that account can perform this
-/// action.
-/// Only staffers can update the user `is_staff` value
-async fn edit_user(
- Path(user_id): Path<i32>,
- Json(mut payload): Json<UserEdit>,
- claims: Claims,
-) -> Result<Json<UserList>, AppError> {
- let mut user = match User::find_by_id(user_id).await {
- Ok(user) => user,
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
-
- let claimed = match User::find_by_id(claims.user_id).await {
- Ok(user) => user,
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
-
- if user.id != claimed.id {
- if !(claimed.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
- }
-
- if !claimed.is_staff.unwrap() && user.is_staff != payload.is_staff {
- payload.is_staff = user.is_staff;
- }
-
- if user.email != payload.email && User::email_has_taken(&payload.email).await? {
- return Err(AppError::BadRequest(
- "An user with this email already exists".to_string(),
- ));
- }
-
- if user.username != payload.username && User::username_has_taken(&payload.username).await? {
- return Err(AppError::BadRequest(
- "An user with this username already exists".to_string(),
- ));
- }
-
- user.edit(payload).await?;
-
- Ok(Json(user))
-}
-
-/// Get user models list
-async fn get_user_models(
- Path(user_id): Path<i32>,
- pagination: Query<Pagination>,
-) -> Result<Json<ModelPagination>, AppError> {
- let user = match User::find_by_id(user_id).await {
- Ok(user) => user,
- Err(_) => {
- return Err(AppError::NotFound("User not found".to_string()));
- }
- };
-
- let page = pagination.0.page.unwrap_or_default();
- let results = user.get_models(page).await?;
- let count = user.count_models().await?;
-
- Ok(Json(ModelPagination { count, results }))
-}
diff --git a/src/routes/warning.rs b/src/routes/warning.rs
deleted file mode 100644
index 384218a..0000000
--- a/src/routes/warning.rs
+++ /dev/null
@@ -1,177 +0,0 @@
-use crate::{
- errors::AppError,
- models::{
- auth::Claims,
- model::Model,
- user::User,
- warning::{Warning, WarningCreate, WarningEdit, WarningFilter, WarningFilterPayload},
- },
- pagination::{Pagination, WarningPagination},
- routes::JsonCreate,
-};
-use axum::{
- extract::{Path, Query},
- http::StatusCode,
- routing::{get, post},
- Json, Router,
-};
-
-/// Create routes for `/v1/warnings/` namespace
-pub fn create_route() -> Router {
- Router::new()
- .route("/", get(list_warnings).post(create_warning))
- .route(
- "/:id",
- get(get_warning).put(edit_warning).delete(delete_warning),
- )
- .route("/filter", post(filter_warnings))
-}
-
-/// List warnings. A staffer can see everything.
-async fn list_warnings(
- pagination: Query<Pagination>,
- claims: Claims,
-) -> Result<Json<WarningPagination>, AppError> {
- let page = pagination.0.page.unwrap_or_default();
-
- let user = User::find_by_id(claims.user_id).await?;
-
- let (results, count) = match user.is_staff.unwrap() {
- true => (
- Warning::list(page, None).await?,
- Warning::count(None).await?,
- ),
- false => (
- Warning::list(page, Some(user.id)).await?,
- Warning::count(Some(user.id)).await?,
- ),
- };
-
- Ok(Json(WarningPagination { count, results }))
-}
-
-/// Get a warning with id = `model_id`
-async fn get_warning(
- Path(warning_id): Path<i32>,
- claims: Claims,
-) -> Result<Json<Warning>, AppError> {
- let user = User::find_by_id(claims.user_id).await?;
-
- if !(user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
-
- match Warning::find_by_id(warning_id).await {
- Ok(warning) => Ok(Json(warning.into())),
- Err(_) => Err(AppError::NotFound("Warning not found".to_string())),
- }
-}
-
-/// Create a warning. Checks Authorization token
-async fn create_warning(
- Json(payload): Json<WarningCreate>,
- claims: Claims,
-) -> Result<JsonCreate<Warning>, AppError> {
- let model = match Model::find_by_id(payload.model_id).await {
- Ok(model) => model,
- Err(_) => return Err(AppError::NotFound("Report not found".to_string())),
- };
-
- let warning = Warning::new(claims.user_id, model.id, payload.note);
-
- let warning_new = Warning::create(warning).await?;
-
- Ok(JsonCreate(warning_new))
-}
-
-/// Staffers can edit a warning
-async fn edit_warning(
- Json(payload): Json<WarningEdit>,
- claims: Claims,
- Path(warning_id): Path<i32>,
-) -> Result<Json<Warning>, AppError> {
- let mut warning: Warning = match Warning::find_by_id(warning_id).await {
- Ok(warning) => warning.into(),
- Err(_) => {
- return Err(AppError::NotFound("Report not found".to_string()));
- }
- };
-
- let user = User::find_by_id(claims.user_id).await?;
-
- if !(user.is_staff.unwrap()) {
- return Err(AppError::Unauthorized);
- }
-
- warning.edit(user.id, payload).await?;
-
- Ok(Json(warning))
-}
-
-/// A staffer can delete a warning
-async fn delete_warning(
- claims: Claims,
- Path(warning_id): Path<i32>,
-) -> Result<StatusCode, AppError> {
- let user = User::find_by_id(claims.user_id).await?;
-
- if !user.is_staff.unwrap() {
- return Err(AppError::Unauthorized);
- }
-
- if Warning::delete(warning_id).await.is_ok() {
- Ok(StatusCode::NO_CONTENT)
- } else {
- Ok(StatusCode::BAD_REQUEST)
- }
-}
-
-/// Apply a filter to warnings list
-async fn filter_warnings(
- Json(payload): Json<WarningFilterPayload>,
- pagination: Query<Pagination>,
- claims: Claims,
-) -> Result<Json<WarningPagination>, AppError> {
- let page = pagination.0.page.unwrap_or_default();
-
- let user = User::find_by_id(claims.user_id).await?;
-
- let (results, count) = match user.is_staff.unwrap() {
- true => (
- Warning::filter(
- page,
- WarningFilter {
- model_id: payload.model_id,
- resolved_by: payload.resolved_by,
- user_id: None,
- },
- )
- .await?,
- Warning::count_by_model_id(WarningFilter {
- model_id: payload.model_id,
- resolved_by: payload.resolved_by,
- user_id: None,
- })
- .await?,
- ),
- false => (
- Warning::filter(
- page,
- WarningFilter {
- model_id: payload.model_id,
- resolved_by: payload.resolved_by,
- user_id: Some(user.id),
- },
- )
- .await?,
- Warning::count_by_model_id(WarningFilter {
- model_id: payload.model_id,
- resolved_by: payload.resolved_by,
- user_id: Some(user.id),
- })
- .await?,
- ),
- };
-
- Ok(Json(WarningPagination { count, results }))
-}