@@ -2,8 +2,11 @@ use askama::Template;
22use askama_web:: WebTemplate ;
33use axum:: extract:: Form ;
44use axum:: extract:: Path ;
5+ use axum:: extract:: Query ;
6+ use axum:: response:: { IntoResponse , Response } ;
57use axum_extra:: extract:: CookieJar ;
68use serde:: { Deserialize , Serialize } ;
9+ use serde_with:: serde_as;
710
811use crate :: database:: { content_folder, torrent} ;
912use crate :: state:: AppStateContext ;
@@ -17,6 +20,19 @@ pub struct ContentFolderForm {
1720 pub name : String ,
1821}
1922
23+ /// A request to move a torrent around in the categories/folders.
24+ ///
25+ /// When validate is set, the requested folder is set to the database.
26+ #[ derive( Clone , Debug , Deserialize ) ]
27+ #[ serde_as]
28+ pub struct MoveTorrentQuery {
29+ #[ serde( default ) ]
30+ #[ serde_as( as = "DeserializeFromStr" ) ]
31+ pub moving_id : Option < i32 > ,
32+ #[ serde( default ) ]
33+ pub moving_validate : bool ,
34+ }
35+
2036#[ derive( Template , WebTemplate ) ]
2137#[ template( path = "content_folders/show.html" ) ]
2238pub struct ContentFolderShowTemplate {
@@ -33,6 +49,8 @@ pub struct ContentFolderShowTemplate {
3349 pub ancestors : Vec < content_folder:: Model > ,
3450 /// Operation status for UI confirmation (Cookie)
3551 pub flash : Option < OperationStatus > ,
52+ /// Torrent being moved (if any)
53+ pub moving_torrent : Option < torrent:: Model > ,
3654}
3755
3856impl ContentFolderShowTemplate {
@@ -42,6 +60,7 @@ impl ContentFolderShowTemplate {
4260 children,
4361 folder,
4462 torrents,
63+ moving_torrent,
4564 } = folder;
4665
4766 Self {
@@ -51,6 +70,7 @@ impl ContentFolderShowTemplate {
5170 torrents,
5271 ancestors,
5372 state : context,
73+ moving_torrent,
5474 }
5575 }
5676}
@@ -65,10 +85,40 @@ pub async fn show(
6585 context : AppStateContext ,
6686 Path ( id) : Path < i32 > ,
6787 status : StatusCookie ,
68- ) -> Result < FlashTemplate < ContentFolderShowTemplate > , AppStateError > {
88+ Query ( moving) : Query < MoveTorrentQuery > ,
89+ ) -> Result < Response , AppStateError > {
6990 // 404 if requested ID does not exist
70- let view = content_folder:: FolderView :: from_id ( & context. db . content_folder ( ) , id) . await ?;
71- Ok ( status. with_template ( ContentFolderShowTemplate :: new ( context, view) ) )
91+ let view =
92+ content_folder:: FolderView :: from_id ( & context. db . content_folder ( ) , id, moving. moving_id )
93+ . await ?;
94+
95+ if view. moving_torrent . is_some ( ) && moving. moving_validate {
96+ // Request to effectively move the torrent to this folder
97+ // Once done, redirect to the same page
98+ if let Err ( e) = context
99+ . db
100+ . torrent ( )
101+ . move_folder (
102+ view. moving_torrent . clone ( ) . unwrap ( ) ,
103+ view. folder . as_ref ( ) . unwrap ( ) ,
104+ )
105+ . await
106+ {
107+ return Ok ( OperationStatus :: error ( e)
108+ . with_template ( ContentFolderShowTemplate :: new ( context, view) )
109+ . into_response ( ) ) ;
110+ }
111+
112+ // Success! Perform a redirection
113+ return Ok ( status
114+ . with_success ( "Torrent successfully moved" . to_string ( ) )
115+ . redirect ( & format ! ( "/folders/{}" , view. folder. as_ref( ) . unwrap( ) . id) )
116+ . into_response ( ) ) ;
117+ }
118+
119+ Ok ( status
120+ . with_template ( ContentFolderShowTemplate :: new ( context, view) )
121+ . into_response ( ) )
72122}
73123
74124pub async fn index (
@@ -112,14 +162,13 @@ pub async fn create_folder(
112162 }
113163}
114164
115- // TODO: create top-level
116165pub async fn create_subfolder (
117166 context : AppStateContext ,
118167 jar : CookieJar ,
119168 Path ( id) : Path < i32 > ,
120169 Form ( form) : Form < ContentFolderForm > ,
121170) -> Result < Result < FlashRedirect , ContentFolderShowTemplate > , AppStateError > {
122- let view = content_folder:: FolderView :: from_id ( & context. db . content_folder ( ) , id) . await ?;
171+ let view = content_folder:: FolderView :: from_id ( & context. db . content_folder ( ) , id, None ) . await ?;
123172 match context
124173 . db
125174 . content_folder ( )
0 commit comments