@@ -643,6 +643,7 @@ public function update_by_uuid(Request $request)
643643 'database_backup_retention_amount_s3 ' => ['type ' => 'integer ' , 'description ' => 'Number of backups to retain in S3 ' ],
644644 'database_backup_retention_days_s3 ' => ['type ' => 'integer ' , 'description ' => 'Number of days to retain backups in S3 ' ],
645645 'database_backup_retention_max_storage_s3 ' => ['type ' => 'integer ' , 'description ' => 'Max storage (MB) for S3 backups ' ],
646+ 'timeout ' => ['type ' => 'integer ' , 'description ' => 'Backup job timeout in seconds (min: 60, max: 36000) ' , 'default ' => 3600 ],
646647 ],
647648 ),
648649 )
@@ -679,7 +680,7 @@ public function update_by_uuid(Request $request)
679680 )]
680681 public function create_backup (Request $ request )
681682 {
682- $ backupConfigFields = ['save_s3 ' , 'enabled ' , 'dump_all ' , 'frequency ' , 'databases_to_backup ' , 'database_backup_retention_amount_locally ' , 'database_backup_retention_days_locally ' , 'database_backup_retention_max_storage_locally ' , 'database_backup_retention_amount_s3 ' , 'database_backup_retention_days_s3 ' , 'database_backup_retention_max_storage_s3 ' , 's3_storage_uuid ' ];
683+ $ backupConfigFields = ['save_s3 ' , 'enabled ' , 'dump_all ' , 'frequency ' , 'databases_to_backup ' , 'database_backup_retention_amount_locally ' , 'database_backup_retention_days_locally ' , 'database_backup_retention_max_storage_locally ' , 'database_backup_retention_amount_s3 ' , 'database_backup_retention_days_s3 ' , 'database_backup_retention_max_storage_s3 ' , 's3_storage_uuid ' , ' timeout ' ];
683684
684685 $ teamId = getTeamIdFromToken ();
685686 if (is_null ($ teamId )) {
@@ -706,6 +707,7 @@ public function create_backup(Request $request)
706707 'database_backup_retention_amount_s3 ' => 'integer|min:0 ' ,
707708 'database_backup_retention_days_s3 ' => 'integer|min:0 ' ,
708709 'database_backup_retention_max_storage_s3 ' => 'integer|min:0 ' ,
710+ 'timeout ' => 'integer|min:60|max:36000 ' ,
709711 ]);
710712
711713 if ($ validator ->fails ()) {
@@ -880,6 +882,7 @@ public function create_backup(Request $request)
880882 'database_backup_retention_amount_s3 ' => ['type ' => 'integer ' , 'description ' => 'Retention amount of the backup in s3 ' ],
881883 'database_backup_retention_days_s3 ' => ['type ' => 'integer ' , 'description ' => 'Retention days of the backup in s3 ' ],
882884 'database_backup_retention_max_storage_s3 ' => ['type ' => 'integer ' , 'description ' => 'Max storage of the backup in S3 ' ],
885+ 'timeout ' => ['type ' => 'integer ' , 'description ' => 'Backup job timeout in seconds (min: 60, max: 36000) ' , 'default ' => 3600 ],
883886 ],
884887 ),
885888 )
@@ -909,7 +912,7 @@ public function create_backup(Request $request)
909912 )]
910913 public function update_backup (Request $ request )
911914 {
912- $ backupConfigFields = ['save_s3 ' , 'enabled ' , 'dump_all ' , 'frequency ' , 'databases_to_backup ' , 'database_backup_retention_amount_locally ' , 'database_backup_retention_days_locally ' , 'database_backup_retention_max_storage_locally ' , 'database_backup_retention_amount_s3 ' , 'database_backup_retention_days_s3 ' , 'database_backup_retention_max_storage_s3 ' , 's3_storage_uuid ' ];
915+ $ backupConfigFields = ['save_s3 ' , 'enabled ' , 'dump_all ' , 'frequency ' , 'databases_to_backup ' , 'database_backup_retention_amount_locally ' , 'database_backup_retention_days_locally ' , 'database_backup_retention_max_storage_locally ' , 'database_backup_retention_amount_s3 ' , 'database_backup_retention_days_s3 ' , 'database_backup_retention_max_storage_s3 ' , 's3_storage_uuid ' , ' timeout ' ];
913916
914917 $ teamId = getTeamIdFromToken ();
915918 if (is_null ($ teamId )) {
@@ -927,13 +930,14 @@ public function update_backup(Request $request)
927930 'dump_all ' => 'boolean ' ,
928931 's3_storage_uuid ' => 'string|exists:s3_storages,uuid|nullable ' ,
929932 'databases_to_backup ' => 'string|nullable ' ,
930- 'frequency ' => 'string|in:every_minute,hourly,daily,weekly,monthly,yearly ' ,
933+ 'frequency ' => 'string ' ,
931934 'database_backup_retention_amount_locally ' => 'integer|min:0 ' ,
932935 'database_backup_retention_days_locally ' => 'integer|min:0 ' ,
933936 'database_backup_retention_max_storage_locally ' => 'integer|min:0 ' ,
934937 'database_backup_retention_amount_s3 ' => 'integer|min:0 ' ,
935938 'database_backup_retention_days_s3 ' => 'integer|min:0 ' ,
936939 'database_backup_retention_max_storage_s3 ' => 'integer|min:0 ' ,
940+ 'timeout ' => 'integer|min:60|max:36000 ' ,
937941 ]);
938942 if ($ validator ->fails ()) {
939943 return response ()->json ([
@@ -960,6 +964,17 @@ public function update_backup(Request $request)
960964
961965 $ this ->authorize ('update ' , $ database );
962966
967+ // Validate frequency is a valid cron expression
968+ if ($ request ->filled ('frequency ' )) {
969+ $ isValid = validate_cron_expression ($ request ->frequency );
970+ if (! $ isValid ) {
971+ return response ()->json ([
972+ 'message ' => 'Validation failed. ' ,
973+ 'errors ' => ['frequency ' => ['Invalid cron expression or frequency format. ' ]],
974+ ], 422 );
975+ }
976+ }
977+
963978 if ($ request ->boolean ('save_s3 ' ) && ! $ request ->filled ('s3_storage_uuid ' )) {
964979 return response ()->json ([
965980 'message ' => 'Validation failed. ' ,
0 commit comments