package logic import ( "encoding/json" "errors" "fmt" "fusenapi/model/gmodel" "fusenapi/service/repositories" "fusenapi/utils/auth" "fusenapi/utils/basic" "fusenapi/utils/file" "fusenapi/utils/hash" "fusenapi/utils/s3url_to_s3id" "io" "net/http" "time" "context" "fusenapi/server/upload/internal/svc" "fusenapi/server/upload/internal/types" "github.com/zeromicro/go-zero/core/logc" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) type UploadLogoDebugLogic struct { logx.Logger ctx context.Context svcCtx *svc.ServiceContext r *http.Request } func NewUploadLogoDebugLogic(r *http.Request, svcCtx *svc.ServiceContext) *UploadLogoDebugLogic { return &UploadLogoDebugLogic{ Logger: logx.WithContext(r.Context()), ctx: r.Context(), svcCtx: svcCtx, r: r, } } // 处理进入前逻辑w,r // func (l *UploadLogoDebugLogic) BeforeLogic(w http.ResponseWriter, r *http.Request) { // } func (l *UploadLogoDebugLogic) UploadLogoDebug(req *types.UploadLogoDebugReq, userinfo *auth.UserInfo) (resp *basic.Response) { // 返回值必须调用Set重新返回, resp可以空指针调用 resp.SetStatus(basic.CodeOK, data) // userinfo 传入值时, 一定不为null if userinfo.IsOnlooker() { // 如果是,返回未授权的错误码 return resp.SetStatus(basic.CodeUnAuth) } var ( productTemplateTags []gmodel.FsProductTemplateTags err error ) var userId int64 var guestId int64 // 检查用户是否是游客 if userinfo.IsGuest() { // 如果是,使用游客ID和游客键名格式 guestId = userinfo.GuestId } else { // 否则,使用用户ID和用户键名格式 userId = userinfo.UserId } //设置内存大小 l.r.ParseMultipartForm(32 << 20) fileObject, fileHeader, err := l.r.FormFile("file") if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,no files") } defer fileObject.Close() // 获取文件的MIME类型 fileType := fileHeader.Header.Get("Content-Type") var imageTypes = make(map[string]struct{}, 7) imageTypes["image/jpg"] = struct{}{} imageTypes["image/jpeg"] = struct{}{} imageTypes["image/png"] = struct{}{} imageTypes["image/gif"] = struct{}{} imageTypes["image/bmp"] = struct{}{} imageTypes["image/tiff"] = struct{}{} imageTypes["image/webp"] = struct{}{} imageTypes["image/svg+xml"] = struct{}{} // 判断文件类型是否为图片 _, ok := imageTypes[fileType] if !ok { return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,file is not image") } // 限制上传文件大小 50k // maxSize := 100 * 1024 // if fileHeader.Size > int64(maxSize) { // return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,The file size exceeds the maximum limit of 100k") // } // 读取数据流 ioData, err := io.ReadAll(fileObject) if err != nil { logx.Error(err) return resp.SetStatus(basic.CodeFileUploadErr, "file upload err,no files") } // 上传文件 var upload = file.Upload{ Ctx: l.ctx, MysqlConn: l.svcCtx.MysqlConn, AwsSession: l.svcCtx.AwsSession, } var resourceId string = hash.JsonHashKey(req.FileKey) uploadRes, err := upload.UploadFileByByte(&file.UploadBaseReq{ FileHash: resourceId, FileByte: ioData, UploadBucket: 1, ApiType: 2, UserId: userId, GuestId: guestId, Source: "upload-logo", }) if err != nil { logx.Error(err) basic.CodeServiceErr.Message = fmt.Sprintf("算法请求--LOGO信息--错误:%+v", err) return resp.SetStatus(basic.CodeServiceErr) } userinfo.Debug = &auth.Debug{ IsAllTemplateTag: 1, } var resultStr string resLogoStandard, err := l.svcCtx.Repositories.ImageHandle.LogoInfoSet(l.ctx, &repositories.LogoInfoSetReq{ LogoUrl: uploadRes.ResourceUrl, Version: l.svcCtx.Config.BLMService.Version, Debug: userinfo.Debug, }) if err != nil { logx.Error(err) basic.CodeServiceErr.Message = fmt.Sprintf("算法请求--LOGO信息--错误:%+v", err) return resp.SetStatus(basic.CodeServiceErr, fmt.Sprintf("算法请求--LOGO信息--错误:%+v", err)) } resultStr = resLogoStandard.Res resultStrB := []byte(resultStr) var module = "logo" var nowTime = time.Now().UTC() // 新增素材记录 materialInfo := gmodel.FsUserMaterial{ Module: &module, UserId: &userId, GuestId: &guestId, ResourceId: &uploadRes.ResourceId, ResourceUrl: &uploadRes.ResourceUrl, Metadata: &resultStrB, Ctime: &nowTime, } err = l.svcCtx.MysqlConn.WithContext(l.ctx).Transaction(func(tx *gorm.DB) error { var userDebug gmodel.FsUserDebug res01 := tx.Model(&gmodel.FsUserDebug{}).Where("guest_id = ?", guestId).Take(&userDebug) if res01.Error != nil { if !errors.Is(res01.Error, gorm.ErrRecordNotFound) { logc.Errorf(l.ctx, "FsUserDebug Take err:%+v", res01.Error) return res01.Error } else { res02 := tx.Model(&gmodel.FsUserDebug{}).Create(&gmodel.FsUserDebug{ GuestId: &guestId, Ctime: &nowTime, }) if res02.Error != nil { logc.Errorf(l.ctx, "FsUserDebug Create err:%+v", res02.Error) return res02.Error } } } resCreate := tx.Create(&materialInfo) err = resCreate.Error if err != nil { logc.Errorf(l.ctx, "FsUserMaterial Create err:%+v", err) return err } return nil }) if err != nil { return resp.SetStatusWithMessage(basic.CodeApiErr, "") } //解析用户素材元数据 var metaData map[string]interface{} if err = json.Unmarshal([]byte(resultStr), &metaData); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse user metadata") } //解析模板标签颜色 var mapMaterialTemplateTagColors map[string][][]string b, _ := json.Marshal(metaData["template_tag"]) if err = json.Unmarshal(b, &mapMaterialTemplateTagColors); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "invalid format of metadata`s template_tag") } //解析单纯的模板标签用于排序 var simpleTemplateTags []string b, _ = json.Marshal(metaData["template_tag_id"]) if err = json.Unmarshal(b, &simpleTemplateTags); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "invalid format of metadata`s template_tag_id") } var templateTagNameList []string for templateTag := range mapMaterialTemplateTagColors { templateTagNameList = append(templateTagNameList, templateTag) } productTemplateTags, err = l.svcCtx.AllModels.FsProductTemplateTags.GetListByTagNames(l.ctx, templateTagNameList, len(templateTagNameList), 1, "id DESC") if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get template tags") } //获取默认渲染的产品(写死) productInfo, err := l.svcCtx.AllModels.FsProduct.FindOne(l.ctx, 30) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return resp.SetStatusWithMessage(basic.CodeDbRecordNotFoundErr, "the product info is not exists") } logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get product info") } //资源id集合 resourceIds := make([]string, 0, 5) for _, v := range productTemplateTags { resourceIds = append(resourceIds, s3url_to_s3id.GetS3ResourceIdFormUrl(*v.Cover)) } resourceIds = append(resourceIds, s3url_to_s3id.GetS3ResourceIdFormUrl(*productInfo.Cover)) //根据resourceUrls找到对应的元数据 resourceMetadataList, err := l.svcCtx.AllModels.FsResource.FindAllByResourceIds(l.ctx, resourceIds) if err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeDbSqlErr, "failed to get resource list") } mapResourceMetadata := make(map[string]map[string]interface{}) for _, v := range resourceMetadataList { var metadata map[string]interface{} if v.Metadata != nil { _ = json.Unmarshal(*v.Metadata, &metadata) } mapResourceMetadata[*v.ResourceUrl] = metadata } //排序 for index, templateTagStr := range simpleTemplateTags { for k, v := range productTemplateTags { if templateTagStr == *v.TemplateTag { productTemplateTags[k], productTemplateTags[index] = productTemplateTags[index], productTemplateTags[k] break } } } list := make([]types.GetProductTemplateTagsRsp, 0, len(productTemplateTags)) for _, templateTagInfo := range productTemplateTags { colors := make([][]string, 0, 10) SelectedColorIndex := 0 isDefaultTemplateTag := false //查看用户素材中标签对应的颜色 if colorsSet, ok := mapMaterialTemplateTagColors[*templateTagInfo.TemplateTag]; ok { //标签颜色 colors = colorsSet } var templateTagGroups []interface{} if templateTagInfo.Groups != nil && *templateTagInfo.Groups != "" { if err = json.Unmarshal([]byte(*templateTagInfo.Groups), &templateTagGroups); err != nil { logx.Error(err) return resp.SetStatusWithMessage(basic.CodeJsonErr, "failed to parse groups") } } list = append(list, types.GetProductTemplateTagsRsp{ Id: templateTagInfo.Id, TemplateTag: *templateTagInfo.TemplateTag, IsDefaultTemplateTag: isDefaultTemplateTag, TemplateTagGroups: templateTagGroups, Cover: *templateTagInfo.Cover, CoverMetadata: mapResourceMetadata[*templateTagInfo.Cover], Colors: colors, SelectedColorIndex: SelectedColorIndex, ProductId: productInfo.Id, ProductCover: *productInfo.Cover, ProductCoverMetadata: mapResourceMetadata[*productInfo.Cover], }) } return resp.SetStatusWithMessage(basic.CodeOK, "success", map[string]interface{}{ "upload_data": UploadUrl{ Status: 1, ResourceId: uploadRes.ResourceId, ResourceUrl: uploadRes.ResourceUrl, }, "tag_data": list, }) } // 处理逻辑后 w,r 如:重定向, resp 必须重新处理 // func (l *UploadLogoDebugLogic) AfterLogic(w http.ResponseWriter, r *http.Request, resp *basic.Response) { // // httpx.OkJsonCtx(r.Context(), w, resp) // }