package transport import ( "fmt" "io" "net/http" "strconv" "time" "github.com/gin-gonic/gin" "github.com/geo-platform/tenant-api/internal/ops/app" "github.com/geo-platform/tenant-api/internal/shared/response" ) type siteDomainMappingRequest struct { RegistrableDomain string `json:"registrable_domain" binding:"required"` SiteKey string `json:"site_key"` SiteName string `json:"site_name" binding:"required"` IsActive *bool `json:"is_active"` } type setSiteDomainMappingActiveRequest struct { IsActive bool `json:"is_active"` } func listSiteDomainMappingsHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) size, _ := strconv.Atoi(c.DefaultQuery("size", "20")) result, err := svc.List(c.Request.Context(), app.SiteDomainMappingListInput{ Keyword: c.Query("keyword"), IsActive: parseOptionalBoolQuery(c.Query("is_active")), Page: page, Size: size, }) if err != nil { response.Error(c, err) return } response.Success(c, result) } } func exportSiteDomainMappingsHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { data, err := svc.ExportCSV(c.Request.Context(), actorFromGin(c), app.SiteDomainMappingListInput{ Keyword: c.Query("keyword"), IsActive: parseOptionalBoolQuery(c.Query("is_active")), }) if err != nil { response.Error(c, err) return } fileName := fmt.Sprintf("site-domain-mappings-%s.csv", time.Now().Format("20060102150405")) c.Header("Content-Type", "text/csv; charset=utf-8") c.Header("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, fileName)) c.Data(http.StatusOK, "text/csv; charset=utf-8", data) } } func importSiteDomainMappingsHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { fileHeader, err := c.FormFile("file") if err != nil { response.Error(c, response.ErrBadRequest(40057, "missing_site_domain_mapping_import_file", "请选择 CSV 文件")) return } file, err := fileHeader.Open() if err != nil { response.Error(c, err) return } defer file.Close() content, err := io.ReadAll(io.LimitReader(file, 2*1024*1024+1)) if err != nil { response.Error(c, err) return } if len(content) > 2*1024*1024 { response.Error(c, response.ErrBadRequest(40058, "site_domain_mapping_import_file_too_large", "CSV 文件不能超过 2MB")) return } result, err := svc.ImportCSV(c.Request.Context(), actorFromGin(c), app.SiteDomainMappingImportInput{ Content: content, }) if err != nil { response.Error(c, err) return } response.Success(c, result) } } func createSiteDomainMappingHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { var body siteDomainMappingRequest if err := c.ShouldBindJSON(&body); err != nil { response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error())) return } result, err := svc.Create(c.Request.Context(), actorFromGin(c), body.toInput()) if err != nil { response.Error(c, err) return } response.Success(c, result) } } func updateSiteDomainMappingHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { id, err := parseIDParam(c) if err != nil { response.Error(c, err) return } var body siteDomainMappingRequest if err := c.ShouldBindJSON(&body); err != nil { response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error())) return } result, err := svc.Update(c.Request.Context(), actorFromGin(c), id, body.toInput()) if err != nil { response.Error(c, err) return } response.Success(c, result) } } func setSiteDomainMappingActiveHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { id, err := parseIDParam(c) if err != nil { response.Error(c, err) return } var body setSiteDomainMappingActiveRequest if err := c.ShouldBindJSON(&body); err != nil { response.Error(c, response.ErrBadRequest(40000, "invalid_payload", err.Error())) return } result, err := svc.SetActive(c.Request.Context(), actorFromGin(c), id, body.IsActive) if err != nil { response.Error(c, err) return } response.Success(c, result) } } func deleteSiteDomainMappingHandler(svc *app.SiteDomainMappingService) gin.HandlerFunc { return func(c *gin.Context) { id, err := parseIDParam(c) if err != nil { response.Error(c, err) return } if err := svc.Delete(c.Request.Context(), actorFromGin(c), id); err != nil { response.Error(c, err) return } response.Success(c, gin.H{"id": id}) } } func (r siteDomainMappingRequest) toInput() app.SiteDomainMappingInput { active := true if r.IsActive != nil { active = *r.IsActive } return app.SiteDomainMappingInput{ RegistrableDomain: r.RegistrableDomain, SiteKey: r.SiteKey, SiteName: r.SiteName, IsActive: active, } } func parseOptionalBoolQuery(value string) *bool { if value == "" { return nil } parsed, err := strconv.ParseBool(value) if err != nil { return nil } return &parsed }