auto_backup.go 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196
  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. 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. }).ExecutedHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  54. // Register cron job only if the backup is enabled
  55. if ctx.Model.Enabled {
  56. if err := cron.AddAutoBackupJob(ctx.Model.ID, ctx.Model.CronExpression); err != nil {
  57. ctx.AbortWithError(err)
  58. return
  59. }
  60. }
  61. }).Create()
  62. }
  63. // GetAutoBackup retrieves a single auto backup configuration by ID.
  64. //
  65. // Path Parameters:
  66. // - id: Auto backup configuration ID
  67. //
  68. // Response: Auto backup configuration details
  69. func GetAutoBackup(c *gin.Context) {
  70. cosy.Core[model.AutoBackup](c).Get()
  71. }
  72. // ModifyAutoBackup updates an existing auto backup configuration with validation.
  73. // This endpoint performs the same validation as creation for modified fields.
  74. //
  75. // Path Parameters:
  76. // - id: Auto backup configuration ID
  77. //
  78. // Request Body: Partial AutoBackup model with fields to update
  79. // Response: Updated auto backup configuration
  80. func ModifyAutoBackup(c *gin.Context) {
  81. cosy.Core[model.AutoBackup](c).SetValidRules(gin.H{
  82. "name": "omitempty",
  83. "backup_type": "omitempty",
  84. "storage_type": "omitempty",
  85. "storage_path": "omitempty",
  86. "cron_expression": "omitempty",
  87. "backup_path": "omitempty",
  88. "enabled": "omitempty",
  89. "s3_endpoint": "omitempty",
  90. "s3_access_key_id": "omitempty",
  91. "s3_secret_access_key": "omitempty",
  92. "s3_bucket": "omitempty",
  93. "s3_region": "omitempty",
  94. }).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  95. // Validate backup configuration before modification
  96. if err := backup.ValidateAutoBackupConfig(&ctx.Model); err != nil {
  97. ctx.AbortWithError(err)
  98. return
  99. }
  100. }).ExecutedHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  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. ctx.AbortWithError(err)
  105. return
  106. }
  107. } else {
  108. if err := cron.RemoveAutoBackupJob(ctx.Model.ID); err != nil {
  109. ctx.AbortWithError(err)
  110. return
  111. }
  112. }
  113. }).Modify()
  114. }
  115. // DestroyAutoBackup deletes an auto backup configuration and removes its cron job.
  116. // This endpoint ensures proper cleanup of both database records and scheduled tasks.
  117. //
  118. // Path Parameters:
  119. // - id: Auto backup configuration ID
  120. //
  121. // Response: Success confirmation
  122. func DestroyAutoBackup(c *gin.Context) {
  123. cosy.Core[model.AutoBackup](c).BeforeExecuteHook(func(ctx *cosy.Ctx[model.AutoBackup]) {
  124. // Remove cron job before deleting the backup task
  125. if err := cron.RemoveAutoBackupJob(ctx.Model.ID); err != nil {
  126. logger.Errorf("Failed to remove auto backup job %d: %v", ctx.Model.ID, err)
  127. }
  128. }).Destroy()
  129. }
  130. // TestS3Connection tests the S3 connection for auto backup configuration.
  131. // This endpoint allows users to verify their S3 settings before saving the configuration.
  132. //
  133. // Request Body: AutoBackup model with S3 configuration
  134. // Response: Success confirmation or error details
  135. func TestS3Connection(c *gin.Context) {
  136. var autoBackup model.AutoBackup
  137. if !cosy.BindAndValid(c, &autoBackup) {
  138. return
  139. }
  140. // Validate S3 configuration
  141. if err := backup.ValidateS3Config(&autoBackup); err != nil {
  142. cosy.ErrHandler(c, err)
  143. return
  144. }
  145. // Test S3 connection
  146. if err := backup.TestS3ConnectionForConfig(&autoBackup); err != nil {
  147. cosy.ErrHandler(c, err)
  148. return
  149. }
  150. c.JSON(http.StatusOK, gin.H{"message": "S3 connection test successful"})
  151. }
  152. // RestoreAutoBackup restores a soft-deleted auto backup configuration.
  153. // This endpoint restores the backup configuration and re-registers the cron job if enabled.
  154. //
  155. // Path Parameters:
  156. // - id: Auto backup configuration ID to restore
  157. //
  158. // Response: Success confirmation
  159. func RestoreAutoBackup(c *gin.Context) {
  160. var autoBackup model.AutoBackup
  161. if err := c.ShouldBindUri(&autoBackup); err != nil {
  162. cosy.ErrHandler(c, err)
  163. return
  164. }
  165. // Restore the backup configuration
  166. if err := backup.RestoreAutoBackup(autoBackup.ID); err != nil {
  167. cosy.ErrHandler(c, err)
  168. return
  169. }
  170. // Get the restored backup configuration to check if it's enabled
  171. restoredBackup, err := backup.GetAutoBackupByID(autoBackup.ID)
  172. if err != nil {
  173. logger.Errorf("Failed to get restored auto backup %d: %v", autoBackup.ID, err)
  174. } else if restoredBackup.Enabled {
  175. // Register cron job if the backup is enabled
  176. if err := cron.AddAutoBackupJob(restoredBackup.ID, restoredBackup.CronExpression); err != nil {
  177. logger.Errorf("Failed to add auto backup job %d after restore: %v", restoredBackup.ID, err)
  178. }
  179. }
  180. c.JSON(http.StatusOK, gin.H{"message": "Auto backup restored successfully"})
  181. }