auto_backup.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. package backup
  2. import (
  3. "net/http"
  4. "github.com/0xJacky/Nginx-UI/internal/backup"
  5. "github.com/0xJacky/Nginx-UI/internal/cron"
  6. "github.com/0xJacky/Nginx-UI/model"
  7. "github.com/gin-gonic/gin"
  8. "github.com/uozi-tech/cosy"
  9. "github.com/uozi-tech/cosy/logger"
  10. )
  11. // GetAutoBackupList retrieves a paginated list of auto backup configurations.
  12. // This endpoint supports fuzzy search by backup name and filtering by backup type and enabled status.
  13. //
  14. // Query Parameters:
  15. // - page: Page number for pagination
  16. // - page_size: Number of items per page
  17. // - name: Fuzzy search filter for backup name
  18. // - backup_type: Filter by backup type (nginx_config/nginx_ui_config/both_config/custom_dir)
  19. // - enabled: Filter by enabled status (true/false)
  20. //
  21. // Response: Paginated list of auto backup configurations
  22. func GetAutoBackupList(c *gin.Context) {
  23. cosy.Core[model.AutoBackup](c).
  24. SetFussy("name").
  25. SetEqual("backup_type", "enabled", "storage_type", "last_backup_status").
  26. PagingList()
  27. }
  28. // CreateAutoBackup creates a new auto backup configuration with comprehensive validation.
  29. // This endpoint validates all required fields, path permissions, and S3 configuration.
  30. //
  31. // Request Body: AutoBackup model with required fields
  32. // Response: Created auto backup configuration
  33. func CreateAutoBackup(c *gin.Context) {
  34. ctx := cosy.Core[model.AutoBackup](c).SetValidRules(gin.H{
  35. "name": "required",
  36. "backup_type": "required",
  37. "storage_type": "required",
  38. "storage_path": "required",
  39. "cron_expression": "required",
  40. "enabled": "omitempty",
  41. "backup_path": "omitempty",
  42. "s3_endpoint": "omitempty",
  43. "s3_access_key_id": "omitempty",
  44. "s3_secret_access_key": "omitempty",
  45. "s3_bucket": "omitempty",
  46. "s3_region": "omitempty",
  47. }).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  48. // Validate backup configuration before creation
  49. if err := backup.ValidateAutoBackupConfig(&ctx.Model); err != nil {
  50. ctx.AbortWithError(err)
  51. return
  52. }
  53. })
  54. ctx.Create()
  55. // Register cron job only if the backup is enabled
  56. if ctx.Model.Enabled {
  57. if err := cron.AddAutoBackupJob(ctx.Model.ID, ctx.Model.CronExpression); err != nil {
  58. logger.Errorf("Failed to add auto backup job %d: %v", ctx.Model.ID, err)
  59. }
  60. }
  61. }
  62. // GetAutoBackup retrieves a single auto backup configuration by ID.
  63. //
  64. // Path Parameters:
  65. // - id: Auto backup configuration ID
  66. //
  67. // Response: Auto backup configuration details
  68. func GetAutoBackup(c *gin.Context) {
  69. cosy.Core[model.AutoBackup](c).Get()
  70. }
  71. // ModifyAutoBackup updates an existing auto backup configuration with validation.
  72. // This endpoint performs the same validation as creation for modified fields.
  73. //
  74. // Path Parameters:
  75. // - id: Auto backup configuration ID
  76. //
  77. // Request Body: Partial AutoBackup model with fields to update
  78. // Response: Updated auto backup configuration
  79. func ModifyAutoBackup(c *gin.Context) {
  80. ctx := cosy.Core[model.AutoBackup](c).SetValidRules(gin.H{
  81. "name": "omitempty",
  82. "backup_type": "omitempty",
  83. "storage_type": "omitempty",
  84. "storage_path": "omitempty",
  85. "cron_expression": "omitempty",
  86. "backup_path": "omitempty",
  87. "enabled": "omitempty",
  88. "s3_endpoint": "omitempty",
  89. "s3_access_key_id": "omitempty",
  90. "s3_secret_access_key": "omitempty",
  91. "s3_bucket": "omitempty",
  92. "s3_region": "omitempty",
  93. }).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  94. // Validate backup configuration before modification
  95. if err := backup.ValidateAutoBackupConfig(&ctx.Model); err != nil {
  96. ctx.AbortWithError(err)
  97. return
  98. }
  99. })
  100. ctx.Modify()
  101. // Update cron job based on enabled status
  102. if ctx.Model.Enabled {
  103. if err := cron.UpdateAutoBackupJob(ctx.Model.ID, ctx.Model.CronExpression); err != nil {
  104. logger.Errorf("Failed to update auto backup job %d: %v", ctx.Model.ID, err)
  105. }
  106. } else {
  107. if err := cron.RemoveAutoBackupJob(ctx.Model.ID); err != nil {
  108. logger.Errorf("Failed to remove auto backup job %d: %v", ctx.Model.ID, err)
  109. }
  110. }
  111. }
  112. // DestroyAutoBackup deletes an auto backup configuration and removes its cron job.
  113. // This endpoint ensures proper cleanup of both database records and scheduled tasks.
  114. //
  115. // Path Parameters:
  116. // - id: Auto backup configuration ID
  117. //
  118. // Response: Success confirmation
  119. func DestroyAutoBackup(c *gin.Context) {
  120. cosy.Core[model.AutoBackup](c).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  121. // Remove cron job before deleting the backup task
  122. if err := cron.RemoveAutoBackupJob(ctx.Model.ID); err != nil {
  123. logger.Errorf("Failed to remove auto backup job %d: %v", ctx.Model.ID, err)
  124. }
  125. }).Destroy()
  126. }
  127. // TestS3Connection tests the S3 connection for auto backup configuration.
  128. // This endpoint allows users to verify their S3 settings before saving the configuration.
  129. //
  130. // Request Body: AutoBackup model with S3 configuration
  131. // Response: Success confirmation or error details
  132. func TestS3Connection(c *gin.Context) {
  133. var autoBackup model.AutoBackup
  134. if !cosy.BindAndValid(c, &autoBackup) {
  135. return
  136. }
  137. // Validate S3 configuration
  138. if err := backup.ValidateS3Config(&autoBackup); err != nil {
  139. cosy.ErrHandler(c, err)
  140. return
  141. }
  142. // Test S3 connection
  143. if err := backup.TestS3ConnectionForConfig(&autoBackup); err != nil {
  144. cosy.ErrHandler(c, err)
  145. return
  146. }
  147. c.JSON(http.StatusOK, gin.H{"message": "S3 connection test successful"})
  148. }
  149. // RestoreAutoBackup restores a soft-deleted auto backup configuration.
  150. // This endpoint restores the backup configuration and re-registers the cron job if enabled.
  151. //
  152. // Path Parameters:
  153. // - id: Auto backup configuration ID to restore
  154. //
  155. // Response: Success confirmation
  156. func RestoreAutoBackup(c *gin.Context) {
  157. var autoBackup model.AutoBackup
  158. if err := c.ShouldBindUri(&autoBackup); err != nil {
  159. cosy.ErrHandler(c, err)
  160. return
  161. }
  162. // Restore the backup configuration
  163. if err := backup.RestoreAutoBackup(autoBackup.ID); err != nil {
  164. cosy.ErrHandler(c, err)
  165. return
  166. }
  167. // Get the restored backup configuration to check if it's enabled
  168. restoredBackup, err := backup.GetAutoBackupByID(autoBackup.ID)
  169. if err != nil {
  170. logger.Errorf("Failed to get restored auto backup %d: %v", autoBackup.ID, err)
  171. } else if restoredBackup.Enabled {
  172. // Register cron job if the backup is enabled
  173. if err := cron.AddAutoBackupJob(restoredBackup.ID, restoredBackup.CronExpression); err != nil {
  174. logger.Errorf("Failed to add auto backup job %d after restore: %v", restoredBackup.ID, err)
  175. }
  176. }
  177. c.JSON(http.StatusOK, gin.H{"message": "Auto backup restored successfully"})
  178. }