@@ -6,7 +6,9 @@ use crate::auth::{filter_visible_projects, get_user_from_headers};
66use crate :: database:: models:: notification_item:: NotificationBuilder ;
77use crate :: database:: models:: project_item:: { DBGalleryItem , DBModCategory } ;
88use crate :: database:: models:: thread_item:: ThreadMessageBuilder ;
9- use crate :: database:: models:: { DBTeamMember , ids as db_ids, image_item} ;
9+ use crate :: database:: models:: {
10+ DBModerationLock , DBTeamMember , ids as db_ids, image_item,
11+ } ;
1012use crate :: database:: redis:: RedisPool ;
1113use crate :: database:: { self , models as db_models} ;
1214use crate :: file_hosting:: { FileHost , FileHostPublicity } ;
@@ -368,6 +370,23 @@ pub async fn project_edit(
368370 ) ) ;
369371 }
370372
373+ // If a moderator is completing a review (changing from Processing to another status),
374+ // check if another moderator holds an active lock on this project
375+ if user. role . is_mod ( )
376+ && project_item. inner . status == ProjectStatus :: Processing
377+ && status != & ProjectStatus :: Processing
378+ && let Some ( lock) =
379+ DBModerationLock :: get_with_user ( project_item. inner . id , & pool)
380+ . await ?
381+ && lock. moderator_id != db_ids:: DBUserId :: from ( user. id )
382+ && !lock. expired
383+ {
384+ return Err ( ApiError :: CustomAuthentication ( format ! (
385+ "This project is currently being moderated by @{}. Please wait for them to finish or for the lock to expire." ,
386+ lock. moderator_username
387+ ) ) ) ;
388+ }
389+
371390 if status == & ProjectStatus :: Processing {
372391 if project_item. versions . is_empty ( ) {
373392 return Err ( ApiError :: InvalidInput ( String :: from (
0 commit comments