Delete user script #13

Merged
loub merged 1 commits from delete-user into main 2026-01-30 11:23:45 +01:00
5 changed files with 78 additions and 9 deletions

View File

@ -149,6 +149,18 @@ impl BookOperator {
.context(DBSnafu) .context(DBSnafu)
} }
/// Finds vec of book by its Owner
pub async fn find_all_by_current_holder(
&self,
current_holder_id: i32,
) -> Result<Vec<Model>, BookError> {
Entity::find()
.filter(Column::CurrentHolderId.eq(current_holder_id))
.all(&self.state.db)
.await
.context(DBSnafu)
}
/// Creates a new book from the given form data. /// Creates a new book from the given form data.
pub async fn create(&self, form: BookForm) -> Result<Model, BookError> { pub async fn create(&self, form: BookForm) -> Result<Model, BookError> {
let book = ActiveModel { let book = ActiveModel {

View File

@ -1,4 +1,5 @@
use crate::models::book::BookOperator; use crate::models::book;
use crate::routes::book::BookForm;
use crate::routes::user::UserForm; use crate::routes::user::UserForm;
use crate::state::AppState; use crate::state::AppState;
use crate::state::error::UserSnafu; use crate::state::error::UserSnafu;
@ -38,6 +39,8 @@ pub enum UserError {
DB { source: sea_orm::DbErr }, DB { source: sea_orm::DbErr },
#[snafu(display("User with id {id} not found"))] #[snafu(display("User with id {id} not found"))]
NotFound { id: i32 }, NotFound { id: i32 },
#[snafu(display("Book error"))]
Book { source: super::book::BookError },
} }
#[derive(Debug)] #[derive(Debug)]
@ -90,7 +93,46 @@ impl UserOperator {
} }
} }
/// Delete user by ID.
/// Before deleting the user, you must search for all the books they own in order to delete them beforehand,
/// then search for all the books they have borrowed in order to update the current holder to None.
pub async fn delete(&self, user_id: i32) -> Result<DeleteResult, UserError> { pub async fn delete(&self, user_id: i32) -> Result<DeleteResult, UserError> {
// get all
let owner_books = book::BookOperator::new(self.state.clone())
.find_all_by_owner(user_id)
.await
.context(BookSnafu)?;
// Delete all book with owner_id = current_user
for owner_book in owner_books {
book::BookOperator::new(self.state.clone())
.delete(owner_book.id)
.await
.context(BookSnafu)?;
}
let current_holder_books = book::BookOperator::new(self.state.clone())
.find_all_by_current_holder(user_id)
.await
.context(BookSnafu)?;
// Update all book with current Holder = current user
for current_holder_book in current_holder_books {
let form = BookForm {
title: current_holder_book.title,
authors: current_holder_book.authors,
owner_id: current_holder_book.owner_id,
description: current_holder_book.description,
comment: current_holder_book.comment,
current_holder_id: None,
};
book::BookOperator::new(self.state.clone())
.update(current_holder_book.id, form)
.await
.context(BookSnafu)?;
}
let user: Option<Model> = Entity::find_by_id(user_id) let user: Option<Model> = Entity::find_by_id(user_id)
.one(&self.state.db) .one(&self.state.db)
.await .await

View File

@ -5,10 +5,7 @@ use log::error;
use snafu::prelude::*; use snafu::prelude::*;
use crate::{ use crate::{
models::{ models::{book::BookError, user::UserError},
book::{BookError, NotFoundSnafu},
user::UserError,
},
state::config::ConfigError, state::config::ConfigError,
}; };

View File

@ -28,5 +28,4 @@
<script src="/assets/js/bootstrap.min.js"></script> <script src="/assets/js/bootstrap.min.js"></script>
<script src="/assets/js/script.js"></script> <script src="/assets/js/script.js"></script>
</body> </body>
</html> </html>

View File

@ -22,10 +22,29 @@
{% endif %} {% endif %}
<li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}/edit">Edit</a></li> <li><a class="dropdown-item" href="/{{ sub_path }}/{{ book.id }}/edit">Edit</a></li>
<li> <li>
<form method="post" action="/{{ sub_path }}/{{ book.id }}/delete" class="mb-0"> <a class="dropdown-item" href="#" data-bs-toggle="modal" data-bs-target="#deleteUserModal{{ book.id }}">Delete</a>
<input class="dropdown-item" type="submit" value="Delete">
</form>
</li> </li>
</ul> </ul>
</div> </div>
<!-- Modal -->
<div class="modal fade" id="deleteUserModal{{ book.id }}" tabindex="-1" aria-labelledby="deleteUserModal{{ book.id }}Label" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h1 class="modal-title fs-5" id="exampleModalLabel">Confirmation</h1>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Are you sure ?</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<form method="post" action="/{{ sub_path }}/{{ book.id }}/delete" class="m-0">
<input class="btn btn-danger" type="submit" value="Delete">
</form>
</div>
</div>
</div>
</div>
{% endmacro %} {% endmacro %}