@@ -2,20 +2,24 @@ package handlers
22
33import (
44 "fmt"
5+ "path"
56 "regexp"
67 "strings"
78
89 "github.com/celestix/gotgproto/dispatcher"
910 "github.com/celestix/gotgproto/ext"
1011 "github.com/charmbracelet/log"
1112 "github.com/gotd/td/tg"
13+ "github.com/krau/SaveAny-Bot/client/bot/handlers/utils/msgelem"
1214 "github.com/krau/SaveAny-Bot/common/i18n"
1315 "github.com/krau/SaveAny-Bot/common/i18n/i18nk"
1416 "github.com/krau/SaveAny-Bot/common/utils/strutil"
1517 "github.com/krau/SaveAny-Bot/common/utils/tgutil"
1618 "github.com/krau/SaveAny-Bot/core"
17- "github.com/krau/SaveAny-Bot/core/tasks/batchimport"
19+ "github.com/krau/SaveAny-Bot/core/tasks/transfer"
20+ "github.com/krau/SaveAny-Bot/pkg/enums/tasktype"
1821 "github.com/krau/SaveAny-Bot/pkg/storagetypes"
22+ "github.com/krau/SaveAny-Bot/pkg/tcbdata"
1923 "github.com/krau/SaveAny-Bot/storage"
2024 "github.com/rs/xid"
2125)
@@ -38,14 +42,8 @@ func handleTransferCmd(ctx *ext.Context, update *ext.Update) error {
3842 sourceStorageName := sourceParts [0 ]
3943 sourcePath := sourceParts [1 ]
4044
41- // Parse target: storage_name:/path
42- targetParts := strings .SplitN (args [2 ], ":" , 2 )
43- if len (targetParts ) != 2 {
44- ctx .Reply (update , ext .ReplyTextString (i18n .T (i18nk .BotMsgTransferErrorInvalidTarget , nil )), nil )
45- return dispatcher .EndGroups
46- }
47- targetStorageName := targetParts [0 ]
48- targetPath := targetParts [1 ]
45+ // Parse target path (without storage name)
46+ targetPath := args [2 ]
4947
5048 userID := update .GetUserChat ().GetID ()
5149
@@ -78,17 +76,6 @@ func handleTransferCmd(ctx *ext.Context, update *ext.Update) error {
7876 return dispatcher .EndGroups
7977 }
8078
81- // Get target storage
82- targetStorage , err := storage .GetStorageByUserIDAndName (ctx , userID , targetStorageName )
83- if err != nil {
84- logger .Errorf ("Failed to get target storage by user ID and name: %s" , err )
85- ctx .Reply (update , ext .ReplyTextString (i18n .T (i18nk .BotMsgTransferErrorTargetNotFound , map [string ]any {
86- "StorageName" : targetStorageName ,
87- "Error" : err ,
88- })), nil )
89- return dispatcher .EndGroups
90- }
91-
9279 // Fetch file list
9380 replied , err := ctx .Reply (update , ext .ReplyTextString (i18n .T (i18nk .BotMsgTransferInfoFetchingFiles , nil )), nil )
9481 if err != nil {
@@ -138,36 +125,133 @@ func handleTransferCmd(ctx *ext.Context, update *ext.Update) error {
138125 return dispatcher .EndGroups
139126 }
140127
141- // Create task elements
142- elems := make ([]batchimport. TaskElement , 0 , len (filteredFiles ))
128+ // Prepare file paths for callback data
129+ filePaths := make ([]string , 0 , len (filteredFiles ))
143130 var totalSize int64
144131 for _ , file := range filteredFiles {
145- elem := batchimport .NewTaskElement (sourceStorage , file , targetStorage , targetPath )
146- elems = append (elems , * elem )
132+ filePaths = append (filePaths , file .Path )
147133 totalSize += file .Size
148134 }
149135
136+ // Build storage selection keyboard
137+ markup , err := msgelem .BuildAddSelectStorageKeyboard (storage .GetUserStorages (ctx , userID ), tcbdata.Add {
138+ TaskType : tasktype .TaskTypeTransfer ,
139+ TransferSourceStorName : sourceStorageName ,
140+ TransferSourcePath : sourcePath ,
141+ TransferFiles : filePaths ,
142+ TransferTargetPath : targetPath ,
143+ })
144+ if err != nil {
145+ logger .Errorf ("Failed to build storage selection keyboard: %s" , err )
146+ ctx .EditMessage (update .EffectiveChat ().GetID (), & tg.MessagesEditMessageRequest {
147+ ID : replied .ID ,
148+ Message : i18n .T (i18nk .BotMsgTransferErrorBuildStorageSelectKeyboardFailed , map [string ]any {"Error" : err }),
149+ })
150+ return dispatcher .EndGroups
151+ }
152+
153+ ctx .EditMessage (update .EffectiveChat ().GetID (), & tg.MessagesEditMessageRequest {
154+ ID : replied .ID ,
155+ Message : i18n .T (i18nk .BotMsgTransferInfoFilesSelectStorage , map [string ]any {
156+ "Count" : len (filteredFiles ),
157+ "SizeMB" : fmt .Sprintf ("%.2f" , float64 (totalSize )/ (1024 * 1024 )),
158+ }),
159+ ReplyMarkup : markup ,
160+ })
161+
162+ return dispatcher .EndGroups
163+ }
164+
165+ func handleTransferCallback (ctx * ext.Context , userID int64 , targetStorage storage.Storage , dirPath string , data tcbdata.Add , msgID int ) error {
166+ logger := log .FromContext (ctx )
167+
168+ // Get source storage
169+ sourceStorage , err := storage .GetStorageByUserIDAndName (ctx , userID , data .TransferSourceStorName )
170+ if err != nil {
171+ logger .Errorf ("Failed to get source storage: %s" , err )
172+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
173+ ID : msgID ,
174+ Message : i18n .T (i18nk .BotMsgTransferErrorStorageNotFound , map [string ]any {"StorageName" : data .TransferSourceStorName , "Error" : err }),
175+ })
176+ return dispatcher .EndGroups
177+ }
178+
179+ // Check if source storage supports listing
180+ listable , ok := sourceStorage .(storage.StorageListable )
181+ if ! ok {
182+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
183+ ID : msgID ,
184+ Message : i18n .T (i18nk .BotMsgTransferErrorStorageNotListable , map [string ]any {"StorageName" : data .TransferSourceStorName }),
185+ })
186+ return dispatcher .EndGroups
187+ }
188+
189+ // Re-fetch files to get FileInfo (since we only stored paths)
190+ // This is necessary to get size and other metadata
191+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
192+ ID : msgID ,
193+ Message : i18n .T (i18nk .BotMsgTransferInfoFetchingFiles , nil ),
194+ })
195+
196+ allFiles , err := listable .ListFiles (ctx , data .TransferSourcePath )
197+ if err != nil {
198+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
199+ ID : msgID ,
200+ Message : i18n .T (i18nk .BotMsgTransferErrorListFilesFailed , map [string ]any {"Error" : err }),
201+ })
202+ return dispatcher .EndGroups
203+ }
204+
205+ // Create a map for quick lookup
206+ fileMap := make (map [string ]storagetypes.FileInfo )
207+ for _ , file := range allFiles {
208+ fileMap [file .Path ] = file
209+ }
210+
211+ // Build task elements for the selected files
212+ targetPath := path .Join (dirPath , data .TransferTargetPath )
213+ elems := make ([]transfer.TaskElement , 0 , len (data .TransferFiles ))
214+ var totalSize int64
215+ for _ , filePath := range data .TransferFiles {
216+ fileInfo , ok := fileMap [filePath ]
217+ if ! ok {
218+ logger .Warnf ("File not found in source storage: %s" , filePath )
219+ continue
220+ }
221+ elem := transfer .NewTaskElement (sourceStorage , fileInfo , targetStorage , targetPath )
222+ elems = append (elems , * elem )
223+ totalSize += fileInfo .Size
224+ }
225+
226+ if len (elems ) == 0 {
227+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
228+ ID : msgID ,
229+ Message : i18n .T (i18nk .BotMsgTransferErrorNoFilesToTransfer , nil ),
230+ })
231+ return dispatcher .EndGroups
232+ }
233+
150234 // Create and add task
151235 taskID := xid .New ().String ()
152236 injectCtx := tgutil .ExtWithContext (ctx .Context , ctx )
153- task := batchimport . NewBatchImportTask (
237+ task := transfer . NewTransferTask (
154238 taskID ,
155239 injectCtx ,
156240 elems ,
157- batchimport .NewProgressTracker (replied . ID , userID ),
241+ transfer .NewProgressTracker (msgID , userID ),
158242 true , // IgnoreErrors
159243 )
160244
161245 if err := core .AddTask (injectCtx , task ); err != nil {
162- ctx .EditMessage (update . EffectiveChat (). GetID () , & tg.MessagesEditMessageRequest {
163- ID : replied . ID ,
246+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
247+ ID : msgID ,
164248 Message : i18n .T (i18nk .BotMsgTransferErrorAddTaskFailed , map [string ]any {"Error" : err }),
165249 })
166250 return dispatcher .EndGroups
167251 }
168252
169- ctx .EditMessage (update . EffectiveChat (). GetID () , & tg.MessagesEditMessageRequest {
170- ID : replied . ID ,
253+ ctx .EditMessage (userID , & tg.MessagesEditMessageRequest {
254+ ID : msgID ,
171255 Message : i18n .T (i18nk .BotMsgTransferInfoTaskAdded , map [string ]any {
172256 "Count" : len (elems ),
173257 "SizeMB" : fmt .Sprintf ("%.2f" , float64 (totalSize )/ (1024 * 1024 )),
0 commit comments